java - 仅包含具有内部状态的静态成员的类

标签 java design-patterns jdbc singleton

我感觉好像我的设计还没有到位,而且我陷入了两种技术之间。我正在尝试编写一个类来分发与数据库的连接。代码如下:

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/

相关文章:

java - 在资源文件中使用maven项目信息

C# 2.0 设计问题 - 从更大的列表创建子列表

java - 如何使用 Java 在控制台中打印任何 PostgreSQL 查询结果?

java - 如何仅使用一个连接在 hibernate 中执行嵌套事务?

Java虚拟对象

java - Android 文本,文本顶部/底部带有 Spannable 图像

java - Java中的第三方API包装器: how to design

c# - 在 N 层架构中实现数据库功能对象?

jdbc - 组织.hibernate.MappingException :No Dialect mapping for JDBC type: -9

java - 对于这种情况,Java String.split 需要什么正则表达式