SpringAOP和Spring事物管理

来源:https://www.cnblogs.com/haizai/archive/2019/05/14/10864808.html
-Advertisement-
Play Games

Spring AOP : Pointcut表達式: designators-指示器 wildcards-通配符 operators-操作符 wildcards: * -- 匹配任意數量的字元 + -- 匹配製定類及其子類 ..-- 一般用於匹配任意數的子包或參數 operator: && || ! ...


Spring AOP :

Pointcut表達式: designators-指示器 wildcards-通配符 operators-操作符
wildcards: * -- 匹配任意數量的字元
+ -- 匹配製定類及其子類
..-- 一般用於匹配任意數的子包或參數
operator: && || !
Wildcards(通配符)
* 匹配任意數量的字元
+ 匹配指定類及其子類
.. 一般用於匹配任意數的子包或參數

Pointcut :切麵表達式
designators:指示器,描述通過什麼方式去匹配Java的那些方法
execution():匹配方法
匹配註解
@target()
@args()
@within()
@annotation()
within():匹配包/類型
this()/bean()/target():匹配對象
args():匹配參數

wildcards:通配符(*:匹配任意數量的字元;+匹配指定類及其子類;..:一般用於匹配任意數的子包或參數)
operators: 運算符(&&:與操作符;||或;!:非)

匹配包/類型 :
// 匹配ProductService類裡頭的所有方法
@Pointcut("within(com.imooc.service.ProductService)")
public void matchType() {
}

// 匹配com.imooc包及子包下所有類的方法
@Pointcut("within(com.imooc..*)")
public void matchPackage(){}

匹配對象:
1:this(包名):匹配AOP對象的目標對象指定類型的方法;
2:target(包名):匹配實現介面的目標對象的方法(不是AOP代理後的對象);
3:bean(包名):匹配所有以Service結尾的bean裡頭的方法;

/**
public class DemoDao implements IDao{}
*/
// 匹配AOP對象的目標對象為指定類型的方法,即DemoDao的aop代理對象的方法
@Pointcut("this(com.imooc.DemoDao)")
public void thisDemo() {}

// 匹配實現IDao介面的目標對象(而不是aop代理後的對象)的方法,這裡即DemoDao的方法
@Pointcut("target(com.iommc.IDao)")
public void targetDemo() {}

// 匹配所有以Service結尾的bean裡頭的方法
@Pointcut("bean(*Service)")
public void beanDemo() {}

匹配參數
// 匹配任何以find開頭而且只有一個Long參數的方法
@Pointcut("execution(* * ..find*(Long))")
public void argsDemo1() {}

// 匹配任何只有一個Long參數的方法
@Pointcut("args(Long)")
public void argsDemo2() {}

// 匹配任何find開頭的而且第一個參數為Long型的方法
@Pointcut("execution(* *..find*(Long,..)")
public void argsDemo3() {}

// 匹配第一個參數為Long型的方法
@Pointcut("args(Long,..)")
public void argsDemo4() {}

匹配註解:
1:匹配方法級別的;
2:匹配類級別的;
3:匹配參數級別的;

@annotion:匹配方法級別的註解方法;
@within:匹配標註有Beta的類底下的方法;
@target:匹配標註有Repository的類底下的方法;
@args:匹配傳入的參數類標註有Repository註解的方法;

示例 :
1: // 匹配方法標註有AdminOnly的註解的方法
@Pointcut("@annotation(com.imooc.demo.security.AdminOnly)")
public void annoDemo(){}

2: // 匹配標註有Beta的類地下的方法,要求的anntation的RetentionPolity級別的CLASS
@Pointcut("@within(com.google.common.annotations.Beta)")
public void annoWithDemo(){}

3: // 匹配標註有Repository的類地下的方法,要求的annotation的RetentionPolicy級別為RUNTIME
@Pointcut("@target(org.springframework.stereotype.Repository)")
public void annoTargetDemo() {}

