Класс только с статическими членами, который имеет внутреннее состояние - PullRequest
0 голосов
/ 25 января 2012

Я чувствую, как будто у меня нет моего дизайна прямо здесь, и что я застрял между двумя методами. Я пытаюсь написать класс, который раздает соединения с базой данных. Код ниже:

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?

Большое спасибо.

Ответы [ 4 ]

2 голосов
/ 25 января 2012

Этот метод должен иметь значение 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 предлагает вам объявить поле источника данных как volatile. Это ключевое слово гарантирует, что поток не использует локальную для потока копию переменной (это может вызвать проблемы, если поток читает устаревшее кэшированное значение).

Я не уверен, происходит ли этот случай между различными вызовами методов или syncrhonized имеет дело с этим, но лучше быть уверенным:)

1 голос
/ 25 января 2012

Вот почему FindBugs жалуется:

http://findbugs.sourceforge.net/bugDescriptions.html#LI_LAZY_INIT_UPDATE_STATIC

Как уже упоминалось, если у вас нет нескольких потоков, у вас не должно быть проблем.

1 голос
/ 25 января 2012

Findbugs жалуется, потому что ваш метод getDataSource не синхронизирован.С вашим текущим кодом два параллельных потока могут вызывать getDataSource и извлекать их в отдельные объекты DataSource.

1 голос
/ 25 января 2012

Проблема с этим кодом заключается в том, что при наличии нескольких заголовков вы можете в конечном итоге создать несколько экземпляров 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();

Простой способ решить проблему параллелизма - добавить синхронизацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...