Вопрос-ответ

Is it safe to use a static java.sql.Connection instance in a multithreaded system?

Безопасно ли использовать статический экземпляр java.sql.Connection в многопоточной системе?

Я запускаю веб-приложение на Tomcat. У меня есть класс, который обрабатывает все запросы к БД. Этот класс содержит Connection объект и методы, которые возвращают результаты запроса.

Это объект connection:

private static Connection conn = null;

У него только один экземпляр (singleton).

Кроме того, у меня есть методы, которые выполняют запросы, такие как поиск пользователя в БД:

public static ResultSet searchUser(String user, String pass) throws SQLException

Этот метод использует статический Connection объект. Мой вопрос в том, безопасно ли мое использование в потоках статических Connection объектов? Или это может вызвать проблемы, когда многие пользователи будут вызывать метод searchUser?

Переведено автоматически
Ответ 1

является ли мое использование в статическом объекте Connection потокобезопасным?


Категорически нет!

Таким образом, соединение будет общим для всех запросов, отправляемых всеми пользователями, и, следовательно, все запросы будут мешать друг другу. Но безопасность потоков - не единственная ваша проблема, утечка ресурсов - также другая ваша проблема. Вы поддерживаете одно соединение открытым в течение всего срока службы приложения. Средняя база данных восстанавливает соединение всякий раз, когда оно было открыто слишком долго, что обычно составляет от 30 минут до 8 часов, в зависимости от конфигурации базы данных. Итак, если ваше веб-приложение работает дольше указанного срока, соединение будет потеряно, и вы больше не сможете выполнять запросы.

Эта проблема также возникает, когда эти ресурсы хранятся как не-static переменная экземпляра экземпляра класса, которая используется повторно несколько раз.

Вы должны всегда получать и закрывать connection, оператор и результирующий набор в минимально возможной области, предпочтительно внутри того же try-with-resources блока, где вы выполняете запрос, в соответствии со следующей идиомой JDBC:

public User find(String username, String password) throws SQLException {
User user = null;

try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, username, email FROM user WHERE username=? AND password=md5(?)");
) {
statement.setString(1, username);
statement.setString(2, password);

try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
user = new User();
user.setId(resultSet.getLong("id"));
user.setUsername(resultSet.getString("username"));
user.setEmail(resultSet.getString("email"));
}
}
}

return user;
}

Обратите внимание, что вы должны не возвращать ResultSet здесь. Вы должны немедленно прочитать его и сопоставить с классом, отличным от JDBC, а затем вернуть его, чтобы ResultSet можно было безопасно закрыть.

Если вы еще не на Java 7, то используйте try-finally блок, в котором вы вручную закрываете доступные ресурсы в порядке, обратном тому, в каком вы их приобрели. Вы можете найти пример здесь: Как часто следует закрывать Connection, Statement и ResultSet в JDBC?

Если вы беспокоитесь о производительности подключения, то вместо этого вам следует использовать пул подключений. Это встроено во многие серверы приложений Java EE, и даже простые сервлетконтейнеры, такие как Tomcat, поддерживают это. Просто создайте источник данных JNDI на самом сервере и позвольте вашему веб-приложению использовать его как DataSource. Очевидно, что это уже пул подключений. Вы можете найти пример по первой ссылке из списка ниже.

Смотрите также:

Ответ 2

Если вы выполняете только Select запросы (searchUser звучит как только выбор данных), проблем не возникнет, кроме конфликта потоков.

Насколько я знаю, a Connection может обрабатывать только один запрос одновременно, поэтому, используя один экземпляр, вы, по сути, сериализуете доступ к базе данных. Но это не обязательно означает, что всегда безопасно обращаться к такой базе данных в многопоточной среде. Все еще могут возникнуть проблемы, если параллельные обращения чередуются.

java multithreading servlets jdbc