溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何解決Spring事務(wù)管理配置文件問(wèn)題

發(fā)布時(shí)間:2020-07-23 11:20:12 來(lái)源:億速云 閱讀:172 作者:小豬 欄目:編程語(yǔ)言

這篇文章主要為大家展示了如何解決Spring事務(wù)管理配置文件問(wèn)題,內(nèi)容簡(jiǎn)而易懂,希望大家可以學(xué)習(xí)一下,學(xué)習(xí)完之后肯定會(huì)有收獲的,下面讓小編帶大家一起來(lái)看看吧。

在開(kāi)發(fā)中,遇到了sql語(yǔ)句報(bào)錯(cuò),但是并沒(méi)有回滾的情況。

經(jīng)過(guò)幾天的排查,終于找到了事務(wù)沒(méi)有回滾的原因。

原來(lái)的項(xiàng)目用的是informix的數(shù)據(jù)庫(kù),原來(lái)針對(duì)事務(wù)回滾的機(jī)制都是好用的。我本地用的是mysql數(shù)據(jù)庫(kù)。

先將程序代碼與spring-mybatis.xml配置文件拿過(guò)來(lái):

1、程序代碼:

這個(gè)問(wèn)題是在驗(yàn)證增刪改查返回值時(shí)發(fā)現(xiàn)的。

兩個(gè)操作,刪除時(shí),因?yàn)殛P(guān)聯(lián)了外鍵,所以會(huì)報(bào)錯(cuò),此時(shí)正常情況更新的語(yǔ)句也會(huì)回滾,但是并沒(méi)有。

/**
   *@Author: Administrator on 2020/3/12 15:15
   *@param:
   *@return:
   *@Description:查詢同步情況
   */
  @Override
  public PageInfo getSyncstatusPages(Syncstatus vo, int pageNo, int pageSize) {
    PageHelper.startPage(pageNo, pageSize);


    /* //查看增刪改查的返回值
    //1新增:返回值自己定義,可以是void,int
    //1-1新增一條數(shù)據(jù):插入成功,返回值為1
    int insert_success1 = yylfHttpServletMapper.insert("8", "2", "1");
    //1-2新增多條數(shù)據(jù):插入成功,返回值為插入的數(shù)據(jù)條數(shù),當(dāng)有一條數(shù)據(jù)錯(cuò)誤時(shí),所有數(shù)據(jù)都會(huì)插入失敗
    int insert_success2 = yylfHttpServletMapper.insert_duotiao("7");
    String insert_success3 = yylfHttpServletMapper.insert_duotiao_String("7");//不支持返回值為String類型
    //1-3新增一條數(shù)據(jù):插入失?。褐麈I沖突,會(huì)直接報(bào)異常
    int insert_failed = yylfHttpServletMapper.insert("1", "2", "1");
    //1-4插入null:屬性為null,如果表中所有字段允許為null,插入一條所有值均為null的數(shù)據(jù)
    Syncstatus syncstatus1 = null;
    yylfHttpServletMapper.insertSyncstatus(syncstatus1);
    //1-5插入一個(gè)沒(méi)有賦值的對(duì)象:屬性為null,如果表中所有字段允許為null,插入一條所有值均為null的數(shù)據(jù)
    Syncstatus syncstatus2 = new Syncstatus();
    yylfHttpServletMapper.insertSyncstatus(syncstatus2);*/


    /*//2刪除:返回值自己定義,可以是void,int
    //2-1刪除成功:沒(méi)有數(shù)據(jù):返回值為0
    int delete_success1 = yylfHttpServletMapper.delete("0");
    //2-2刪除成功:有多條數(shù)據(jù):返回值為刪除的數(shù)據(jù)條數(shù)
    int delete_success2 = yylfHttpServletMapper.delete_systemcode("2");*/
    //2-3刪除失?。豪缬型怄I:報(bào)異常


    //3更新:返回值自己定義,可以是void,int
    //3-1更新成功:沒(méi)有數(shù)據(jù),返回值為0
    //int update_no = yylfHttpServletMapper.update_no("0");
    //3-2更新成功:有多條數(shù)據(jù),返回更新的數(shù)據(jù)條數(shù)
    int update_duotiao = yylfHttpServletMapper.update_duotiao_systemcode("2");
    int delete_fail = yylfHttpServletMapper.delete("1");
    //3-3更新失?。豪缬型怄I,報(bào)異常
    //int update_fail = yylfHttpServletMapper.update_fail("1");

    //4查詢
    //4-1 沒(méi)數(shù):String 類型返回null
    //Object object = yylfHttpServletMapper.select("0");
    //4-1 沒(méi)數(shù):集合 類型返回[]空集合
    //Syncstatus syncstatus3 = new Syncstatus();
    //syncstatus3.setStatus("7");
    //List<Syncstatus> page0 = yylfHttpServletMapper.getSyncstatusList(syncstatus3);
    //4-1 沒(méi)數(shù):int 類型返回null,如果定義為int會(huì)報(bào)錯(cuò)。因?yàn)闆](méi)數(shù)時(shí)返回null,可以將返回類型改為String
    //String i = yylfHttpServletMapper.select_int(0);
    //4-1:當(dāng)返回值為對(duì)象時(shí),若返回值為空,則返回null
    //4-2 有數(shù)
    List<Syncstatus> pages = yylfHttpServletMapper.getSyncstatusList(vo);
    return new PageInfo<Syncstatus>(pages);
  }

