![](/img/trans.png)
[英]Is it poor design to declare a class abstract because it only has static members?
[英]Class with only static members which has an internal state
我感觉好像我的设计还没到位,我陷入了两种技术之间。 我正在尝试编写一个类,分发与数据库的连接。 代码如下:
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正在重新启动Incorrect lazy initialization and update of static field
:
if (dataSource == null) {
dataSource = new ComboPooledDataSource();
...
任何建议,不胜感激。 我感觉好像卡在Singleton模式和一个仅由一组静态方法组成的类之间的某个地方。
更一般而言,这是将数据库连接分发给DAO的好方法吗?
非常感谢。
为了避免两次并行执行(两个线程同时调用它),应该synchronized
该方法。
添加
未同步的异常可能导致两个线程执行此操作:
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建议的那样,您应该将datasource字段声明为volatile
。 该关键字确保线程不使用变量的线程本地副本(如果线程读取过期的缓存值,则可能导致问题)。
我不确定这种情况是否在不同的方法调用之间发生,或者是否syncrhonized
处理,但是最好确定:)
该代码的问题在于,在存在多头处理的情况下,您最终可能会创建ComboPooledDataSource
多个实例, ComboPooledDataSource
dataSource
在不同的时间指向不同的实例。
如果该方法大约同时被多个线程调用,则可能发生这种情况。
假设dataSource
为null
,并且两个线程的执行交织如下:
Thread 1: if (dataSource == null) { // condition is true
Thread 2: if (dataSource == null) { // condition is true
Thread 1: dataSource = new ComboPooledDataSource();
Thread 2: dataSource = new ComboPooledDataSource();
解决并发问题的一种简单方法是添加同步。
Findbugs抱怨因为您的getDataSource
方法未同步。 使用当前代码,两个并发线程可以调用getDataSource
并检索到单独的DataSource对象。
这就是为什么FindBugs抱怨的原因:
http://findbugs.sourceforge.net/bugDescriptions.html#LI_LAZY_INIT_UPDATE_STATIC
如前所述,如果您没有多个线程,则应该没有问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.