Являются ли addBatch () и executeBatch () поточно-ориентированными? - PullRequest
5 голосов
/ 02 октября 2009

Могу ли я вызвать executeBacth из потока, в то время как другой продолжает вызывать addBatch () для того же объекта Statement (или PreparedStatement)?

Обновление: у кого-нибудь есть опыт с этой проблемой? потому что я получаю неправильные результаты. Не все обновления, которые я добавил в пакет, выполнены.

Ответы [ 5 ]

18 голосов
/ 18 ноября 2009

Я бы сделал шаг назад и глубоко пересмотрел бы дизайн. С какой стати вы хотели бы разделить одно и то же Statement (и, следовательно, неявно также * Connection) между двумя потоками?

Обычная практика JDBC заключается в том, что вы должны приобрести и закрыть Connection, Statement и ResultSet в кратчайшем возможном объеме. То есть внутри того же самого метода блока. Вот основной пример:

public void update(List<Item> items) throws SQLException {
    Connection connection = null;
    PreparedStatement statement = null;
    try {
        connection = database.getConnection();
        statement = connection.prepareStatement(sql);
        for (Item item : items) {
            statement.setObject(1, item.getSomething());
            statement.addBatch();
        }
        statement.executeBatch();
    } finally {
        if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
        if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
    }
}

Если все, что вам нужно, это просто повысить производительность соединения, используйте пул соединений. Например C3P0 . Но, конечно, не разделяет дорогие ресурсы БД между потоками! Таким образом, вам также не нужно беспокоиться о безопасности потоков. Это деталь реализации.

О, если это еще не ясно: вы не улучшите производительность базы данных, поделившись одним и тем же оператором и соединением между несколькими потоками. Хуже того, он только замедлится, и вы столкнетесь с проблемами безопасности потоков как на стороне Java, так и на стороне базы данных.

6 голосов
/ 02 октября 2009

Да. Согласно спецификации JDBC все реализации драйвера JDBC должны быть потокобезопасными:

Соответствие API JDBC 3.0, раздел A.1.6


Если я правильно понимаю ваш комментарий к ответу BalusC, вы выполняете итерацию ResultSet из одного оператора и одновременно работаете с другими PreparedStatements в отдельном потоке, чтобы обновить другие строки. Это не обязательно должно работать (опять же, это зависит от драйвера JDBC, но не имеет прямого отношения к безопасности потока). Я не уверен насчет самых последних версий, но более старые драйверы Oracle JDBC сделали, например, не поддерживает множественные утверждения, конечно, не ошибся должным образом, но дал неожиданные результаты, как вы описываете. Если я правильно помню, создание второго оператора в соединении во время итерации набора результатов из первого оператора приведет к тому, что первый оператор будет закрыт молча, а первый набор результатов будет возвращать только те строки, которые уже были извлечены из базы данных, хотя больше строк мог быть доступен. Ваша реализация звучит аналогично и может демонстрировать аналогичное поведение, также как и в других базах данных.

3 голосов
/ 19 ноября 2009

Как указал jambjo, спецификация требует безопасности потоков. Однако, как указывал Ракеш Джуял, на практике обеспечить такую ​​безопасность невозможно. Поэтому, если вы хотите быть по-настоящему портативным и надежным, по возможности избегайте многопоточного доступа к переменным, если вы не уверены, что используемые вами драйверы соответствуют спецификации.

Что касается addBatch и executeBatch, то в некоторых случаях эти методы сами ненадежны. Я знаю, что всякий раз, когда я пытался использовать их с драйверами Oracle (однопоточными), я получал непредсказуемые результаты. Так что, возможно, безопасность потоков - это не ваша проблема, а скорее проблемы.

3 голосов
/ 18 ноября 2009

PreparedStatement не заставляйте реализующий класс, чтобы сделать этот метод потокобезопасным . Так что совершенно очевидно, что это зависит от реализации класса.

Например: - DelegatingPreparedStatement использует эти методы, но они не являются потокобезопасными, в то время как ' OraclePreparedStatement ' также имеет эти методы, и они являются потоковыми безопасный.

1 голос
/ 22 ноября 2009

Это может быть очень специфично для JDBC. Я бы предпочел никогда не полагаться на параллельный доступ к пакетной обработке и делегировать сложность параллелизма серверу баз данных. почему бы не иметь больше независимых соединений?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...