2、對(duì)數(shù)據(jù)庫(kù)的操作:

<update id="update_duotiao_systemcode">
  UPDATE aaa SET systemcode = '3' WHERE systemcode = #{systemcode,jdbcType=VARCHAR}
 </update>

<delete id="delete">
  delete from aaa where uuid = #{uuid,jdbcType=VARCHAR}
 </delete>

3、配置文件:

<&#63;xml version="1.0" encoding="UTF-8"&#63;>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource">
    <constructor-arg ref="dataSourceTarget"/>
  </bean>

  <!-- 定義使用dbcp2連接池的數(shù)據(jù)源
      此處使用自定義的數(shù)據(jù)源,將用戶名與密碼解密處理
   -->
  <bean id="dataSourceTarget" class="com.asd.common.jdbc.MyBasicDataSource" >
    <property name="url" value="${jdbc.url}"> </property>
    <property name="username" value="${jdbc.username}"> </property>
    <property name="password" value="${jdbc.password}"> </property>
    <property name="driverClassName" value="${jdbc.driverClassName}"> </property>
    <!-- informix-->
    <!--<property name="validationQuery" value="select count(*) from systables"> </property>-->
    <!-- mysql檢測(cè)方式 -->
     <property name="validationQuery" value="select 1"> </property>
    <!-- oracle檢測(cè)方式
    <property name="validationQuery" value="select 1 from dual"> </property> -->
  </bean>

  <!-- 配置SqlSessionFactoryBean -->
  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 注入數(shù)據(jù)源 相關(guān)信息看源碼 -->
    <property name="dataSource" ref="dataSource" />
    <!-- 掃描的實(shí)體所在的包-->
    <property name="configLocation" value="classpath:mybatis.xml"/>
    <!-- mapper和resultmap配置路徑 -->
    <property name="mapperLocations">
      <list>
        <value>classpath:mybatis/*Mapper.xml</value>
      </list>
    </property>
  </bean>

  <!-- 自動(dòng)掃描mapper接口,注入sqlsessionfactory -->
  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.asd.modules.dao"/>
  </bean>

  <!-- 啟用類掃描機(jī)制,通過(guò)元數(shù)據(jù)配置Service -->
  <context:component-scan base-package="com.asd">
    <context:include-filter type="regex"
                expression="com\.asd\.modules\.sevice\.impl\.*ServiceImpl" />
  </context:component-scan>

  <!-- mybatis事物配置 -->

  <context:annotation-config />
  <!-- ================================事務(wù)相關(guān)控制================================================= -->

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
  </bean>

  <tx:advice id="reinsAdvice" transaction-manager="transactionManager">
    <tx:attributes>

      <tx:method name="delete*" propagation="REQUIRED" read-only="false"
            rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" />

      <tx:method name="insert*" propagation="REQUIRED" read-only="false"
            rollback-for="java.lang.RuntimeException" />
      <tx:method name="save*" propagation="REQUIRED" read-only="false"
            rollback-for="java.lang.RuntimeException" />

      <tx:method name="update*" propagation="REQUIRED" read-only="false"
            rollback-for="java.lang.Exception" />

      <tx:method name="find*" propagation="SUPPORTS" />
      <tx:method name="get*" propagation="SUPPORTS" />
      <tx:method name="select*" propagation="SUPPORTS" />
      <tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
    </tx:attributes>
  </tx:advice>

  <aop:config>
    <!-- 把事務(wù)控制在Service層 -->
    <aop:pointcut id="reinsPointCut"
           expression="execution(* com.asd.modules.service.impl.*ServiceImpl.*(..))" />
    <aop:advisor pointcut-ref="reinsPointCut"
           advice-ref="reinsAdvice" />
  </aop:config>

</beans>

4、數(shù)據(jù)庫(kù)語(yǔ)句:

-- 創(chuàng)建aaa表用來(lái)驗(yàn)證增刪改查的返回值
CREATE TABLE `reserve`.`aaa` (
 `uuid` char(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `systemcode` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `status` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 
 PRIMARY KEY (`uuid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;


-- 創(chuàng)建bbb表用來(lái)關(guān)聯(lián)aaa的uuid作外鍵
CREATE TABLE `reserve`.`bbb` (
 `uuid` char(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `systemcode` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `status` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 
 PRIMARY KEY (`uuid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

alter table bbb add constraint FK_T_POSITI_REFERENCE_T_COMPAN foreign key (uuid)references 
aaa (uuid);

insert into bbb (uuid,systemcode,status)value ('1','2','2');

-- 驗(yàn)證事支持
DELETE from aaa where uuid != '1';
insert into aaa (uuid,systemcode,status)value ('2','2','2');
SELECT * FROM aaa;

排查過(guò)程共查找了下述方面:

1、排除數(shù)據(jù)庫(kù)原因:

如何解決Spring事務(wù)管理配置文件問(wèn)題

查看mysql數(shù)據(jù)庫(kù)是支持事務(wù)的;而且用informix數(shù)據(jù)庫(kù)進(jìn)行了驗(yàn)證,同樣沒(méi)有回滾。

2、驗(yàn)證了impl的類型等均為問(wèn)題。

3、查看了事務(wù)的配置信息也正確好用。

4、驗(yàn)證了系統(tǒng)其它的一些方法,發(fā)現(xiàn)是支持事務(wù)的。

5、將這兩個(gè)語(yǔ)句放到其它方法里也好用。

6、事務(wù)是在service層處理的,在控制層也加了異常捕獲(這個(gè)操作并不會(huì)影響事務(wù)回滾,即使不catch,也會(huì)回滾的)

最終鎖定問(wèn)題原因:是因?yàn)榉椒Q的問(wèn)題。

當(dāng)將方法名改成其它的,不以get開(kāi)頭,不報(bào)錯(cuò)。

這個(gè)問(wèn)題很坑,因?yàn)楸疽詾闉榕渲梦募械膅et*,會(huì)使這個(gè)方法的事務(wù)起作用,誰(shuí)知道恰恰get*的這個(gè)配置雖然起作用了,但是結(jié)果卻是事務(wù)不回滾,在將該配置改為

<tx:method name="get*" propagation="SUPPORTS" rollback-for="java.lang.Exception"/>

也沒(méi)有用,最后將其注釋掉,事務(wù)回滾。走了下面的配置:

<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />

需要注意的是tx:method 的name屬性指的是方法名。

將SUPPORTS改為REQUIRED后,事務(wù)也進(jìn)行回滾。最終得到原因:是因?yàn)閜ropagation的配置信息不正確。

拓展:

一、在聲明式的事務(wù)處理中,要配置一個(gè)切面,其中就用到了propagation,表示打算對(duì)這些方法怎么使用事務(wù),是用還是不用,其中propagation有七種配置,REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。默認(rèn)是REQUIRED。

二、Spring中七種Propagation類的事務(wù)屬性詳解:

  • REQUIRED:支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù)。這是最常見(jiàn)的選擇。
  • SUPPORTS:支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就以非事務(wù)方式執(zhí)行。
  • MANDATORY:支持當(dāng)前事務(wù),如果當(dāng)前沒(méi)有事務(wù),就拋出異常。
  • REQUIRES_NEW:新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
  • NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
  • NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
  • NESTED:支持當(dāng)前事務(wù),如果當(dāng)前事務(wù)存在,則執(zhí)行一個(gè)嵌套事務(wù),如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù)。

三、注意.

這個(gè)配置將影響數(shù)據(jù)存儲(chǔ),必須根據(jù)情況選擇。

問(wèn)題往往出現(xiàn)在你忽略的地方。

以上就是關(guān)于如何解決Spring事務(wù)管理配置文件問(wèn)題的內(nèi)容,如果你們有學(xué)習(xí)到知識(shí)或者技能,可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI