当前位置: 首页 > 面试题库 >

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

司空宗清
2023-03-14
问题内容

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

这是连接对象:

private static Connection conn = null;

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

另外,我还有执行查询的方法,例如在db中搜索用户:

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

此方法使用静态Connection对象。我的问题是,我在静态Connection对象线程中使用安全吗?还是在许多用户调用该searchUser方法时会引起问题?


问题答案:

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

当这些资源作为static多次重用的类实例的非实例变量保存时,也会出现此问题。

你应该始终在尽可能短的范围内获取并关闭连接,语句和结果集,最好按照与以下JDBC习惯用法相同的代码try-with-resources块在内部执行查询:

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这里。你应该立即读取它并将其映射到非JDBC类,然后将其返回,以便ResultSet可以安全地关闭。

如果你尚未使用Java 7,请使用一个try-finally块,在该块中,以相反的顺序手动关闭可关闭资源。你可以在此处找到一个示例:在JDBC中应多久关闭一次Connection,StatementResultSet

如果你担心连接性能,则应该改用连接池。它内置在许多Java EE应用程序服务器中,甚至像Tomcat这样的准系统servlet容器也支持它。只需在服务器本身中创建JNDI数据源,然后让你的webapp将其抓取为即可DataSource。透明地,它已经是一个连接池。你可以在下面列表的第一个链接中找到示例。



 类似资料:
  • 问题内容: 假设我有一些Java代码: 如果一个线程正在初始化SomeClass的对象,并且在第二个线程想要再次加载SomeClass的过程中正在初始化静态块中的值,那么该静态块会怎样?即使第一个线程未完成,第二个线程是否仍假设它已初始化而忽略了它?还是发生其他事情? 问题答案: 如果第一个线程尚未完成对SomeClass的初始化,则第二个线程将阻塞。 Java语言规范的12.4.2节中对此进行了

  • 问题内容: 鉴于以下多态: 我们如何在没有昂贵的getInstance()方法同步和双重检查锁定争议的情况下使它保持线程安全和懒惰?这里提到了单例的有效方法,但似乎并没有扩展到多例。 问题答案: 使用Java 8,它甚至可以更简单:

  • 我的问题与静态变量的线程安全有关。 如果两个线程,t1具有静态锁,t2具有对象锁,可以同时继续,那么A类的状态测试将如何是线程安全的呢? 可能是,我错过了一些非常基本的东西,但不确定它是如何工作的。 根据下面的答案,我得到的印象是,如果必须使这些状态成为线程安全的,那么两个锁都应该由正在更新此状态的线程持有,或者确保它被仅静态方法或仅非静态方法访问。对吧?

  • 本文向大家介绍静态内部类单例 线程安全-Java版相关面试题,主要包含被问及静态内部类单例 线程安全-Java版时的应答技巧和注意事项,需要的朋友参考一下 我比较倾向于使用静态内部类的方法,这种方法也是《Effective Java》上所推荐的。 这种写法仍然使用JVM本身机制保证了线程安全问题;由于 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,

  • 问题内容: 我已经阅读了很多,但是还没有找到确切的答案。 我有一堂课,看起来像这样: 而且我想知道从Foo实例访问sharedData是否是线程安全的(如构造函数和doSomethingUseful()中所示)。Foo的许多实例将在多线程环境中创建。 我的意图是在静态初始化程序中初始化sharedData,此后不进行修改(只读)。 我读到的是,不可变对象本质上是线程安全的。但是我仅在实例变量的上下

  • 我有一个简单的静态日志记录类。但是,它肯定不是线程安全的,因为每个调用都试图写入同一个文件。我得到了这些例外情况: 什么是最好的方法使它的线程安全? 作为一个日志记录函数,我希望能够从代码的许多不同部分访问它(因此,我选择它为静态的原因)。然而,我想要使它成为线程安全的,我总是必须向它传递一个公共对象来lock(),我认为这违背了静态函数的目的。还是事实并非如此?