Is it safe to use a static java.sql.Connection instance in a multithreaded system?
Безопасно ли использовать статический экземпляр java.sql.Connection в многопоточной системе?
Я запускаю веб-приложение на Tomcat. У меня есть класс, который обрабатывает все запросы к БД. Этот класс содержит Connection объект и методы, которые возвращают результаты запроса.
Это объект connection:
privatestaticConnectionconn=null;
У него только один экземпляр (singleton).
Кроме того, у меня есть методы, которые выполняют запросы, такие как поиск пользователя в БД:
Этот метод использует статический Connection объект. Мой вопрос в том, безопасно ли мое использование в потоках статических Connection объектов? Или это может вызвать проблемы, когда многие пользователи будут вызывать метод searchUser?
Переведено автоматически
Ответ 1
является ли мое использование в статическом объекте Connection потокобезопасным?
Категорически нет!
Таким образом, соединение будет общим для всех запросов, отправляемых всеми пользователями, и, следовательно, все запросы будут мешать друг другу. Но безопасность потоков - не единственная ваша проблема, утечка ресурсов - также другая ваша проблема. Вы поддерживаете одно соединение открытым в течение всего срока службы приложения. Средняя база данных восстанавливает соединение всякий раз, когда оно было открыто слишком долго, что обычно составляет от 30 минут до 8 часов, в зависимости от конфигурации базы данных. Итак, если ваше веб-приложение работает дольше указанного срока, соединение будет потеряно, и вы больше не сможете выполнять запросы.
Эта проблема также возникает, когда эти ресурсы хранятся как не-static переменная экземпляра экземпляра класса, которая используется повторно несколько раз.
Вы должны всегда получать и закрывать connection, оператор и результирующий набор в минимально возможной области, предпочтительно внутри того же try-with-resources блока, где вы выполняете запрос, в соответствии со следующей идиомой JDBC:
public User find(String username, String password)throws SQLException { Useruser=null;
try ( Connectionconnection= dataSource.getConnection(); PreparedStatementstatement= connection.prepareStatement("SELECT id, username, email FROM user WHERE username=? AND password=md5(?)"); ) { statement.setString(1, username); statement.setString(2, password);
try (ResultSetresultSet= statement.executeQuery()) { if (resultSet.next()) { user = newUser(); user.setId(resultSet.getLong("id")); user.setUsername(resultSet.getString("username")); user.setEmail(resultSet.getString("email")); } } }
return user; }
Обратите внимание, что вы должны не возвращать ResultSet здесь. Вы должны немедленно прочитать его и сопоставить с классом, отличным от JDBC, а затем вернуть его, чтобы ResultSet можно было безопасно закрыть.
Если вы беспокоитесь о производительности подключения, то вместо этого вам следует использовать пул подключений. Это встроено во многие серверы приложений Java EE, и даже простые сервлетконтейнеры, такие как Tomcat, поддерживают это. Просто создайте источник данных JNDI на самом сервере и позвольте вашему веб-приложению использовать его как DataSource. Очевидно, что это уже пул подключений. Вы можете найти пример по первой ссылке из списка ниже.
Если вы выполняете только Select запросы (searchUser звучит как только выбор данных), проблем не возникнет, кроме конфликта потоков.
Насколько я знаю, a Connection может обрабатывать только один запрос одновременно, поэтому, используя один экземпляр, вы, по сути, сериализуете доступ к базе данных. Но это не обязательно означает, что всегда безопасно обращаться к такой базе данных в многопоточной среде. Все еще могут возникнуть проблемы, если параллельные обращения чередуются.