我有一个看起来像这样的课程:
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
}
}
问题是reloadFile()
方法可以使用hds
从不同的线程调用。因此,当我在另一个线程中使用它的连接对象时,hds
可能会被关闭。解决这个问题的最佳方法是什么?我应该在创建新的HikariDataSource
对象后等待几秒钟,然后关闭旧对象(直到查询完成)?
修改:另一个问题:hds
应该volatile
,以便所有主题都可以看到hds
的更改吗?
答案 0 :(得分:1)
在<form method="post" action="password/email" enctype="multipart/form-code">
{!! csrf_field() !!}
<table class="table" style="width:50%; margin:0 auto;">
<tr>
<td colspan="2">
<h1 class="well text-center">Reset Password Form</h1>
</td>
</tr>
<tr>
<td>
Email:<input type="email" name="email" value="{{old('email')}}" />
</td>
</tr>
<tr>
<td>
<button type="submit" class="btn btn-default">Send Password</button>
</td>
</tr>
</table>
</form>
的源代码中有一个非常快速简短的介绍。在其HikariDataSource
中,它正在调用其内部close()
的{{1}}方法,为此它将尝试正确关闭池化连接。
如果您想避免强制关闭正在进行连接的任何可能性,一种方法是使用HikariPool
:
shutdown()
这将确保
答案 1 :(得分:1)
为什么你要让HikariCP重新加载?许多重要的池参数(minimumIdle
,maximumPoolSize
,connectionTimeout
等)在运行时可通过JMX bean进行控制,而无需重新启动池。
在关闭和重建连接时,重新启动池是将应用程序“挂起”几秒钟的好方法。如果你不能通过JMX界面做你需要的东西,Adrian的建议似乎是一个非常合理的解决方案。
其他解决方案是可行的,但更复杂。
编辑:仅仅是为了我自己的娱乐,这里是更复杂的解决方案......
public class ConnectionPool {
private AtomicReference<HikariDataSource> hds;
public ConnectionPool(String propertyFileName) {
hds = new AtomicReference<>();
...
}
public void reloadFile() {
final HikariDataSource ds = hds.getAndSet(new HikariDataSource(new HikariConfig(propertyFileName)));
if (ds != null) {
new Thread(new Runnable() {
public void run() {
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + ds.getPoolName() + ")");
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
HikariPoolMXBean poolProxy = JMX.newMXBeanProxy(mBeanServer, poolName, HikariPoolMXBean.class);
poolProxy.softEvictConnections();
do {
Thread.sleep(500);
} while (poolProxy.getActiveConnections() > 0);
ds.close();
}
}).start();
}
}
public HikariDataSource getHikariDataSource() {
return hds.get();
}
public void executeQuery(final String sql, final CallBack<ResultSet, SQLException> callBack) {
new Thread(new Runnable() {
@Override
public void run() {
...
try {
connection = getHikariDataSource().getConnection();
...
}
}
}).start();
}
}
这将换出池(原子)并将启动一个等待所有活动连接返回的线程,然后再关闭孤立池实例。
这假设您让HikariCP生成唯一的池名称,即不在您的属性中设置poolName
,并registerMbeans=true
。
答案 2 :(得分:0)
一些选择:
同步对数据源的所有访问权限,以便只有一个线程可以搞乱它。不可扩展,但可行。
滚动您自己的连接池,例如Apache Commons Pooling,这样无论线程如何,每次访问都会请求数据源,池会根据需要创建一个。可以搞乱数据ACID,只取决于是否需要脏数据,数据刷新,事务性等等。
每个线程也可以使用ThreadLocal拥有自己的数据源,以便每个线程完全相互独立。同样,数据质量可能是一个问题,如果您已经获得了很多资源,那么资源可能会成为一个问题。线程(取决于您的定义)和太多的开放连接导致客户端或服务器上的资源问题。