4: //匹配傳入的參數類標註有Repository註解的方法;
@Pointcut("@args(org.springframework.stereotype.Repository)")
public void annoArgsDemo(){}

@Before,表示在切點之前執行的插入的邏輯;
@Aspect切麵類,標註界面類;
@Component,標註在類上,表示這個類交給spring托管;
execution表達式:
攔截方法:
@Pointcut("execution(public * com.imooc.service.*.*(..))");
攔截拋出的異常:
@Pointcut("exection(public * com.imooc.service.*.*(..) throws java.lang.IllegalAccessException)");
//匹配任何公共方法
@Pointcut("execution(public * com.imooc.service.*.*(..))")

//匹配com.imooc包及子包下Service類中無參方法
@Pointcut("execution(* com.imooc..*Service.*())")

//匹配com.imooc包及子包下Service類中的任何只有一個參數的方法
@Pointcut("execution(* com.imooc..*Service.*(*))")

//匹配com.imooc包及子包下任何類的任何方法
@Pointcut("execution(* com.imooc..*.*(..))")

//匹配com.imooc包及子包下返回值為String的任何方法
@Pointcut("execution(String com.imooc..*.*(..))")

//匹配異常
execution(public * com.imooc.service.*.*(..) throws java.lang.IllegalAccessException)

5種Advice:
1:@Before,前置通知;
2:@After(finally),後置通知,方法執行完成之後;
3:@AfterReturning,返回通知,成功執行之後執行;
4:@AfterThrowing,異常通知,拋出異常之後執行
5: @Around : 環繞通知

原理概述 : 織入的時機
1: 編譯期(Aspectj)
2: 類載入時(Aspectj 5+)
3: 運行時(Spring AOP)
運行時織入:
1:靜態代理與動態代理;
2:基於介面代理與基於繼承代理;

代理模式;
組成:調用者,統一的介面、真實對象、代理者;
原理:通過介面,實現這樣一個過程,在調用真實對象的時候,調用者並不直接與真實對象打交道,而是通過一個代理者與真實對象通信,代理者能夠負責真實
對象的非業務邏輯,如日誌管理、訪問控制 、異常處理等,使得真實對象專註於業務邏輯的實現,不受非業務邏輯的干擾。
代理對象會把正真的業務邏輯委托給實際對象 而代理對象只會進行一寫邊緣的附加操作 這就是aop的實現原理.
代理對象調用目標對象的方法產生的異常需要拋出去,不能處理,因為代理對象的作用是對目標對象進行增強,不會對目標對象進行改變.

靜態代理就是一個代理類根據被代理類的情況,被代理類有幾個方法,代理類就需要有幾個方法,每個方法都要對被代理類進行代理,這樣會出現代碼重覆的情況,
如多個被代理方法其實前後需要執行的邏輯是一樣的,但是靜態代理還是需要為每個方法寫一個代理方法,造成代碼重覆。動態代理根據放射得到被代理類執行的方
法和參數,避免了代碼的重覆。
靜態代理的代碼,靜態代理的弊端:代理的對象越多.
JDK實現要點:
1類:java.lang.reflect.Proxy;
2介面:InvoctionHandler;
3只能基於介面進行動態代理.
動態代理實現時,需要的介面,InvocationHandler介面。
註意:在捕獲異常之後,執行插入程式,然後還需要將異常在catch代碼塊內拋出去!

jdk運行期動態代理源碼解析:其實就是真實類實現一個介面,我們再寫一個類似於切麵的類,實現invocationhandler介面且實現invoke方法,同時要保存真實類對象,
初始化時賦值對象,invoke方法中反射方式調用真是對象方法,在方法前後可以加上定製的邏輯,這個方法其實是動態代理對象調用的,動態代理對象是客戶端通過動
態代理類實例化的,而動態代理類是真實對象方法執行前的運行期生成的.class類,這個類實現了和真實對象一樣的介面,所以也有真實對象的方法,調用代理對象方
法時也就可以傳入參數,然後代理對象再將方法和參數傳遞給invocationhandler的實例對象。

