在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环境下访问这样的数据库总是安全的 。 如果并发访问是交错的,则可能仍然存在问题。