我在 java 中尽可能简单的连接管理器是线程安全的吗?
Is my as-simple-as-possible connection manager in java thread-safe?
我尝试为在 tomcat7 服务器上运行的小型 Web 应用程序创建尽可能简单的连接管理器。我找到了很多关于如何实现它的例子,但几乎总是那些需要 JNDI 和 JEE,否则就没有完整的例子。
我希望我的连接管理器在我调用 getConnection() 时从连接池传递一个连接,并且它是线程安全的,这样在我关闭它之前没有其他人使用我的连接。
在我的应用程序中,我从 REST 服务调用 ConnectionManager.getConnection(),然后在整个请求中使用该连接进行所有数据库调用,并在 finally 子句中关闭它。
有人可以看看我的代码,看看它是否足以满足我的需求...?两个 REST 调用可能获得相同的连接或 tomcat DataSource 是否为我处理它是否有任何风险?
让我的 class 成为一个带有 getDataSource() 方法的 DataSourceManager 来传递数据源,并在我的 REST 服务中获得与 DataSourceManager.getDataSource() 的连接是否更合适。获取连接()?从技术上讲,这会有什么不同吗?
或者我必须以其他方式执行此操作才能使其正常工作...?
import java.sql.Connection;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import se.esvenska.util.Property;
public class ConnectionManager {
private static DataSource dataSource;
private static void initDataSource() throws DatabaseException {
try {
PoolProperties p = new PoolProperties();
p.setUrl("...url...");
p.setDriverClassName("org.postgresql.Driver");
p.setUsername("...user...");
p.setPassword("...password...");
p.setDefaultAutoCommit(false);
dataSource = new DataSource();
dataSource.setPoolProperties(p);
} catch (Exception e) {
e.printStackTrace();
throw new DatabaseException(e);
}
}
public static Connection getConnection() throws Exception {
if (dataSource == null) {
initDataSource();
}
return dataSource.getConnection();
}
}
这取决于你所说的线程安全是什么意思。我不认为它会爆炸,但你肯定有可能不止一次地调用 initDataSource
。
public static Connection getConnection() throws Exception {
if (dataSource == null) { // Another thread can come in after this
initDataSource(); // and before this
}
return dataSource.getConnection();
}
你需要synchronize
那个方法:
public static synchronized Connection getConnection() throws Exception {
// -----------^
if (dataSource == null) { // Now this region is
initDataSource(); // protected
}
return dataSource.getConnection();
}
我建议进行一些更改:
- 将构造函数设为私有
getConnection
应该是使用双锁的线程安全的,详情 here
package com.test;
import java.sql.Connection;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import se.esvenska.util.Property;
public class ConnectionManager {
private ConnectionManager() {
}
private static DataSource dataSource;
private static void initDataSource() throws DatabaseException {
try {
PoolProperties p = new PoolProperties();
p.setUrl("...url...");
p.setDriverClassName("org.postgresql.Driver");
p.setUsername("...user...");
p.setPassword("...password...");
p.setDefaultAutoCommit(false);
dataSource = new DataSource();
dataSource.setPoolProperties(p);
} catch (Exception e) {
e.printStackTrace();
throw new DatabaseException(e);
}
}
public static Connection getConnection() throws Exception {
if (dataSource == null) {
synchronized(ConnectionManager. class) {
if (dataSource == null) {
initDataSource();
}
}
}
return dataSource.getConnection();
}
}
我尝试为在 tomcat7 服务器上运行的小型 Web 应用程序创建尽可能简单的连接管理器。我找到了很多关于如何实现它的例子,但几乎总是那些需要 JNDI 和 JEE,否则就没有完整的例子。
我希望我的连接管理器在我调用 getConnection() 时从连接池传递一个连接,并且它是线程安全的,这样在我关闭它之前没有其他人使用我的连接。
在我的应用程序中,我从 REST 服务调用 ConnectionManager.getConnection(),然后在整个请求中使用该连接进行所有数据库调用,并在 finally 子句中关闭它。
有人可以看看我的代码,看看它是否足以满足我的需求...?两个 REST 调用可能获得相同的连接或 tomcat DataSource 是否为我处理它是否有任何风险?
让我的 class 成为一个带有 getDataSource() 方法的 DataSourceManager 来传递数据源,并在我的 REST 服务中获得与 DataSourceManager.getDataSource() 的连接是否更合适。获取连接()?从技术上讲,这会有什么不同吗?
或者我必须以其他方式执行此操作才能使其正常工作...?
import java.sql.Connection;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import se.esvenska.util.Property;
public class ConnectionManager {
private static DataSource dataSource;
private static void initDataSource() throws DatabaseException {
try {
PoolProperties p = new PoolProperties();
p.setUrl("...url...");
p.setDriverClassName("org.postgresql.Driver");
p.setUsername("...user...");
p.setPassword("...password...");
p.setDefaultAutoCommit(false);
dataSource = new DataSource();
dataSource.setPoolProperties(p);
} catch (Exception e) {
e.printStackTrace();
throw new DatabaseException(e);
}
}
public static Connection getConnection() throws Exception {
if (dataSource == null) {
initDataSource();
}
return dataSource.getConnection();
}
}
这取决于你所说的线程安全是什么意思。我不认为它会爆炸,但你肯定有可能不止一次地调用 initDataSource
。
public static Connection getConnection() throws Exception {
if (dataSource == null) { // Another thread can come in after this
initDataSource(); // and before this
}
return dataSource.getConnection();
}
你需要synchronize
那个方法:
public static synchronized Connection getConnection() throws Exception {
// -----------^
if (dataSource == null) { // Now this region is
initDataSource(); // protected
}
return dataSource.getConnection();
}
我建议进行一些更改:
- 将构造函数设为私有
getConnection
应该是使用双锁的线程安全的,详情 herepackage com.test; import java.sql.Connection; import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.PoolProperties; import se.esvenska.util.Property; public class ConnectionManager { private ConnectionManager() { } private static DataSource dataSource; private static void initDataSource() throws DatabaseException { try { PoolProperties p = new PoolProperties(); p.setUrl("...url..."); p.setDriverClassName("org.postgresql.Driver"); p.setUsername("...user..."); p.setPassword("...password..."); p.setDefaultAutoCommit(false); dataSource = new DataSource(); dataSource.setPoolProperties(p); } catch (Exception e) { e.printStackTrace(); throw new DatabaseException(e); } } public static Connection getConnection() throws Exception { if (dataSource == null) { synchronized(ConnectionManager. class) { if (dataSource == null) { initDataSource(); } } } return dataSource.getConnection(); } }