ネイティブJDBCトランザクション管理は、マニュアルをコミットとロールバックが必要な、比較的複雑ですが、またのtry-catchの束。学生が知っているおなじみの春は、春には、トランザクション管理の変更をトランザクション管理サービスへの宣言的なアプローチを使用しています非常にシンプル。春のトランザクションは、私はいくつかの簡単なJDBCプロパティをシミュレートするために、ここで使用され、非常に強いです。
1.宣言的トランザクションデザイン
Javaの動的プロキシ実装に主に基づいて、宣言的トランザクション
接続によって同時実行の問題を解決するためにThreadLocal変数に格納されている。春にはまた、基本的な使用のThreadLocalです。
ネストされたトランザクションの問題を解決するために、接続の作成者を記録することにより。
カスタム注釈@EnableTranscation:トランザクションが開いているかどうかを示すために使用される方法
サービス工場:あなたは@EnableTranscationサービスが含ま修正の方法を使用している場合、それ以外のサービスインスタンス、サービスプロキシオブジェクトが作成され、春の豆のコースをシミュレートするために使用されるコンテナを作成します
カスタムダオ、接続を直接作成することはできません、あなたは現在のスレッドの接続のホールドを取得する必要があります。
2.接続プールの管理
これは、データベースへの接続にC3P0接続プールを使用しました。
2.1 C3POの設定
ルート
ルート
com.mysql.jdbc.Driver
JDBCます。mysql:// localhostを:?3306 /学ぶ-JDBC characterEncoding = UTF-8
10
5
5
50
100
10
2.2データベース接続ツール
パッケージと閉じたデータベース接続リソースデータベース接続の方法
パブリッククラスDbConnUtil {
// C3P0設定名
プライベート静的最後の文字列c3p0PoolName =「myC3p0Pool」。
//コンフィグレーションデータソース
プライベート静的最終データソースのdataSource =新しいComboPooledDataSource(c3p0PoolName)。
//ローカル接続を設定します
プライベート静的ThreadLocalのtxConnectionLocal =新しいのThreadLocal <>();
/ **データベース接続
* @ParamをautoCommitTxオープンオファーがトランザクションをコミットするかどうか
* @Return Connectionデータベース接続
* @since 1.0
* @author zongf
* 2019年7月18日@Created
* /
パブリック静的接続のgetConnection(ブールautoCommitTx){
{試します
接続の接続= dataSource.getConnection()。
Connection.setAutoCommit(autoCommitTx)。
接続を返します。
}キャッチ(のSQLException e)の{
e.printStackTrace();
}
ヌルを返します。
}
/ **
* @description:このスレッドの接続を取得
* @Return:接続データベース接続
* @author:zongf
* @time:2019年6月26日午後2時37分〇〇秒
* @since 1.0
* /
パブリック静的TxConnection getTxConnection(){
TxConnection txConnection = NULL;
// ThreadLocalの接続が空の場合は、新しい接続を作成します
IF(txConnectionLocal.get()== NULL || txConnectionLocal.get()のgetConnection()== NULL){
txConnection =新しいTxConnection(のgetConnection(真));
txConnectionLocal.set(txConnection)。
}他{
txConnection = txConnectionLocal.get()。
}
txConnectionを返します。
}
現在のスレッドで/ **データベース接続
* @return接続
* @since 1.0
* @author zongf
* 2019年7月18日@Created
* /
パブリック静的接続getLocalConnection(){
。getTxConnection()のgetConnection()を返します。
}
現在のスレッドの/ **データベース接続オブジェクト
* @returnのThreadLocal
* @since 1.0
* @author zongf
* 2019年7月18日@Created
* /
パブリック静的ThreadLocalのgetLocalTxConnection(){
txConnectionLocalを返します。
}
/ **戻り接続は、あなたが設定する必要がある場合はtrueに自動コミット。
* @param接続
* @returnヌル
* @since 1.0
* @author zongf
* 2019年7月18日@Created
* /
パブリック静的ボイドリリース(コネクション接続)は、SQLExceptionをスローします{
{試します
もし(接続!= nullの&&!connection.isClosed()){
Connection.setAutoCommit(真)。
}
}キャッチ(のSQLException e)の{
e.printStackTrace();
} 最後に {
connection.close();
}
}
}
2.3トランザクション定義された接続オブジェクト
1は動的プロキシオープントランザクションを追跡する必要があるため、ネストされたトランザクションは、総務担当の開口部と層の動的エージェントによってロールバックされ、そのため取引オープナーを記録する必要があります。私はTxConnnecitonオブジェクトを作成したそうです。
パブリッククラスTxConnection {
プライベート接続接続。
プライベート文字列の作成者。
//省略セッター/ゲッターメソッド
}
3.トランザクション開いたコメントをカスタマイズします
同様の春の定義には、トランザクションを開くためのコメント@Transcation。
Propagation.REQUIRES_NEW openNewTx春の取引シミュレーションの伝播のための7の1
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
公共@interface EnableTranscation {
//新しいトランザクションを開くかどうか
ブールopenNewTx()デフォルトはfalse;
}
4.動的プロキシ・プロセッサ
/ **総務動的プロキシプロセッサ
* @since 1.0
* @author zongf
* 2019年7月18日@Created
* /
パブリッククラスTranscationHandlerは{のInvocationHandlerを実装します
プライベートオブジェクトのターゲット。
公共TranscationHandler(オブジェクト・ターゲット){
this.target =ターゲット。
}
パブリックオブジェクトを呼び出し(オブジェクトプロキシ、メソッドのメソッド、オブジェクト[] argsが)のThrowableを{スロー
//現在のデータベース接続を取得します。
TxConnection txConnection = DbConnUtil.getTxConnection()。
//古い接続オブジェクトを保存
TxConnection oldTxConnection = NULL;
{試します
//ターゲットオブジェクトのメソッドを取得します。
。方法targetMethod = target.getClass()getMethod(method.getName()、method.getParameterTypes())。
現在開いているトランザクションかどうかを確認するには//メソッド
ブールenableTx = targetMethod.isAnnotationPresent(EnableTranscation.class)。
//現在の接続が手動に設定されているオープントランザクションは、トランザクションをコミットした場合
IF(enableTx){
//情報のメモを入手
EnableTranscation注釈= targetMethod.getAnnotation(EnableTranscation.class)。
//新しいトランザクションを開くかどうかを取得します
ブールopenNewTx = annotation.openNewTx()。
(もし!txConnection.getConnection()。getAutoCommit()){// falseを、トランザクションが開かれたことを示します
もし(openNewTx){//あなたは、トランザクションを開く必要がある場合
//元のデータベース接続を保存
oldTxConnection = txConnection。
//新しい接続を取得します。
txConnection =新しいTxConnection(DbConnUtil.getConnection(偽)、this.toString());
//現在のスレッドでデータベース接続を置き換えます
DbConnUtil.getLocalTxConnection()セット(txConnection)。
}
}エルスは{// trueが、それはトランザクションがオンになっていないことを示し、
//オープン・トランザクションは、設定をfalseに自動コミットしない。それは、ビジネスを開始していると述べました
txConnection.getConnection()にsetAutoCommit(false)を指定します。;
txConnection.setCreator(this.toString())。
}
}
//ターゲット・メソッドを実行します
対象物体= targetMethod.invoke(this.target、引数)。
トランザクションが現在のハンドラオブジェクトが作成されている場合は、//、トランザクションをコミット
IF(this.toString()。等号(txConnection.getCreator())){
txConnection.getConnection()(コミット)。
}
オブジェクトを返します。
}キャッチ(例外e){
もし(txConnection!= nullの&& this.toString()。等号(txConnection.getCreator())){
もし(txConnection.getConnection()!= nullを&&!txConnection.getConnection()。閉じられ()){
。txConnection.getConnection()ロールバック();
txConnection.getConnection()にsetAutoCommit(真)。
}
}
新しいのRuntimeException(「!例外が発生し、トランザクションがロールバックされた」、e)を投げます。
} 最後に {
//データベース接続を解放
もし(txConnection!= nullの&& this.toString()。等号(txConnection.getCreator())){
DbConnUtil.release(txConnection.getConnection())。
}
新しい接続がnullでない場合は、//、それは新しいビジネスを開くことを意味する。元の接続をロールバック
もし(oldTxConnection!= NULL){
DbConnUtil.getLocalTxConnection()セット(oldTxConnection)。
}
}
}
}
5.のServiceFactory工場
サービスファクトリクラスを作成し、春のコンテナをシミュレートするために使用。ターゲット・サービスが@EnableTransactionノートを含める場合は、動的プロキシサービス、または作成サービスオブジェクトを作成します。
/ **サービスプラントシミュレーションの春のコンテナ
* @since 1.0
* @author zongf
* 2019年7月18日@Created
* /
パブリッククラスのServiceFactory {
/ ** Serviceインスタンスを取得します。
* @Param CLZサービス実装クラスの種類
* @Return Tサービスオブジェクトまたは動的プロキシオブジェクト
* @since 1.0
* @author zongf
* 2019年7月18日@Created
* /
パブリック静的TのgetService(クラスCLZ){
T T = NULL;
{試します
T = clz.newInstance()。
}キャッチ(例外e){
e.printStackTrace();
新しいのRuntimeExceptionをスロー(「オブジェクトの作成に失敗しました」);
}
//判断がインターフェイスにすることはできません、インタフェースの実装クラスを作成することはできません
IF(clz.isInterface()){
(「インタフェースはインスタンスを作成することはできません!」)新しいのRuntimeExceptionを投げます。
}
//動的プロキシを開くかどうか
偽enableTx =ブール。
この方法は、ノートを@EnableTx持っている場合//すべての非プライベートメソッドをループ、その後、プロキシを作成する必要があります
方法[]メソッド= clz.getMethods()。
{(メソッドメソッド法)のために
(method.getAnnotation(EnableTranscation.class)!= NULL){場合
enableTx =はtrue。
ブレーク;
}
}
//プロキシを作成する必要がある場合は、プロキシオブジェクトが返されます
IF(enableTx){
リターン(T)たとえば、Proxy.newProxyInstance(clz.getClassLoader()、clz.getInterfaces()、新しいTranscationHandler(T))。
}
トンを返します。
}
}
6.宣言的トランザクションのテスト
著者BaseDao前に書かれたテストは、基本的な手順を用いて開発を簡素化します。
1.1定義インタフェース
パブリックインターフェイスIMixService {
//通常のシミュレート
空成功();
//異常動作、トランザクションのロールバックをシミュレート
空エラー();
空のショー();
}
6.2実装クラスを定義します
パブリッククラスMixServiceは{IMixServiceを実装します
プライベートIUserService UserServiceの= ServiceFactory.getService(UserService.class)。
プライベートIPersonService personService = ServiceFactory.getService(PersonService.class)。
@EnableTranscation
@オーバーライド
公共ボイド成功(){
this.userService.save(新しいUserPO( "ユーザ01"、 "123456"));
this.personService.save(新PersonPO( "人-01"、 "ABCDEFG"));
} 無錫ウィメンズ病院http://www.bhnnk120.com/
@EnableTranscation
@オーバーライド
公共ボイドエラー(){
this.userService.save(新しいUserPO( "ユーザ01"、 "123456"));
this.personService.save(新PersonPO( "人-01"、 "ABCDEFG"));
//異常ホールをシミュレート
int型のA = 1/0;
}
@オーバーライド
公共ボイドショー(){
一覧userPOS = this.userService.queryAll();
一覧personPOS = this.personService.queryAll();
System.out.println( "\ nは****** t_user:*****");
userPOS.forEach(のSystem.out ::のprintln)。
System.out.println( "\ nは****** t_person:*****");
personPOS.forEach(のSystem.out ::のprintln)。
}
}
6.3テストケース
パブリッククラスMixServiceは{IMixServiceを実装します
プライベートIUserService UserServiceの= ServiceFactory.getService(UserService.class)。
プライベートIPersonService personService = ServiceFactory.getService(PersonService.class)。
@EnableTranscation
@オーバーライド
公共ボイド成功(){
this.userService.save(新しいUserPO( "ユーザ01"、 "123456"));
this.personService.save(新PersonPO( "人-01"、 "ABCDEFG"));
}
@EnableTranscation
@オーバーライド
公共ボイドエラー(){
this.userService.save(新しいUserPO( "ユーザ01"、 "123456"));
this.personService.save(新PersonPO( "人-01"、 "ABCDEFG"));
//異常ホールをシミュレート
int型のA = 1/0;
}
@オーバーライド
公共ボイドショー(){
一覧userPOS = this.userService.queryAll();
一覧personPOS = this.personService.queryAll();
System.out.println( "\ nは****** t_user:*****");
userPOS.forEach(のSystem.out ::のprintln)。
System.out.println( "\ nは****** t_person:*****");
personPOS.forEach(のSystem.out ::のprintln)。
}
}