通過System.setProperties()可以設置保存jdk動態代理生成的位元組碼文件.

JDK與Cglib代理對比:
1:JDK只能針對有介面的類的介面方法進行動態代理;
2:Cglib基於繼承來實現代理,無法對static、final類進行代理;
3:Cglib基於繼承來實現代理,無法對private、static方法進行代理。

Cglib實現:
1:生成指定類對象的子類,也就是重寫類中的業務函數。
2:執行回調函數,加入intercept()函數。
3:創建這個類的子類對象。
-----------------------------------------
反射技術實現;
methodProxy.invokeSuper();
JDK通過介面代理,所以只能代理實現介面的類的方法,而cglib通過繼承實現代理,所以不能代理final類,也無法代理private和static方法.
無法對final類進行代理,因為final類不能被繼承
關於Cglib無法對static類和方法進行代理:
單一的類是沒有static修飾符的,只有靜態類內部可以用static修飾;
對於static方法,它是屬於類的,子類在不重寫的情況下,是可以調用的,但是一旦重寫了就無法調用了,普通的public方法可以通過super.method()調用,但是
static方法不行.

Spring如何創建代理bean?
JDK動態代理與Cglib代理是如何選用的?
-----------------------------
1:如果目標對象實現了介面,則預設採用JDK動態代理;
2:如果目標對象沒有實現介面,則採用Cglib進行動態代理;
3:如果目標對象實現了介面,且強制Cglib代理,則使用Cglib代理;

繼承JPARepository對數據操作實現自己的事務控制,@transactional會在子事務外層加一層事務控制,對事務整體進行控制,在方法執行前後判斷事務需要進行回滾操作。
SpringBoot對緩存的一個控制:
1、引入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2、使用註解:
@Cacheable(cacheNames={"menu"})
public List<String> getMenuList(){
System.out.println("看看是不是只有第一次被調用");
return Arrays.asList("java","C++","PHP");
}

使用SpringAop的註意事項/坑
1: 不宜把重要的業務邏輯放到aop中處理;
2: 無法攔截static,final方法,private方法;
3: 無法攔截內部方法調用.

實現AOP的方法被方法內部調用時是不會走AOP的織入邏輯的,因為內部調用AOP方法的調用對象是this,而this不是增強的代理對象,所以不會走織入代碼,解決方法
就是用ApplicationContent獲取到增強的代理對象的bean,然後用這個bean來執行AOP方法,就可以走織入的代碼邏輯了.
Spring Aop 的坑,無法攔截方法內部調用,因為內部調用是this調用的,而不是代理類調用的.
無法攔截內部調用的原因:aop通過代理實現的,而省略的this是指該對象,而不是代理後的對象
解決aop無法內部調用的問題:通過spring的ApplicationContext獲取該類的對象,就是代理對象,使用代理對象去調用內部方法.
解決方法:通過ApplicationContext來獲取代理bean,通過代理bean調用方法。

課程總結:

1.面向切麵編程是對面向對象編程的補充,主要用於日誌記錄,許可權驗證,事務配置等功能。

2.使用aspectJ實現aop,aspectJ是一個面向切麵的框架,它擴展了Java語言。

3.主要註解:

@Aspect 標註說明Java類是切麵配置的類 由@Pointcut和@Advice組成

@Pointcut 描述在哪些類的哪些方法植入代碼

@Advice表達在Pointcut表達式的什麼時間執行

4. pointcut中的通配符,運算符,指示器(通過什麼方式匹配植入的方法)

通配符:* 匹配任意數量的字元 +匹配指定類及其子類 ..一般用於匹配任意數的子包或參數

運算符:&&與操作符 || 或操作符 !非操作符

指示器:

a. @within 匹配包/類型

@Pointcut("within(com.imooc.service.ProductService")) //匹配ProductService類里的所有方法

@Pointcut("within(com.imooc..*)") //匹配com.imooc包及子包下所有類的方法

