DataSourceの高度なアプリケーション

6152 ワード

DataSourceは、データベースへの同時アクセスを最大限に高めることができることはよく知られていますが、DataSourceへの参照は、Connectionを取得する方法がデータベースのパフォーマンスに最も関連する技術であり、DataSourceの呼び出しがデータベースのパフォーマンスに大きな決定的な役割を果たすことを明らかにする知識もたくさんあります.一般的にDataSourceへの参照は、次の手順で行います.
            Context ct = new InitialContext();
            DataSource ds = (DataSource) ct.lookup(sourceUrl);

 
このような簡単な2行ですが、呼び出し条件が異なると、パフォーマンスに大きな違いが生じます.Connectを取得したパッケージクラスが(Bean)DataSourceへの参照には、いくつかの方法があります.通常のパッケージクラスであれば、構築メソッドで呼び出すことができますが、javaBeanとしてinitメソッドで呼び出すことができますが、どこで呼び出すにしても、このクラスやBeanを呼び出すときは、DataSourceを検索します.実はDataSourceの検索プロセスもかなりのものですリソースを消費するプロセスなので、パッケージクラスやBeanで呼び出すたびに検索しても、実際にはデータソースが変わらない唯一のリソースであるため、DataSourceを静的リソースとして宣言する必要があります.では、なぜstaticと宣言しないのでしょうか.これにより、必要なときだけ検索できます.さらに多くの場合、検索したデータソースを直接参照できます.
public class ConnectionFactory{
     static DataSource dsCache = null;

    aMethodForGetConnectio(){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(source);
                }
            }
        }
        Connection conn = dsCache.getConnection();
    }
}

 
一般的には、ConnectionFactoryが初めて呼び出されたときにのみDataSourceが検索するが、他の場合は事故が起こらない限り(nullではないDataSourceが突然nullになることは考えられない)、検索を必要とせずに直接参照することができる.データソースを静的と宣言しない場合は、ConnectionFactoryを呼び出すたびにjndiの検索が生成されます.
public class ConnectionFactory{
     DataSource dsCache = null;

    aMethodForGetConnectio(){
        if(dsCache == null){
            Context ct = new InitialContext();
            dsCache = (DataSource) ct.lookup(source);
        }
        Connection conn = dsCache.getConnection();
    }
}

 
dsCacheは静的リソースではないため、if(dsCache=null)が呼び出されるたびに成立する.Connectionも静的であれば資源も節約できるのではないかと言われています.接続は工場ではないことに注意し、複数のユーザーが同時に同じ接続にアクセスすると、誰も接続を閉じることができず、最後に誰も接続を閉じていないようになります.最後に使用したユーザーは、後で誰かが使用するかどうか分からないからです.一方、1つのConnectionの処理能力は低い、多くのユーザが同時にデータベースにアクセスするデータを同時に満たすことは不可能である.一方、DataSourceは複数のユーザによる同一のリソースへの参照であるが、工場であり、異なるユーザが同一のDataSourceにアクセスして得られるのは異なるConnectionリソースである.特定のDataSourceを検索するには、jndiの参照を構成します.一般的に、パッケージクラスまたはBeanがjndi参照文字列をデッドラインコードに書くことができない場合は、プロファイルに配置して読み込むことができます.
    Properties properties = new Properties();
    properties.load(new FileInputStream("    "));
    dsCache = (DataSource) ct.lookup(properties.getProperty("key"));

 
これにより、DataSourceを変更する際にConnectionFactoryを再コンパイルせずに「プロファイル」を変更することができますが、1つのコンテナの下にある複数のアプリケーションに複数のDataSourceを同時に構成している場合は、どのデータソースを調べるかを指定することはできませんので、1つの方法を再ロードすることが望ましいです.構築メソッドでも他のメソッドでも、パラメータに基づいて検索されるメソッドを再ロードする必要があります.
public class ConnectionFactory{
     static DataSource dsCache = null;

    aMethodForGetConnectio(){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    Properties properties = new Properties();
                    properties.load(new FileInputStream("    "));
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(properties.getProperty("key"));
                }
            }
        }
        Connection conn = dsCache.getConnection();
    }
    aMethodForGetConnectio(String source){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(source);
                }
            }
        }
        Connection conn = dsCache.getConnection();
    }
}

また、デフォルトの検索文字列については、さらに最適化できますが、プロパティを読み込むたびにパフォーマンスに大きな影響はありません.
public class ConnectionFactory{
     static DataSource dsCache = null;
     static Properties properties = new Properties();
    aMethodForGetConnectio(){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    if(!properties.containsKey("key"))
                        properties.load(new FileInputStream("    "));
                    //                  
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(properties.getProperty("key"));
                }
            }
        }
        Connection conn = dsCache.getConnection();
    }
}

 
以上の最適化により、カプセル化クラスを最小限のリソース消費で最大のパフォーマンスを得ることができます.if(dsCache==null){}発生時の状況をログに記録し、いつこのような異常が発生したかを見て、私は私のデータベースを追跡しました.青島日報社に作ったメールシステムのホストに6万人以上のユーザーがいて、同時に同時にアクセス量が大きいですが、日記の記録は、ログは、アプリケーションを再起動するたびに1つのレコードが生成されます.つまり、ConnectionFactoryが最初に呼び出されたときにのみ生成されます.その他の状況は正常です.
public class ConnectionFactory{
     static DataSource dsCache = null;
     static Properties properties = new Properties();
    aMethodForGetConnectio(){
        if(dsCache == null){
            synchronized(this){
                if(dsCache==null){
                    if(!properties.containsKey("key"))
                        properties.load(new FileInputStream("    "));
                    //                  
                    Context ct = new InitialContext();
                    dsCache = (DataSource) ct.lookup(properties.getProperty("key"));
                }
            }
            //   dsCache == null ,             :
            PrintWriter pw = new PrintWriter(new FileWriter("connection.log",true));
            pw.println(new java.util.Date() + ":      aMethodForGetConnectio():"
                    + sun.reflect.Reflection.getCallerClass(2));
            pw.close();
        }
        Connection conn = dsCache.getConnection();
    }
}

 
主に現在の日付を記録し、現在のメソッド名とどのクラスがこのメソッドを呼び出したかを記録する.sun.reflect.Reflection.getCallerClass(int i)メソッドでは、iが0の場合はReflectionそのもの、1の場合はBeanまたはパッケージクラス、すなわちConnectionFactory、2の場合はそれを呼び出すクラス、3以上は不確定である.これにより、カプセル化クラスやBeanを一定期間(少なくとも数日以上)追跡することができ、アプリケーションが再起動していない場合は、レコードを1つだけ生成する必要があります.これにより、トップクラスのパフォーマンスを持つパッケージクラスが作成されます.