久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    Spring 事務原理和使用

     萬皇之皇 2018-07-02

    作者:郭松

    來自:

    http://tech./2017/02/06/rd/server/SpringTransactional/


    1.Spring@Transactional的配置

    步驟一、在Spring配置文件中引入命名空間

    步驟二、xml配置文件中,添加事務管理器bean配置

                         

    步驟三、在使用事務的方法或者類上添加下面的注解

    @Transactional(“pkgouTransactionManager”)


    2.傳播行為和隔離級別

    1> 事務注解方式: @Transactional

    • 標注在類前:標示類中所有方法都進行事務處理

    • 標注在接口、實現類的方法前:標示方法進行事務處理

    2> 事務傳播行為介紹:

    3> 事務超時設置:

    @Transactional(timeout=30) //默認是30秒

    4> 事務隔離級別:

    • 臟讀 : 一個事務讀取到另一事務未提交的更新數據

    • 不可重復讀 : 在同一事務中, 多次讀取同一數據返回的結果有所不同, 換句話說, 后續讀取可以讀到另一事務已提交的更新數據。相反,”可重復讀”在同一事務中多次讀取數據時,能夠保證所讀數據一樣,也就是后續讀取不能讀到另一事務已提交的更新數據

    • 幻讀 : 一個事務讀到另一個事務已提交的insert數據

    @Transactional的屬性:

    3.工作原理
    自動提交

    默認情況下,數據庫處于自動提交模式。每一條語句處于一個單獨的事務中,在這條語句執行完畢時,如果執行成功則隱式的提交事務,如果執行失敗則隱式的回滾事務。 事務管理,是一組相關的操作處于一個事務之中,因此必須關閉數據庫的自動提交模式。這點,Spring會在org/springframework/jdbc/datasource/DataSourceTransactionManager.java中將底層連接的自動提交特性設置為false。

    // switch to manual commit if necessary。 this is very expensive in some jdbc drivers,// so we don't want to do it unnecessarily (for example if we've explicitly// configured the connection pool to set it already)。if (con。getautocommit()) {    txobject.setmustrestoreautocommit(true);    if (logger.isdebugenabled())     {        logger.debug('switching jdbc connection [' + con + '] to manual commit');     }     //首先將自動提交屬性改為false     con.setautocommit(false);}
    spring事務回滾規則

    Spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內拋出異常。Spring事務管理器會捕捉任何未處理的異常,然后依據規則決定是否回滾拋出異常的事務。 默認配置下,Spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾)。而拋出checked異常則不會導致事務回滾。 Spring也支持明確的配置在拋出哪些異常時回滾事務,包括checked異常。也可以明確定義哪些異常拋出時不回滾事務。 還可以編程性的通過setRollbackOnly()方法來指示一個事務必須回滾,在調用完setRollbackOnly()后你所能執行的唯一操作就是回滾。

    4.注意事項

    由于Spring事務管理是基于接口代理或動態字節碼技術,通過AOP實施事務增強的。

    (1)對于基于接口動態代理的AOP事務增強來說,由于接口的方法是public的,這就要求實現類的實現方法必須是public的(不能是protected,private等),同時不能使用static的修飾符。所以,可以實施接口動態代理的方法只能是使用“public” 或 “public final”修飾符的方法,其它方法不可能被動態代理,相應的也就不能實施AOP增強,也即不能進行Spring事務增強。

    (2)基于CGLib字節碼動態代理的方案是通過擴展被增強類,動態創建子類的方式進行AOP增強植入的。由于使用final,static,private修飾符的方法都不能被子類覆蓋,相應的,這些方法將不能被實施的AOP增強。

    所以,必須特別注意這些修飾符的使用,@Transactional 注解只被應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯,但是這個被注解的方法將不會展示已配置的事務設置。

    用 spring 事務管理器,由spring來負責數據庫的打開,提交,回滾。默認遇到運行期異常(throw new RuntimeException(“注釋”);)會回滾,即遇到不受檢查(unchecked)的異常時回滾;

    @Transactional(rollbackFor=Exception.class) //指定回滾,遇到異常Exception時回滾public void methodName() {throw new Exception('注釋');}

    而遇到需要捕獲的異常(throw new Exception(“注釋”);)不會回滾,即遇到受檢查的異常(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查異常或說受檢查異常)時,需我們指定方式來讓事務回滾 要想所有異常都回滾,要加上 @Transactional(rollbackFor={Exception。class,其它異常}) 。如果讓unchecked異常不回滾:@Transactional(notRollbackFor=RunTimeException.class)如下:

    @Transactional(noRollbackFor=Exception.class)//指定不回滾,遇到運行期異常(throw new RuntimeException('注釋');)會回滾public ItimDaoImpl getItemDaoImpl() {throw new RuntimeException('注釋');}

    僅僅 @Transactional注解的出現不足于開啟事務行為,它僅僅是一種元數據,能夠被可以識別 @Transactional注解和上述的配置適當的具有事務行為的beans所使用。其實,根本上是 元素的出現 開啟了事務行為。

    Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現的任何接口上。你當然可以在接口上使用 @Transactional 注解,但是這將只能當你設置了基于接口的代理時它才生效。因為注解是不能繼承的,這就意味著如果你正在使用基于類的代理時,那么事務的設置將不能被基于類的代理所識別,而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。因此,請接受Spring團隊的建議并且在具體的類火方法上使用 @Transactional 注解。

    @Transactional 注解標識的方法,處理過程盡量的簡單。尤其是帶鎖的事務方法,能不放在事務里面的最好不要放在事務里面。可以將常規的數據庫查詢操作放在事務前面進行,而事務內進行增、刪、改、加鎖查詢等操作。

    @Transactional 注解的默認事務管理器bean是“transactionManager”,如果聲明為其他名稱的事務管理器,需要在方法上添加@Transational(“managerName”)。

    @Transactional 注解標注的方法中不要出現網絡調用、比較耗時的處理程序,因為,事務中數據庫連接是不會釋放的,如果每個事務的處理時間都非常長,那么寶貴的數據庫連接資源將很快被耗盡。

    5.自我調用中的問題 

    Spring事務使用AOP代理后的方法調用執行流程,如圖所示:

    從圖中可以看出,調用事務時首先調用的是AOP代理對象而不是目標對象,首先執行事務切面,事務切面內部通過TransactionInterceptor環繞增強進行事務的增強。即進入目標方法之前開啟事務,退出目標方法時提交/回滾事務。

    這樣在自我調用時,則會出現無法開啟事務的問題,比如:

    public interface TargetService {      public void a();      public void b();  }  @Service public class TargetServiceImpl implements TargetService{      public void a()     {      this.b();      }      @Transactional(propagation = Propagation.REQUIRES_NEW)      public void b()     {    //執行數據庫操作    }  }

    此處的this指向目標對象,因此調用this.b()將不會執行b事務切面,即不會執行事務增強,因此b方法的事務定義“@Transactional(propagation = Propagation.REQUIRES_NEW)”將不會實施,即結果是b和a方法的事務是方法的事務定義是一樣的。

    解決方法 通過BeanPostProcessor 在目標對象中注入代理對象:

    一、定義BeanPostProcessor 需要使用的標識接口

    public interface BeanSelfAware{    public abstract void setSelf(Object obj);}

    二、定義自己的BeanPostProcessor(InjectBeanSelfProcessor)

    public class InjectBeanSelfProcessor    implements BeanPostProcessor, ApplicationContextAware{    ApplicationContext context;private static Log log = LogFactory.getLog(com/netease/lottery/base/common/BeanSelf/InjectBeanSelfProcessor);public InjectBeanSelfProcessor(){}public void setApplicationContext(ApplicationContext context)    throws BeansException{    this.context = context;}public Object postProcessAfterInitialization(Object bean, String beanName)    throws BeansException{    if(bean instanceof BeanSelfAware)    {//如果Bean實現了BeanSelfAware標識接口,就將代理對象注入        BeanSelfAware myBean = (BeanSelfAware)bean;        Class cls = bean.getClass();        if(!AopUtils.isAopProxy(bean))        {            Class c = bean.getClass();            Service serviceAnnotation = (Service)c.getAnnotation(org/springframework/stereotype/Service);            if(serviceAnnotation != null)                try                {                    bean = context.getBean(beanName);                    if(AopUtils.isAopProxy(bean));                }                catch(BeanCurrentlyInCreationException beancurrentlyincreationexception) { }                catch(Exception ex)                {                    log.fatal((new StringBuilder()).append('No Proxy Bean for service ').append(bean.getClass()).append(' ').append(ex.getMessage()).toString(), ex);                }        }        myBean.setSelf(bean);        return myBean;    } else    {        return bean;    }}public Object postProcessBeforeInitialization(Object bean, String beanName)    throws BeansException{    return bean;}

    三、目標類實現

    public interface TargetService {  public void a();  public void b();  }  @Service public class TargetServiceImpl implements TargetService,BeanSelfAware{  private TargetService self;  public void setSelf(Object proxyBean) { //通過InjectBeanSelfProcessor注入自己(目標對象)的AOP代理對象      this.self = (TargetService) proxyBean;  }  public void a() {      self.b();  }  @Transactional(propagation = Propagation.REQUIRES_NEW)  public void b() {//執行數據庫操作}  }

    postProcessAfterInitialization根據目標對象是否實現BeanSelfAware標識接口,通過setSelf(bean)將代理對象(bean)注入到目標對象中,從而可以完成目標對象內部的自我調用。


    轉發是對作者最大的支持!!!


      本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發現有害或侵權內容,請點擊一鍵舉報。
      轉藏 分享 獻花(0

      0條評論

      發表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 国语精品自产拍在线观看网站| 丰满爆乳一区二区三区| 天堂mv在线mv免费mv香蕉| 在线看无码的免费网站| V一区无码内射国产| 久久蜜臀av一区三区| 亚洲AV无码乱码在线观看性色扶| 少妇精品无码一区二区三区| 亚洲AVAV天堂AV在线网阿V| 呦系列视频一区二区三区| 18禁无遮挡啪啪无码网站破解版| 国产AV无码专区亚洲AWWW| 日韩中文字幕人妻一区| 精品无码一区二区三区亚洲桃色| 漂亮人妻中文字幕丝袜| 男女无遮挡XX00动态图120秒| 国产美女被遭强高潮免费一视频 | 无码人妻精品一区二区三区下载| 亚洲人亚洲人成电影网站色| 插插无码视频大全不卡网站| 免费久久人人爽人人爽AV| 亚洲另类精品无码专区 | 午夜成人性爽爽免费视频| 暖暖 在线 日本 免费 中文| 无码AV免费永久免费永久专区 | 亚洲欧美中文日韩V在线观看 | 在线看片免费人成视频电影| 国产成人精品亚洲日本在线观看| 精品人妻av区乱码| 欧乱色国产精品兔费视频| 亚洲人成网站77777在线观看| 无码人妻一区二区三区精品视频 | 国产破外女出血视频| 尹人香蕉久久99天天拍| 国产亚洲精品AA片在线播放天| 伊人无码一区二区三区| 国产精品自在自线视频| 久久国产免费观看精品3| 色8久久人人97超碰香蕉987| 精品免费看国产一区二区| 日本精品一区二区不卡|