b. execution 表達式:方法的修飾符 返回值 包名.類名.方法(參數)

@Pointcut("execution(public * com.imooc.service.*Service.*(..))")//表示com.imooc.service包下以Service字元結尾的類中任意參數的所有方法

5.Advice 註明要在哪個切點執行什麼操作,有幾種方式

@Before("") //意思是在切點執行前執行

@After("") //意思是在切點執行前執行

@Around("") //表明在切點方法的前後都要執行該處理器方法

Spring事務 :
Spring事務管理介面:
PlatformTransactionManager:事務管理器
TransactionDefinition:事務定義信息(事務隔離級別、傳播行為)(隔離、傳播、超時、只讀)
TransactionStatus:事務具體運行狀態

事務管理器PlatformTransactionManager
Spring為不同的持久化框架提供了不同PlatformTransactionManager介面實現;
org.springframework.jdbc.datasource.DataSourceTransactionManager : 使用Spring JDBC或iBatis進行持久化數據時使用.
org.springframework.orm.hibernate3.HibernateTransactionManager : 使用Hibernate3.0版本進行持久化數據時使用.
org.springframework.orm.jpa.JpaTransactionManager : 使用JPA進行持久化時使用
org.springframework.jdo.JdoTransactionManager : 當持久化機制是Jdo時使用
org.springframework.transaction.jta.JtaTransactionManager : 使用一個JTA實現管理事務,在一個事務跨越多個資源時必須使用.
TransactionDefinition定義事務隔離級別
如果不考慮隔離性,會引發如下的安全問題:
1.臟讀。
一個事務讀取了另一個事務改寫但還未提交的數據,如果這些數據被回滾,則讀到的數據是無效的。
2.不可重覆讀。
在同一個事務中,多次讀取同一數據返回的結果有所不同。
3.幻讀。
一個事務讀取了幾行記錄後,另一個事務插入一些記錄,幻讀就發生了。再後來的查詢中,第一個事務就會發現有些原來沒有的記錄。


隔離級別的出現就是為瞭解決以上問題的。

資料庫提供的事務的隔離級別(四種):
1.READ_UNCOMMITED;
允許你讀取還未提交的改變了的數據,可能導致臟,幻,不可重覆讀。
2.READ_COMMINTED:
允許在併發事務已經提交後讀取,可防止臟讀,但幻讀和不可重覆讀還是有可能發生。
3.REPEATABLE_READ:
對相同欄位的多次讀取是一致的,除非數據被事務本身改變,可防止臟讀,不可重覆讀,但幻讀仍有可能出現。
4.SERILIZABLE:
完全服從ACID的隔離級別,確保不發生臟讀,幻讀,不可重覆讀,這在所有的隔離級別中是最慢的,它是典型的完全通過鎖定在事務中涉及的數據表來完成的。

除了以上的資料庫提供的事務隔離級別,spring提供了Default隔離級別,該級別表示spring使用後端資料庫預設的隔離級別。

MySQL預設事務隔離級別:REPATABLE_READ(可能出現幻讀)
Oracle預設:READ_COMMITTED(可能出現不可重覆讀和幻讀)

propagation_required:a存在事務,則b與a同一事務,如果a沒有事務,則b新起事務
propagation_supported:a存在事務,則b與a同事務,如果a沒有事務,則b也沒有事務
propagation_mondatary:a存在事務,則b與a同事務,如果a沒有事務,則拋異常
propagation_required_new:如果a存在事務,b新起事務
propagation_not_supported:如果a存在事務,b不已事務運行
propagation_never:如果出現事務,直接拋出異常
propagation_nested:a事務運行結束後,會有保存點,這邊可以自定事務,b出錯,a可以回滾或者就到a的保存點

TransactionDefinition定義事務之事務的傳播行為(002)<br>
<br>
事務的傳播行為有七種,這七種行為可以分為三類,圖中前三個分為一類(讓aaa()和bbb()操作在同一事務里),中間三個為一類(保證aaa()和bbb()操作在不同一事務里),最後為一類(aaa()執行完成後,設置一個保存點,如果bbb()發生異常,將回滾到保存點或初始狀態)。<br>
<br>
重點記住PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW, PROPAGATION_NESTED

