ResultSet используется повторно

Итак, у меня есть фрагмент кода, который вызывается несколько раз. Однако во время некоторого тестирования я заметил, что мой ResultSet возвращается неправильно в соответствии с базой данных. После дальнейших исследований я заметил, что он каким-то образом используется повторно. СТОИТ упомянуть, что когда я перезапускаю программу, она получает правильный результат. SQL всегда один и тот же.

Мой код:

PreparedStatement ps = connection.prepareStatement(sql);
ps.setInt(1, packet.getUserId());
ResultSet dbResult = ps.executeQuery();

while(dbResult.next())
{
    System.out.println("There were items!" );
    Item item = new Item();
    item.setItemType(dbResult.getInt(1));
    item.setFromUser(dbResult.getString(2));
    item.setItemMessage(dbResult.getString(3));
    toReturn.add(item);
}

Это была моя последовательность тестирования:

  • Получить строки из ResultSet один раз и получить правильные результаты - ОК
  • Удалите все строки из таблицы, которые использует конкретный sql выше, что означает, что ResultSet не должен ничего возвращать в следующий раз.
  • Попробуйте выполнить выборку еще раз (теперь она должна вернуть 0 строк), НО она возвращает те же самые строки, что и на шаге 1, даже если таблица базы данных пуста.

Должен ли быть закрыт ResultSet или что-то еще после использования, или что мне не хватает? Я получаю результаты из ResultSet, хотя в базе данных ничего нет. Я могу гарантировать, что SQL является законным, но ResultSet, похоже, не создается из него во второй раз, когда он вызывается.

РЕДАКТИРОВАТЬ (код инициализации соединения)

public class DBFactory 
{
    protected String databaseName = null;
    protected String username = null;
    protected String password = null;
    protected Connection connection = null;
    protected Statement statement = null;

    protected DBFactory( String databaseName, String username, String password)
    {
        this.databaseName = databaseName;
        this.username = username;
        this.password = password;
    }

    protected void initConnection()
    {
        if (databaseName == null || username == null || password == null)
            throw new IllegalStateException();

        try 
        {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            this.connection = DriverManager.getConnection(this.databaseName, this.username, this.password);
            this.statement = this.connection.createStatement();
        } 
        catch (Exception e) 
        {
            System.out.println("DBFactory " + e.getMessage());
        }
    }

person Lucas Arrefelt    schedule 15.12.2012    source источник
comment
Вы пропустили важные фрагменты своего кода, показывающие, КАК вы удаляете строки и повторно выдаете запрос, а также параметры вашего соединения (REPEATABLE_READ и т. д.). Без этих деталей мы просто предполагаем.   -  person Jim Garrison    schedule 15.12.2012
comment
Я не удаляю их из кода, я делаю это вручную вне программы.   -  person Lucas Arrefelt    schedule 15.12.2012
comment
Опубликуйте код, который создает соединение.   -  person reprogrammer    schedule 15.12.2012
comment
Но завершается ли ваш код, а затем перезапускается после внесения внешних изменений, или он каким-то образом продолжает работать и повторяет запрос?   -  person Jim Garrison    schedule 15.12.2012
comment
Этот код расположен на стороне сервера, то есть каждый раз, когда клиент запрашивает эту информацию, этот код запускается (функция вверху).   -  person Lucas Arrefelt    schedule 15.12.2012
comment
СТОИТ упомянуть, что когда я перезапускаю программу, она снова получает правильный результат.   -  person Lucas Arrefelt    schedule 15.12.2012
comment
System.out.println("There were items!" ); выполняется ли эта строка, когда вы очищаете свои таблицы и запускаете без перезапуска?   -  person Bhesh Gurung    schedule 15.12.2012
comment
Да, это так. Я провел еще несколько исследований по этому вопросу, и кажется, что PreparedStatements использует кэширование. Поскольку я запускаю один и тот же sql несколько раз, он использует кешированный. Однако предполагается, что они становятся недействительными при изменении таблицы, но здесь, похоже, это не так.   -  person Lucas Arrefelt    schedule 15.12.2012
comment
Я не создаю новое соединение каждый раз, я использую то же самое. Может быть, это следует изменить?   -  person Lucas Arrefelt    schedule 15.12.2012
comment
Вы как-то внутри транзакции? Что находится между DBFactory и кодом запроса?   -  person Sarah Happy    schedule 15.12.2012


Ответы (2)


Я ожидаю, что у вас отключена автоматическая фиксация для соединения.

Насколько я понимаю вашу проблему, этот небольшой пример кода продемонстрирует ее.

package org.yi.happy.mysql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class RepeatQuery {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.jdbc.Driver").newInstance();

        setupDatabase();

        System.out.println("opening database...");
        Connection connection = openConnection();
        connection.setAutoCommit(false);

        queryDatabase(connection);

        deleteRecords();

        queryDatabase(connection);

        connection.close();
    }

    private static Connection openConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://localhost/test", null,
                null);
    }

    private static void setupDatabase() throws SQLException {
        Connection conn = openConnection();

        System.out.println("doing insert on another connection...");
        PreparedStatement stmt = conn
                .prepareStatement("insert into strings(id, value) values(?, ?)");

        stmt.setInt(1, 1);
        stmt.setString(2, "test");
        stmt.execute();

        stmt.setInt(1, 2);
        stmt.setString(2, "data");
        stmt.execute();

        stmt.close();
        conn.close();
    }

    private static void deleteRecords() throws SQLException {
        Connection conn = openConnection();
        System.out.println("doing delete on another connection...");
        PreparedStatement stmt = conn.prepareStatement("delete from strings");
        stmt.execute();

        stmt.close();
        conn.close();
    }

    private static void queryDatabase(Connection connection)
            throws SQLException {
        System.out.println("doing query...");
        PreparedStatement ps = connection
                .prepareStatement("select id, value from strings");
        ResultSet dbResult = ps.executeQuery();

        while (dbResult.next()) {
            int id = dbResult.getInt(1);
            String value = dbResult.getString(2);
            System.out.println(id + " <=> " + value);
        }
    }
}

Результат вышеизложенного

doing insert on another connection...
opening database...
doing query...
2 <=> data
1 <=> test
doing delete on another connection...
doing query...
2 <=> data
1 <=> test

Если я изменюсь

            connection.setAutoCommit(false);

читать

            connection.setAutoCommit(true);

вывод становится

doing insert on another connection...
opening database...
doing query...
2 <=> data
1 <=> test
doing delete on another connection...
doing query...

чего вы, кажется, ожидаете.

person Community    schedule 15.12.2012

Скорее всего, вы находитесь в транзакции, если вы зафиксируете или отмените текущую транзакцию, вы увидите текущее состояние базы данных.

Попробуйте

        connection.rollback();

or

        connection.commit();

перед вашим запросом или включите автоматическую фиксацию.

person Community    schedule 15.12.2012