在multithreading系统中使用静态java.sql.Connection实例是否安全?

我正在Tomcat上运行一个Web应用程序。 我有一个类处理所有的数据库查询。 这个类包含Connection对象和返回查询结果的方法。

这是连接对象:

 private static Connection conn = null; 

它只有一个实例(单例)。

另外,我有执行查询的方法,比如在db中search用户:

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

此方法使用静态Connection对象。 我的问题是,我使用静态Connection对象线程安全吗? 或者当很多用户会调用searchUser方法时会引起问题?

我在静态连接对象中使用线程安全吗?

绝对不!

这样,所有用户发送的所有请求将共享连接,因此所有查询都将互相干扰。 但是线程安全不是你唯一的问题,资源泄漏也是你的另一个问题。 在整个应用程序的生命周期中,您都保持打开一个连接。 一般情况下,数据库一旦打开时间过长(通常在30分钟到8小时之间),将取回连接,具体取决于数据库的configuration。 因此,如果您的Web应用程序运行时间超过此时间,则连接将丢失,您将无法再执行查询。

当这些资源被保存为多次重用的类实例的非static实例variables时,这个问题也适用。

您应该始终尽可能最短的范围内获取并closures连接,语句和结果集,最好在try-with-resources执行查询的位置相同的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块,其中您按照获取的顺序手动closures可closures的资源。

如果担心连接性能,则应该使用连接池。 这是内置于许多Java EE应用程序服务器,甚至像Tomcat支持它的准系统servlet容器。 只要在服务器本身中创build一个JNDI数据源,并让你的Web应用程序抓取它作为DataSource 。 它透明地已经是一个连接池。

也可以看看:

  • 我应该如何在基于servlet的应用程序中连接到JDBC数据库/数据源?
  • 当我的应用程序失去连接时,我应该如何恢复?
  • 我使用JDBC连接池吗?
  • 在JSP页面中使用MVC和DAO模式在HTML中显示JDBC ResultSet
  • 使用JDBC的DAO教程

如果只运行Select查询( searchUser听起来像只select数据),除了线程争用之外,不会有任何问题。

据我所知,一个Connection一次只能处理一个查询,所以通过使用一个实例,你基本上可以序列化数据库访问。 但是这并不一定意味着在multithreading环境下访问这样的数据库总是安全的 。 如果并发访问是交错的,则可能仍然存在问题。