相關代碼(公共1):
//package cn.muke.spring.demo1;
@AccountDao.java
/**
* 轉賬案例的DAO層的介面
*/
public interface AccountDao {
/**
* out :轉出賬號
* money:轉出金額
*/
public void outMoney(String out,Double money);

/**
* in :轉入賬號
* money:轉入金額
*/
public void inMoney(String in,Double money);
}

@AccountService.java
/**
* 轉賬案例的業務層介面
*/
public interface AccountService {
/**
* out :轉出賬號
* in :轉入賬號
* money:轉賬金額
*/
public void transfer(String out,String in,Double money);
}

@AccountDaoImpl.java
/**
* 轉賬案例的DAO層的實現類
*/
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
/**
* out :轉出賬號
* money:轉出金額
*/
public void outMoney(String out, Double money) {
String sql="update account set money=money-? where name=?";
this.getJdbcTemplate().update(sql,money,out);
}

/**
* in :轉入賬號
* money:轉入金額
*/
public void inMoney(String in, Double money) {
String sql="update account set money=money+? where name=?";
this.getJdbcTemplate().update(sql,money,in);
}
}
事務的傳播行為和隔離級別[transaction behavior and isolated level]
Spring中事務的定義:
一、Propagation :
  key屬性確定代理應該給哪個方法增加事務行為。這樣的屬性最重要的部份是傳播行為。有以下選項可供使用:
PROPAGATION_REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
PROPAGATION_SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。
PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。
PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則拋出異常。

很多人看到事務的傳播行為屬性都不甚瞭解,我昨晚看了j2ee without ejb的時候,看到這裡也不瞭解,甚至重新翻起資料庫系統的教材書,但是也沒有找到對這個的分析。今天搜索,找到一篇極好的分析文章,雖然這篇文章是重點分析PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRED_NESTED的
解惑 spring 嵌套事務
********TransactionDefinition 介面定義*******************

int PROPAGATION_REQUIRED = 0;


int PROPAGATION_SUPPORTS = 1;

int PROPAGATION_MANDATORY = 2;


int PROPAGATION_REQUIRES_NEW = 3;

int PROPAGATION_NOT_SUPPORTED = 4;

int PROPAGATION_NEVER = 5;

int PROPAGATION_NESTED = 6;

*************************************************************************
在這篇文章里,他用兩個嵌套的例子輔助分析,我這裡直接引用了。
********************sample***********************
ServiceA {


void methodA() {
ServiceB.methodB();
}

}

