我感觉好像我的设计还没有到位,而且我陷入了两种技术之间。我正在尝试编写一个类来分发与数据库的连接。代码如下:
public final class DBUtil {
private static String databaseDriver = null;
private static String databaseConnectionString = null;
private static String databaseUser = null;
private static String databasePassword = null;
private static String serverName = null;
private static ComboPooledDataSource dataSource = null;
private DBUtil() {
throw new AssertionError();
}
private static void getParameters() {
final Properties configFile = new Properties();
try {
configFile.load(DBUtil.class.getClassLoader().getResourceAsStream("my.properties"));
if (configFile.containsKey("databaseConnectionString") && configFile.containsKey("databaseUser") && configFile.containsKey("databasePassword") && configFile.containsKey("databaseDriver")) {
DBUtil.databaseConnectionString = configFile.getProperty("databaseConnectionString");
DBUtil.databaseDriver = configFile.getProperty("databaseDriver");
DBUtil.databaseUser = configFile.getProperty("databaseUser");
DBUtil.databasePassword = configFile.getProperty("databasePassword");
}
else {
// Properties file not configured correctly for database connection
}
}
catch (IOException e) {}
}
public static Connection getDatabaseConnection() {
if (Strings.isNullOrEmpty(databaseConnectionString) || Strings.isNullOrEmpty(databaseUser) || Strings.isNullOrEmpty(databasePassword) || Strings.isNullOrEmpty(databaseDriver)) {
DBUtil.getParameters();
}
dataSource = getDataSource();
int retryCount = 0;
Connection connection = null;
while (connection == null) {
try {
connection = dataSource.getConnection();
}
catch (SQLException sqle) {}
}
return connection;
}
private static ComboPooledDataSource getDataSource() {
if (dataSource == null) {
dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass(databaseDriver);
dataSource.setJdbcUrl(databaseConnectionString);
dataSource.setUser(databaseUser);
dataSource.setPassword(databasePassword);
}
catch (PropertyVetoException pve) {}
}
return dataSource;
}
public static void cleanUpDataSource() {
try {
DataSources.destroy(dataSource);
}
catch (SQLException sqle) {}
}
}
当我这样做时,FindBugs 正在返回错误的延迟初始化和静态字段更新
:
if (dataSource == null) {
dataSource = new ComboPooledDataSource();
...
非常感谢任何建议。我感觉好像我被困在单例模式和仅由一组静态方法组成的类之间。
更一般地说,这是向 DAO 分发数据库连接的好方法吗?
非常感谢。
最佳答案
该方法应该同步
以避免两次并行执行(两个线程同时调用它)。
已添加
不同步异常可能会导致两个线程执行此操作:
T1 if (datasource == null) YES
T2 if (datasource == null) YES
T1 datasource = new Datasource...
T2 datasource = new Datasource(...); AGAIN!
T1 和 T2 在两个数据源之一上调用方法(取决于 T2 何时覆盖 T1 对象创建)。
不稳定
正如@Jean-Marc建议的那样,您应该将数据源字段声明为 volatile
。该关键字确保线程不使用变量的线程本地副本(如果线程读取过时的缓存值,这可能会导致问题)。
我不确定这种情况是否发生在不同的方法调用之间,或者 syncrhonized
是否处理它,但最好确定:)
关于java - 仅包含具有内部状态的静态成员的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9004233/