Безопасно ли использовать статический экземпляр java.sql.Connection в многопоточной системе?
Я запускаю веб-приложение на Tomcat. У меня есть класс, который обрабатывает все запросы БД. Этот класс содержит Connection
объект и методы, которые возвращают результаты запроса.
Это объект подключения:
private static Connection conn = null;
У него только один экземпляр (синглтон).
Кроме того, у меня есть методы, которые выполняют запросы, такие как поиск пользователя в БД:
public static ResultSet searchUser(String user, String pass) throws SQLException
Этот метод использует статический Connection
объект. Мой вопрос, мое использование в статическом Connection
Поток объекта безопасен? Или это может вызвать проблемы, когда многие пользователи searchUser
метод?
2 ответа
мое использование в статическом потоке объекта Connection безопасно?
Точно нет!
Таким образом, соединение будет общим для всех запросов, отправленных всеми пользователями, и, таким образом, все запросы будут мешать друг другу. Но потокобезопасность - не единственная ваша проблема, утечка ресурсов - это и другая ваша проблема. Вы сохраняете одно соединение открытым в течение всего срока службы приложения. Средняя база данных будет восстанавливать соединение всякий раз, когда оно было открыто слишком долго, что обычно составляет от 30 минут до 8 часов, в зависимости от конфигурации базы данных. Поэтому, если ваше веб-приложение будет работать дольше, соединение будет потеряно, и вы больше не сможете выполнять запросы.
Эта проблема также применяется, когда эти ресурсы хранятся какstatic
переменная экземпляра экземпляра класса, который используется многократно.
Вы должны всегда получать и закрывать соединение, оператор и набор результатов в кратчайшей возможной области, предпочтительно внутри того же самого 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
Вот. Если вы еще не на Java 7, то используйте try-finally
блок, в котором вы вручную закрываете закрываемые ресурсы в обратном порядке по мере их приобретения.
Если вы беспокоитесь о производительности подключения, то вам следует использовать вместо этого пул подключений. Это встроено во многие серверы приложений Java EE и даже в базовые контейнеры сервлетов, такие как Tomcat. Просто создайте источник данных JNDI на самом сервере и позвольте вашему веб-приложению захватить его как DataSource
, Это прозрачно уже пул соединений.
Смотрите также:
Если вы только работаете Select
запросы (searchUser
звучит как только выбор данных) не будет никаких проблем, кроме конфликта потоков.
Насколько я знаю, Connection
может обрабатывать только один запрос за раз, поэтому, используя один экземпляр, вы по существу сериализуете доступ к базе данных. Но это не обязательно означает, что доступ к такой базе данных всегда безопасен в многопоточной среде. Могут все еще быть проблемы, если одновременный доступ чередуется.