在多线程系统中使用静态java.sql.Connection实例安全吗?

在多线程系统中使用静态java.sql.Connection实例安全吗?,java,multithreading,servlets,jdbc,connection,Java,Multithreading,Servlets,Jdbc,Connection,我正在Tomcat上运行一个web应用程序。我有一个处理所有DB查询的类。 此类包含连接对象和返回查询结果的方法 这是连接对象: private static Connection conn = null; 它只有一个实例(singleton) 此外,我还有执行查询的方法,例如在数据库中搜索用户: public static ResultSet searchUser(String user, String pass) throws SQLException 此方法使用静态连接对象。我的问题是

我正在Tomcat上运行一个web应用程序。我有一个处理所有DB查询的类。 此类包含
连接
对象和返回查询结果的方法

这是连接对象:

private static Connection conn = null;
它只有一个实例(singleton)

此外,我还有执行查询的方法,例如在数据库中搜索用户:

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

此方法使用静态
连接
对象。我的问题是,在静态
连接中使用对象线程安全吗?或者,当许多用户调用
searchUser
方法时,它会导致问题吗?

如果您只运行
Select
查询(
searchUser
听起来像是只选择数据),除了线程争用之外,不会出现任何问题

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

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

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

当这些资源作为类实例的非
静态
实例变量保存并多次重用时,此问题也适用

您应该始终在尽可能短的范围内获取并关闭连接、语句和结果集,最好是在与您根据以下JDBC习惯用法执行查询的位置相同的范围内:

public User find(字符串用户名、字符串密码)引发SQLException{
User=null;
试一试(
Connection=dataSource.getConnection();
PreparedStatement=connection.prepareStatement(“选择id、用户名、来自用户名为?且密码为md5(?)的用户的电子邮件”);
) {
statement.setString(1,用户名);
语句.setString(2,密码);
try(ResultSet ResultSet=statement.executeQuery()){
if(resultSet.next()){
user=新用户();
user.setId(resultSet.getLong(“id”);
user.setUsername(resultSet.getString(“用户名”);
user.setEmail(resultSet.getString(“电子邮件”);
}
}
}       
返回用户;
}
请注意,您应该不要在此处返回
ResultSet
。您应该立即阅读它并将其映射到非JDBC类,然后返回它,这样就可以安全地关闭
ResultSet

如果您还没有使用Java 7,那么请使用
try finally
块,在该块中,您可以按照与获取资源相反的顺序手动关闭可关闭的资源。您可以在此处找到一个示例:

如果您担心连接性能,那么应该改用连接池。这是许多JavaEE应用服务器中内置的,甚至像Tomcat这样的基本servletcontainers也支持它。只需在服务器本身中创建一个JNDI数据源,并让您的webapp将其作为
数据源
获取即可。它显然已经是一个连接池。您可以在下面列表的第一个链接中找到一个示例

另见:

虽然这与当前的问题无关,但出于好奇,hibernate也做了同样的事情。我的意思是,每次我们创建会话对象时,它是否会创建新的连接对象并在使用后关闭。@Vikas:Hibernate没有那么愚蠢:)是的,它正确地完成了。作为开发人员,您仍然需要确保正确使用Hibernate会话(即,不要将其指定为
静态
变量或其他内容)。@BaluC:如果我们在web链接中使用类似的代码,该怎么办?它使用的是C3P0-@JustCause:探索答案底部的“另见”链接。请注意,您的链接没有使用静态的
连接
,这里的问题都是关于这个问题的。@BalusC:我知道,我只是想知道这个代码对web是否更安全。有什么想法吗?