Если DbUtils создает соединение в том же потоке, например:
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
, тогда это потокобезопасно.
Но если соединение является переменной класса, например:
private static Connection connection = DriverManager.getConnection(url, username, password);
public static Connection getConnection() throws SQLException {
return connection;
}
Тогда оно определенно не является потокобезопасным, поскольку одно и то же соединение будет общим для всех потоков.Также, когда оно закрыто в потоке, все последующие потоки не смогут использовать соединение, потому что оно больше не открыто.Кроме того, когда он никогда не закрывается, БД прервет соединение раньше или позже, обычно через несколько часов, и ваше приложение больше не будет работать, потому что соединение больше не открыто.
Что касаетсясервлет,
public abstract class DatabaseInvokerServlet extends HttpServlet {
private AbstractUser currentUser;
private HttpServletRequest request;
private HttpServletResponse response;
// ...
}
это определенно не потокобезопасен.Вы назначаете текущего пользователя, запрос и ответ как переменные экземпляра.Из каждого класса сервлета существует только один экземпляр за время существования приложения.Этот экземпляр является общим для всех посетителей / сеансов в течение всего срока службы приложения.Каждый HTTP-запрос работает в отдельном потоке и использует один и тот же экземпляр.
Представьте себе двух одновременных посетителей: посетитель А задает текущего пользователя, запрос и ответ.Процесс БД, однако, занимает много времени.Перед возвратом ответа посетителя A посетитель B вызывает тот же сервлет, и поэтому текущий пользователь, запрос и ответ будут переопределены.Затем запрос посетителя A завершается и он хочет написать ответ, вместо этого он пишет в ответ посетителя B!Посетитель B видит результат запроса посетителя A, а посетитель A ничего не видит на своем экране!
Никогда не следует назначать данные, относящиеся к запросу / сеансу, в качестве переменной экземпляра сервлета.Вы должны сохранять их метод (поток) локальным.
public abstract class DatabaseInvokerServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AbstractUser currentUser = request.getSession().getAttribute("user");
// Keep the variables in the method block!
// Do not assign them as instance variable!
}
}
Что касается полной картины, этот подход является неуклюжим.Уровень доступа к базе данных не должен иметь ничего общего с сервлетами.Он должен работать в своих собственных автономных классах, которые вы можете просто создать / вызвать в любом другом Java-классе, любом классе сервлета или обычном приложении с main()
или чем-то еще.У вас не должно быть ни одной строки java.sql.*
импорта в ваших классах сервлетов (ожидайте, возможно, SQLException
, если он не абстрагирован).У вас не должно быть ни одной строки javax.servlet.*
импорта в ваших классах базы данных.
См. Также: