Java:与 HikariDataSource 对象的并发

标签 java concurrency thread-safety connection-pooling hikaricp

我有一个类,看起来像这样:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

public class ConnectionPool {
    private HikariDataSource hds;
    private final String propertyFileName;

    public ConnectionPool(String propertyFileName) {
        if (propertyFileName == null) {
            throw new IllegalArgumentException("propertyFileName can't be null");
        }

        this.propertyFileName = propertyFileName;
        reloadFile();
    }

    public void reloadFile() {
        if (hds != null) {
            hds.close();
        }

        hds = new HikariDataSource(new HikariConfig(propertyFileName));
    }

    public HikariDataSource getHikariDataSource() {
        return hds;
    }

    public String getPropertyFileName() {
        return propertyFileName;
    }

    public void executeQuery(final String sql, final CallBack<ResultSet, SQLException> callBack) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Connection connection = null;
                PreparedStatement preparedStatement = null;
                ResultSet resultSet = null;

                try {
                    connection = hds.getConnection();
                    preparedStatement = connection.prepareStatement(sql);
                    resultSet = preparedStatement.executeQuery();
                    callBack.call(resultSet, null);
                } catch (SQLException e) {
                    callBack.call(null, e);
                } finally {
                    if (resultSet != null) {
                        try {
                            resultSet.close();
                        } catch (SQLException ignored) {}
                    }

                    if (preparedStatement != null) {
                        try {
                            preparedStatement.close();
                        } catch (SQLException ignored) {}
                    }

                    if (connection != null) {
                        try {
                            connection.close();
                        } catch (SQLException ignored) {}
                    }
                }
            }
        }).start();
    }

    public void executeUpdate(final String sql, final CallBack<Integer, SQLException> callBack) {
        //TODO
    }

    public void execute(final String sql, final CallBack<Boolean, SQLException> callBack) {
        //TODO
    }

    public void connection(final String sql, final CallBack<Connection, SQLException> callBack) {
        //TODO
    }
}

问题在于,当使用 hds 时,可以从不同的线程调用 reloadFile() 方法。因此,当我在另一个线程中使用 hds 的连接对象时,它可能会关闭。解决这个问题的最佳方法是什么?创建新的 HikariDataSource 对象后,我是否应该等待几秒钟再关闭旧的对象(直到查询完成)?

编辑:另一个问题:hds 是否应该是 volatile ,以便 hds 的更改对所有线程都可见?

最佳答案

非常快速、简短地查看了 HikariDataSource 中的源代码。在其 close() 中,它调用其内部 HikariPoolshutdown() 方法,为此它将尝试正确关闭池化池连接。

如果您想避免正在进行的连接被强制关闭,一种方法是使用 ReadWriteLock:

public class ConnectionPool {
    private HikariDataSource hds;
    private ReentrantReadWriteLock dsLock = ....;
    //....

    public void reloadFile() {
        dsLock.writeLock().lock();
        try {
            if (hds != null) {
                hds.close();
            }

            hds = new HikariDataSource(new HikariConfig(propertyFileName));
        } finally {
            dsLock.writeLock().unlock();
        }
    }

    public void executeQuery(final String sql, final CallBack<ResultSet, SQLException> callBack) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Connection connection = null;
                PreparedStatement preparedStatement = null;
                ResultSet resultSet = null;

                dsLock.readLock().lock();
                try {
                    connection = hds.getConnection();
                    // ....
                } catch (SQLException e) {
                    callBack.call(null, e);
                } finally {
                    // your other cleanups
                    dsLock.readLock().unlock();
                }
            }
        }).start();
    }
    //....
}

这将确保

  1. 多个线程可以访问您的数据源(以获取连接等)
  2. 数据源的重新加载需要等待使用数据源的线程完成
  3. 重新加载时,没有线程能够使用数据源来获取连接。

关于Java:与 HikariDataSource 对象的并发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35005139/

相关文章:

java - 确保许多值相等的惯用方法

java - 我的初始值不是从1开始并且保持不变

c++ - 有原子 |= 操作吗?

java - 创建一个对读取操作线程安全的 DOM

ios - NSCondition - 多线程

java - 如何保存 editText 可见性状态 (View.GONE)?

java - 2D 游戏中的 LWJGL HUD

java - 计算 ArrayList 中单词的出现次数

haskell - 并发性能比顺序性能差

c# - 演示受限执行区域重要性的代码