ServiceB {


void methodB() {
}

}
*************************************************
我們這裡一個個分析吧
1: PROPAGATION_REQUIRED
加入當前正要執行的事務不在另外一個事務里,那麼就起一個新的事務
比如說,ServiceB.methodB的事務級別定義為PROPAGATION_REQUIRED, 那麼由於執行ServiceA.methodA的時候,
ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB看到自己已經運行在ServiceA.methodA
的事務內部,就不再起新的事務。而假如ServiceA.methodA運行的時候發現自己沒有在事務中,他就會為自己分配一個事務。
這樣,在ServiceA.methodA或者在ServiceB.methodB內的任何地方出現異常,事務都會被回滾。即使ServiceB.methodB的事務已經被
提交,但是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾
2: PROPAGATION_SUPPORTS
如果當前在事務中,即以事務的形式運行,如果當前不再一個事務中,那麼就以非事務的形式運行
這就跟平常用的普通非事務的代碼只有一點點區別了。不理這個,因為我也沒有覺得有什麼區別
3: PROPAGATION_MANDATORY
必須在一個事務中運行。也就是說,他只能被一個父事務調用。否則,他就要拋出異常。
4: PROPAGATION_REQUIRES_NEW
這個就比較繞口了。 比如我們設計ServiceA.methodA的事務級別為PROPAGATION_REQUIRED,ServiceB.methodB的事務級別為PROPAGATION_REQUIRES_NEW,
那麼當執行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成以後,
他才繼續執行。他與PROPAGATION_REQUIRED 的事務區別在於事務的回滾程度了。因為ServiceB.methodB是新起一個事務,那麼就是存在
兩個不同的事務。如果ServiceB.methodB已經提交,那麼ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。如果ServiceB.methodB失敗回滾,
如果他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。
5: PROPAGATION_NOT_SUPPORTED
當前不支持事務。比如ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,
那麼當執行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態運行完,再繼續ServiceA.methodA的事務。
6: PROPAGATION_NEVER
不能在事務中運行。假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,
那麼ServiceB.methodB就要拋出異常了。
7: PROPAGATION_NESTED
理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,
而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最後回滾,他也要回滾的。
而Nested事務的好處是他有一個savepoint。
*****************************************
ServiceA {


void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED 級別
} catch (SomeException) {
// 執行其他業務, 如 ServiceC.methodC();
}
}

}
********************************************
也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如
ServiceC.methodC,繼續執行,來嘗試完成自己的事務。
但是這個事務並沒有在EJB標準中定義。

二、Isolation Level(事務隔離等級):
1、Serializable:最嚴格的級別,事務串列執行,資源消耗最大;

2、REPEATABLE READ:保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的數據。避免了“臟讀取”和“不可重覆讀取”的情況,但是帶來了更多的性能損失。

3、READ COMMITTED:大多數主流資料庫的預設事務等級,保證了一個事務不會讀到另一個並行事務已修改但未提交的數據,避免了“臟讀取”。該級別適用於大多數系統。

4、Read Uncommitted:保證了讀取過程中不會讀取到非法數據。
隔離級別在於處理多事務的併發問題。
我們知道並行可以提高資料庫的吞吐量和效率,但是並不是所有的併發事務都可以併發運行,這需要查看資料庫教材的可串列化條件判斷了。
這裡就不闡述。
我們首先說併發中可能發生的3中不討人喜歡的事情
1: Dirty reads--讀臟數據。也就是說,比如事務A的未提交(還依然緩存)的數據被事務B讀走,如果事務A失敗回滾,會導致事務B所讀取的的數據是錯誤的。

2: non-repeatable reads--數據不可重覆讀。比如事務A中兩處讀取數據-total-的值。在第一讀的時候,total是100,然後事務B就把total的數據改成200,事務A再讀一次,結果就發現,total竟然就變成200了,造成事務A數據混亂。

3: phantom reads--幻象讀數據,這個和non-repeatable reads相似,也是同一個事務中多次讀不一致的問題。但是non-repeatable reads的不一致是因為他所要取的數據集被改變了(比如total的數據),但是phantom reads所要讀的數據的不一致卻不是他所要讀的數據集改變,而是他的條件數據集改變。比如Select account.id where account.name="ppgogo*",第一次讀去了6個符合條件的id,第二次讀取的時候,由於事務b把一個帳號的名字由"dd"改成"ppgogo1",結果取出來了7個數據。
Dirty reads non-repeatable reads phantom reads
Serializable 不會 不會 不會
REPEATABLE READ 不會 不會 會
READ COMMITTED 不會 會 會
Read Uncommitted 會 會 會

三、readOnly
事務屬性中的readOnly標誌表示對應的事務應該被最優化為只讀事務。這是一個最優化提示。在一些情況下,一些事務策略能夠起到顯著的最優化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)時避免dirty checking(試圖“刷新”)。
四、Timeout
在事務屬性中還有定義“timeout”值的選項,指定事務超時為幾秒。在JTA中,這將被簡單地傳遞到J2EE伺服器的事務協調程式,並據此得到相應的解釋。

事務的API介紹

