Java线程安全数据库连接

时间:2012-02-25 02:03:33

标签: java mysql database thread-safety thread-local

我正在编写一个servlet,通过访问和修改数据库中的某些表来处理每个请求。我希望与数据库的连接是线程安全的。我不想使用现有的库/框架(spring,hibernate等)。

我知道我可以通过以下方式使用java的ThreadLocal:

public class DatabaseRegistry { //assume it's a singleton


private Properties prop = new Properties();
    public static final ThreadLocal<Connection> threadConnection = new ThreadLocal<Connection>();

    private Connection connect() throws SQLException {
        try {
            // This will load the MySQL driver, each DB has its own driver
            Class.forName("com.mysql.jdbc.Driver");
            // Setup the connection with the DB
            Connection connection = DriverManager
                    .getConnection("jdbc:mysql://" + prop.getProperty("hostname") + "/" + prop.getProperty("database") + "?"
                            + "user=" + prop.getProperty("username") + "&password=" + prop.getProperty("password"));
            return connection;
        } catch (SQLException e) {          
            throw e;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } 

        return null;

    }

    public Connection getConnection() throws SQLException {

        if(threadConnection.get() == null) {
            Connection connection = connect();
            threadConnection.set(connection);
            return threadConnection.get();
        } else
            return threadConnection.get();
    } 

    private void freeConnection(Connection connection) throws SQLException {
        connection.close();
        threadConnection.remove();
    }
}

每次调用getConnection()时,新连接都会添加到ThreadLocal对象中,然后在释放连接时将其删除。

这是正确的方法吗?或者DatabaseRegistry本身是否应该扩展ThreadLocal类?或者是否有更好的方法来使所有连接线程安全?

由于

3 个答案:

答案 0 :(得分:2)

我认为将数据库连接设置为线程安全并不常见。通常你想要的是:

  • 序列化对servlet某些部分的访问,这样一次只能有一个servlet执行代码(例如,实现SingleThreadModel接口)。
  • 锁定特定的表/表页/行,以便您可以对某个特定元组进行操作(通过更改数据库隔离级别)。
  • 使用乐观锁定检测表中的已修改行(使用表的某些引用属性来检查当前版本是否与表中的版本相同)。

AFAIK,ThreadLocal的典型用途是为每个线程存储唯一的数据库连接,以便可以在业务逻辑中的不同方法中使用相同的连接,而无需每次都将其作为参数传递。因为公共servlet容器实现使用一个线程来填充HTTP请求,所以保证两个不同的请求使用两个不同的数据库连接。

答案 1 :(得分:2)

我知道你说你不想使用图书馆来做这件事,但是如果你这样做的话会更好。选择一个标准的连接池(C3P0,DBCP或其他东西),你会比自己烘焙更快乐。为什么不能使用库来执行此操作?

答案 2 :(得分:0)

我不确定您为什么希望数据库连接是线程安全的。大多数时候建立与数据库的连接是事务中最长的部分。通常,连接在请求之间重用,并且管理开放连接池(通过框架或更典型的应用程序服务器)。

如果您担心对同一个表的并发修改,您可能需要查看同步方法:http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html