2012-01-25 16 views
0

私はここに自分のデザインを持っていないと感じ、私は2つのテクニックの間にこだわっています。私は、データベースに接続を渡すクラスを作成しようとしています。コードは以下の通りです:私が行うとき内部状態の静的メンバーのみを持つクラス

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をreturingさ:

if (dataSource == null) { 
     dataSource = new ComboPooledDataSource(); 
     ... 

何かアドバイスは大歓迎します。私はシングルトンパターンと単純な静的メソッドのセットからなるクラスの間のどこかにここでこだわっているかのように感じます。

もっと一般的に、これはDAOへのデータベース接続を引き渡す良い方法ですか?

多くのありがとうございます。

+0

本当に変更可能な統計情報は避けたいと思っています。 –

答えて

2

この方法は、2つの並列実行(同時に2つのスレッドを呼び出す)を避けるため、​​である必要があります。 2つのデータソース(T2はT1のオブジェクトの作成をオーバーライドする際に依存する)のいずれかでメソッドを呼び出す

T1 if (datasource == null) YES 
T2        if (datasource == null) YES 
T1 datasource = new Datasource... 
T2        datasource = new Datasource(...); AGAIN! 

とT1とT2:例外がこれを実行する二つのスレッドにつながる可能性が同期していない

を追加しました

揮発性ジャンマルクは、あなたがvolatileとしてデータソースのフィールドを宣言すべき提案@として。このキーワードは、スレッドが変数のスレッドローカルコピーを使用しないようにします(スレッドが古いキャッシュされた値を読み取ると問題を引き起こす可能性があります)。

私はこのような場合は、別のメソッド呼び出しの間で発生したかどうかわからないんだけど、かとsyncrhonized取引であれば、確かに良いでしょう:)

+1

絶対に安全なように、私はvolatileSourceとしてdataSourceを宣言する必要もあると思います。 –

+0

アーキテクチャについて:小さな制御されたアプリケーションにはSingleton + Factoryを使用しても問題ありません。もっと大きなことをしたいのなら、Spring IOC(あなたが知っているのは、XMLを作成してオブジェクトをつなぎ合わせること)を使うことを検討すべきです。あなたのアプリケーションの特殊性がそのXML設定オブジェクトに含まれ、オブジェクトが(DAO.datasourceとして)プロパティを設定していると単純に仮定しているので、これはうれしいことです。それはハリウッドの原則と呼ばれています。「私たちに電話しないで、電話します」。 – helios

+0

メソッドが同期化されている場合、データソースフィールドは、synchronizedがすでにメモリバリアを意味するため、volatileである必要はありません。 –

1

そのコードに問題があなたをmultitheadingの存在下での可能性があることです多くの場合、ComboPooledDataSourceの複数のインスタンスが作成され、dataSourceのインスタンスが異なる時刻にあることがあります。

これは、メソッドがほぼ同時に複数のスレッドによって呼び出された場合に発生する可能性があります。

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(); 

同時実行の問題を解決する簡単な方法は、同期を追加することです:

はのはdataSourcenullで、次のように2つのスレッドの実行がインターリーブされているとしましょう。

1

getDataSourceメソッドが同期されていないため、Findbugsが苦情を申し立てています。現在のコードでは、2つの同時スレッドがgetDataSourceを呼び出して、別のDataSourceオブジェクトに取得することが可能です。

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

を述べたように、あなたが問題を持つべきではありません複数のスレッドを持っていない場合:FindBugsのは不平を言っている理由

関連する問題