最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring事務(wù)相關(guān)問(wèn)題解決方案

 更新時(shí)間:2020年02月27日 11:49:52   作者:min.jiang  
這篇文章主要介紹了Spring事務(wù)相關(guān)問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

有些spring相關(guān)的知識(shí)點(diǎn)之前一直沒(méi)有仔細(xì)研究:比如spring的事務(wù),并不是沒(méi)有使用,也曾經(jīng)簡(jiǎn)單的在某些需要事務(wù)處理的方法上通過(guò)增加事務(wù)注解來(lái)實(shí)現(xiàn)事務(wù)功能,僅僅是跟隨使用(甚至并未測(cè)試過(guò)事務(wù)的正確性),至于如何在項(xiàng)目中配置事務(wù),如何才能將事務(wù)寫(xiě)正確,事務(wù)的其它的一些原理性的東西從未花時(shí)間研究。最近同事正好拋出了一個(gè)問(wèn)題,借此機(jī)會(huì)學(xué)習(xí)了一遍。

問(wèn)題一:增加了readOnly=true的事務(wù)中包含寫(xiě)操作,為什么線上運(yùn)行這段代碼是正常的呢?

@Transactional(readOnly = true)
  public Integer getUID(String key, String type) {
    keyGeneratorDao.insert(key, type);
    keyGeneratorDao.update(key, type);
    return keyGeneratorDao.select(key, type);
  }

我為什么對(duì)這個(gè)問(wèn)題感興趣?

不懂這個(gè)readOnly參數(shù)的含義,之前寫(xiě)@Transactional的注解,那都是使用的默認(rèn)值,不帶顯示參數(shù)。提出配置了readOnly參數(shù)后,理論上應(yīng)該程序報(bào)錯(cuò)而實(shí)際上沒(méi)有報(bào)錯(cuò),想搞清楚為什么。

開(kāi)始寫(xiě)單元測(cè)試:

在單元測(cè)試類中寫(xiě)事務(wù)函數(shù)以及測(cè)試方法

@Autowired
  private IkeyGeneratorDao keyGeneratorDao;

  @Transactional(readOnly=true)
  public Integer getId(String key, String type){
    return keyGeneratorDao.select(key, type);
  }
  @Transactional
  public Integer getUID(String key, String type) {
    keyGeneratorDao.insert(key, type);
    keyGeneratorDao.update(key, type);
    return this.getId(key,type);
  }
  @Test
  public void testCreateGuid(){
    int guid=this.getUID("12345", "jim");
    System.out.println(guid);
  }

測(cè)試結(jié)果顯示正常,與上面提到的不允許進(jìn)行寫(xiě)操作的觀點(diǎn)相反,于是想起典型的事務(wù)生效問(wèn)題。

挖的第一個(gè)坑:如果事務(wù)采用的是cglib動(dòng)態(tài)代理,調(diào)用的方法與事務(wù)方法處在同一個(gè)類中事務(wù)不生效。

將兩個(gè)事務(wù)事務(wù)轉(zhuǎn)移到單獨(dú)的類中,然后測(cè)試,類代碼省略,只是將上面兩個(gè)標(biāo)記了@Transactional的方法封裝在一個(gè)單獨(dú)的類中。

@Autowired
  private KeyGeneratorService keyService;

  @Test
  public void testCreateGuid2(){
    int guid=this.keyService.getUID("12345", "jim");
    System.out.println(guid);
  }

測(cè)試結(jié)果顯示也是正常,于是想確認(rèn)下事務(wù)到底是否生效,加入異常以測(cè)試數(shù)據(jù)是否回滾,修改代碼如下:

@Transactional
  public Integer getUID3(String key, String type) {
    keyGeneratorDao.insert(key, type);
    Integer.parseInt("aaa");//throw exception
    keyGeneratorDao.update(key, type);
}

測(cè)試結(jié)果顯示事務(wù)回滾正常,可以排除事務(wù)環(huán)境配置問(wèn)題。

挖的第二個(gè)坑:做測(cè)試一定要與原問(wèn)題代碼盡量保持一致,否則會(huì)產(chǎn)生其它的不明原因影響判斷。通過(guò)對(duì)比原問(wèn)題的代碼發(fā)現(xiàn)我寫(xiě)的測(cè)試代碼與問(wèn)題代碼有區(qū)別,readOnly是加在包含有寫(xiě)操作的方法上,而我的是兩個(gè)方法,只有在讀的方法上增加了readOnly,于時(shí)再次修改代碼:

@Transactional(readOnly = true)
  public Integer getUID4(String key, String type) {
    keyGeneratorDao.insert(key, type);
    keyGeneratorDao.update(key, type);
    return keyGeneratorDao.select(key, type);
  }

測(cè)試結(jié)果顯示運(yùn)行不正常,提示如下錯(cuò)誤:Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed,到這的確說(shuō)明在在加了readOnly=true的事務(wù)內(nèi)是不允許寫(xiě)入操作的。為什么這段代碼在線上運(yùn)行是成功的呢,于時(shí)查看前端的調(diào)用,發(fā)現(xiàn)前端調(diào)用的并不是直接標(biāo)識(shí)了Transactional的方法,而是根據(jù)不同的具體業(yè)務(wù)重新包裝的方法,比如我們需要生成訂單的編號(hào),前端只調(diào)用genOrderCode而不調(diào)用getUID。

非事務(wù)方法在內(nèi)部調(diào)用了本類事務(wù)方法,然后非事務(wù)方法被外部調(diào)用ServicegenOrderCode,是一個(gè)非事務(wù)方法,內(nèi)部調(diào)用了getUIDgetUID,是一個(gè)事務(wù)方法

@Autowired
  private IkeyGeneratorDao keyGeneratorDao;

  @Transactional(readOnly = true)
  public Integer getUID(String key, String type) {
    keyGeneratorDao.insert(key, type);
    keyGeneratorDao.update(key, type);
    return keyGeneratorDao.select(key, type);
  }

  public String genOrderCode(Date orderDate)
  {
    SimpleDateFormat df = new SimpleDateFormat("yyMMddHH");
    String ticketDate = df.format(orderDate);
    Integer uid = getUID(ticketDate, ORDER_CODE);    

    return ticketDate + genRandom2(uid.toString(), 3, 3) ;
  }

Test,外部類調(diào)用非事務(wù)方法

  @Test
  public void testCreateGuid3(){
    String guid=this.keyService.genOrderCode(new Date());
    System.out.println(guid);
  }

測(cè)試結(jié)果居然是正常的,這與線上運(yùn)行的結(jié)果相同,后面經(jīng)同事提醒,這又是一個(gè)不正確使用事務(wù)的案例。

挖的第三個(gè)坑:當(dāng)調(diào)用一個(gè)類的非事務(wù)方法且這個(gè)非事務(wù)方法內(nèi)部調(diào)用了本類自身的事務(wù)方法,那么事務(wù)也不會(huì)生效。

問(wèn)題二:下面的代碼可以實(shí)現(xiàn)事務(wù)回滾嗎?

Service

  • genOrderCode方法調(diào)用
  • getUID2兩個(gè)方法都是具備相同的事務(wù)參數(shù)
  • getUID2拋出異常
  • genOrderCode捕獲這個(gè)異常
@Transactional
  public Integer getUID2(String key, String type) {
    keyGeneratorDao.insert(key, type);
    Integer.parseInt("aaa");//throw exception
    keyGeneratorDao.update(key, type);
    return keyGeneratorDao.select(key, type);
  }

  @Transactional
  public String genOrderCode(Date orderDate)
  {
    try{
      SimpleDateFormat df = new SimpleDateFormat("yyMMddHH");
      String ticketDate = df.format(orderDate);
      Integer uid = getUID2(ticketDate, ORDER_CODE);    

      return ticketDate + genRandom2(uid.toString(), 3, 3) ;
    }catch(Exception ex){
      System.out.println(ex);
    }
    return null;
  }

Test

  @Test
  public void testCreateGuid3(){
    String guid=this.keyService.genOrderCode(new Date());
    System.out.println(guid);
  }

執(zhí)行測(cè)試代碼,發(fā)現(xiàn)可以成功提交,但數(shù)據(jù)是不完整的,因?yàn)楦虏僮鳑](méi)有完成。為什么會(huì)是這樣的呢?因?yàn)槟J(rèn)的Propagation.REQUIRED指明多個(gè)操作處于一個(gè)事務(wù)中,由于genOrderCode有異常處理,所以即使getUID2中發(fā)生異常,系統(tǒng)也會(huì)認(rèn)定提交是合法的,因此會(huì)出現(xiàn)插入操作正常更新不正常但事務(wù)正常提交并不回滾的情況。
如果顯示指定Propagation.REQUIRES_NEW呢?

@Transactional(propagation=Propagation.REQUIRES_NEW)
  public Integer getUID2(String key, String type) {
    keyGeneratorDao.insert(key, type);
    Integer.parseInt("aaa");//throw exception
    keyGeneratorDao.update(key, type);
    return keyGeneratorDao.select(key, type);
  }

再執(zhí)行相同的測(cè)試,數(shù)據(jù)正?;貪L,這里提供兩張圖,可以看的清楚些(因?yàn)槌S玫木瓦@兩種,其它的有興趣可以多多研究)

REQUIRED

REQUIRES_NEW

通過(guò)事務(wù)的兩個(gè)小問(wèn)題,總結(jié)出解決問(wèn)題的一些小技巧或者叫經(jīng)驗(yàn):發(fā)現(xiàn)問(wèn)題之后,不要局限于某個(gè)點(diǎn),最好根據(jù)上下文來(lái)結(jié)合分析,比如問(wèn)題一的readonly可寫(xiě)入,單看那段代碼很難找出合理的解釋,只有結(jié)合前后端調(diào)用才能找出根本原因。寫(xiě)單元測(cè)試盡量寫(xiě)相同的代碼,否則有可能會(huì)出現(xiàn)一些干擾項(xiàng)影響判斷。學(xué)習(xí)呢,有時(shí)間盡量學(xué)的全點(diǎn),比如@Transactional這個(gè)注解,除了readOnly還有Propagation等等。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java多線程案例之阻塞隊(duì)列詳解

    Java多線程案例之阻塞隊(duì)列詳解

    阻塞隊(duì)列是一種特殊的隊(duì)列.?也遵守?“先進(jìn)先出”?的原則.阻塞隊(duì)列能是一種線程安全的數(shù)據(jù)結(jié)構(gòu)。本文將通過(guò)一些示例為大家詳細(xì)講講阻塞隊(duì)列的原理與使用,感興趣的小伙伴可以學(xué)習(xí)一下
    2022-10-10
  • Java實(shí)現(xiàn)AES加密和解密方式完整示例

    Java實(shí)現(xiàn)AES加密和解密方式完整示例

    這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)AES加密和解密方式的相關(guān)資料,AES加密為最常見(jiàn)的對(duì)稱加密算法,是一種區(qū)塊加密標(biāo)準(zhǔn),這個(gè)標(biāo)準(zhǔn)用來(lái)替代原先的DES,已經(jīng)被多方分析且廣為全世界所使用,需要的朋友可以參考下
    2023-10-10
  • Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的酒店前臺(tái)管理小功能(實(shí)例代碼)

    Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的酒店前臺(tái)管理小功能(實(shí)例代碼)

    這篇文章主要介紹了Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的酒店前臺(tái)管理小功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • 詳解JAVA設(shè)計(jì)模式之代理模式

    詳解JAVA設(shè)計(jì)模式之代理模式

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之代理模式的的相關(guān)資料,文中代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • Spring中bean集合注入的方法詳解

    Spring中bean集合注入的方法詳解

    Spring作為項(xiàng)目中不可缺少的底層框架,提供的最基礎(chǔ)的功能就是bean的管理了。bean的注入相信大家都比較熟悉了,但是有幾種不太常用到的集合注入方式,可能有的同學(xué)會(huì)不太了解,今天我們就通過(guò)實(shí)例看看它的使用
    2022-07-07
  • Java實(shí)現(xiàn)數(shù)據(jù)連接池Druid舉例

    Java實(shí)現(xiàn)數(shù)據(jù)連接池Druid舉例

    本文主要介紹了Java實(shí)現(xiàn)數(shù)據(jù)連接池Druid舉例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • java正則表達(dá)式精確查找和替換指定字符代碼示例

    java正則表達(dá)式精確查找和替換指定字符代碼示例

    這篇文章主要給大家介紹了關(guān)于java正則表達(dá)式精確查找和替換指定字符的相關(guān)資料,java正則表達(dá)式是一種用于匹配、查找和替換文本的強(qiáng)大工具,它可以用于驗(yàn)證輸入是否符合特定的格式、從文本中提取信息、以及將文本中的某些內(nèi)容替換成其他內(nèi)容,需要的朋友可以參考下
    2024-04-04
  • Java 二分查找算法的實(shí)現(xiàn)

    Java 二分查找算法的實(shí)現(xiàn)

    這篇文章主要介紹了Java 如何實(shí)現(xiàn)二分查找算法,幫助大家更好的理解和學(xué)習(xí)Java 算法,感興趣的朋友可以了解下
    2020-09-09
  • 搭建SpringBoot項(xiàng)目三種方式(圖文教程)

    搭建SpringBoot項(xiàng)目三種方式(圖文教程)

    Springboot作為當(dāng)下最主流的java開(kāi)發(fā)框架,已成為IT從業(yè)人員的入門(mén)必備技能,本文主要介紹了搭建SpringBoot項(xiàng)目三種方式,感興趣的可以了解一下
    2023-09-09
  • 關(guān)于SpringBoot中controller參數(shù)校驗(yàn)的使用

    關(guān)于SpringBoot中controller參數(shù)校驗(yàn)的使用

    本文主要介紹了關(guān)于SpringBoot中controller參數(shù)校驗(yàn)的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01

最新評(píng)論

安溪县| 福安市| 高雄市| 普宁市| 东港市| 邵东县| 铜鼓县| 奎屯市| 即墨市| 绥滨县| 汕尾市| 新源县| 贵港市| 聂拉木县| 夏邑县| 蒙自县| 白城市| 新干县| 凤冈县| 彝良县| 台东县| 论坛| 太仆寺旗| 诏安县| 怀来县| 长海县| 连南| 遵化市| 富平县| 轮台县| 威信县| 交口县| 望谟县| 红安县| 依兰县| 三明市| 平谷区| 深州市| 奇台县| 阿拉尔市| 比如县|