一、簡介
PlatformTransactionManager - 平臺事務管理器,真正用來管理事務的介面,包含事務的提交,回滾等信息
TransactionDefinition - 事務定義信息(隔離級別、傳播行為、是否超時、設置只讀)
TransactionStatus - 事務具體的運行狀態(是否已經提交,是否有保存點,是不是一個新的事務等等這些狀態)

關係:
首先會根據TransactionDefinition事務定義的信息(比如定義了什麼樣的隔離級別,定義什麼樣的傳播行為),由PlatformTransactionManager對事務進行管理,進行事務管理的過程中,事務會產生一些相應的狀態,這些狀態在TransactionStatus中

二、PlatformTransactionManager 介面
1. DataSourceTransactionManager
使用Spring JDBC 或iBatis進行持久化數據時使用
2. HibernateTransactionManager
使用Hibernate3.0版本進行持久化數據時使用

三、TransactionDefinition
1.事務隔離級別
解決臟讀、不可重覆讀、幻讀等安全問題

事務隔離級別(四種):
DEFAULT
READ_UNCOMMITED
READ_COMMITED
REPEATABLE_READ
SERIALIZABLE

2.事務的傳播行為
解決業務層的方法之間的相互調用的問題(在調用方法的過程中,事務是如何傳遞的)

事務的傳播行為有七種,又分為三類:
第一類共同點:A和B方法在同一個事務中。
*PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS
PROPAGATION_MANDATORY

第二類共同點:A 方法和 B 方法不在同一個事務裡面。
*PROPAGATION_REQUIRES_NEW
PROPAGATION_NOT_SUPPORTED
PROPAGATION_NEVER

第三類:如果 A 方法有的事務執行完,設置一個保存點,如果 B 方法中事務執行失敗,可以滾回保存點或初始狀態。
*PROPAGATION_NESTED

四、TransactionStatus

TransactionStatus介面用來記錄事務的狀態

該介面定義了一組方法,用來獲取或判斷事務的相應狀態信息.

平臺事務管理器(PlatformTransactionManager)會根據TransactionDefinition中定義的事務信息(包括隔離級別、傳播行為)來進行事務的管理,在管理的過程中事務可能
產生了保存點或事務是新的事務等情況,那麼這些信息都會記錄在TransactionStatus的對象中.
TransactionStatus記錄事務的狀態信息(刷新、是否有保存點、是否完成、是否是一個新事務、是否只回滾、設置只回滾)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天我們將利用vue的條件指令來完成一個簡易的動態變色功能按鈕 首先我們還是要對vue進行配置,在上篇隨筆中有相關下載教學. 然後我們要在html頁面上搭建三個簡易的按鈕,顏色分別為紫,綠和藍(顏色隨意)其代碼如下: 這裡的@是v-on事件指令,在這裡要在三個按鈕上設置點擊事件 接著我們要進行條件指 ...
  • nodejs版本:v10.14.2 1.首先準備一個簡單的html頁面 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>nodejs顯示html</title> 6 </head> 7 < ...
  • 典型的一個Web應用的生命周期從用戶在瀏覽器輸入一串URL,或者單擊一個鏈接開始(就是訪問一個頁面)。而這個生命周期的結束就是我們關閉這個頁面。 響應流程: 例子(本例來自《javascript:忍者秘籍》) HTML: javascript: ...
  • 1、viewer.js 使用 Demo http://fengyuanchen.github.io/viewerjs/ 2、viewer.js 下載地址 https://github.com/fengyuanchen/viewerjs 3、viewer只能初始化一次,也就是說如果用ajax添加了新的 ...
  • ...
  • 1 2 3 4 5 6 前端壓縮上傳圖片 7 8 9 10 11 12 13 121 122 123 ...
  • 廢話不多說,直接上源碼 ...
  • 文章首發: "結構型模式:代理模式" 七大結構型模式之七:代理模式。 簡介 姓名 :代理模式 英文名 :Proxy Pattern 價值觀 :為生活加點料 個人介紹 : Provide a surrogate or placeholder for another object to control ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...