Spring事務配置&&回滾失效的原因之一

2019-06-21_18-34.png

包名的配置問題

execution(* com.keeep.isrvbase.service.*.*(..)) 
//表示匹配com.keeep.isrvbase.service包下的所有方法
execution(* com.keeep.isrvbase.service..*.*(..)) 
 //表示匹配com.savage.server包及其子包下的所有方法

Spring 事務的隔離性

事務隔離級別:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
讀取未提交數(shù)據(jù)(會出現(xiàn)臟讀, 不可重復讀) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)
讀取已提交數(shù)據(jù)(會出現(xiàn)不可重復讀和幻讀)
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重復讀(會出現(xiàn)幻讀)
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化

MYSQL: 默認為REPEATABLE_READ級別
SQLSERVER: 默認為READ_COMMITTED

臟讀 : 一個事務讀取到另一事務未提交的更新數(shù)據(jù)  
不可重復讀 : 在同一事務中, 多次讀取同一數(shù)據(jù)返回的結(jié)果有所不同, 換句話說,后續(xù)讀取可以讀到另一事務已提交的更新數(shù)據(jù).   
相反, "可重復讀"在同一事務中多次讀取數(shù)據(jù)時, 能夠保證所讀數(shù)據(jù)一樣, 也就是后續(xù)讀取不能讀到另一事務已提交的更新數(shù)據(jù)   
幻讀 : 一個事務讀到另一個事務已提交的insert數(shù)據(jù)

Spring事務的傳播行為

事物傳播行為介紹: 
@Transactional(propagation=Propagation.REQUIRED) 
如果有事務, 那么加入事務, 沒有的話新建一個(默認情況下)
@Transactional(propagation=Propagation.NOT_SUPPORTED) 
容器不為這個方法開啟事務
@Transactional(propagation=Propagation.REQUIRES_NEW) 
不管是否存在事務,都創(chuàng)建一個新的事務,原來的掛起,新的執(zhí)行完畢,繼續(xù)執(zhí)行老的事務
@Transactional(propagation=Propagation.MANDATORY) 
必須在一個已有的事務中執(zhí)行,否則拋出異常
@Transactional(propagation=Propagation.NEVER) 
必須在一個沒有的事務中執(zhí)行,否則拋出異常(與Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS) 
如果其他bean調(diào)用這個方法,在其他bean中聲明事務,那就用事務.如果其他bean沒有聲明事務,那就不用事務.

事務配置

package com.keeep.isrvbase.pojo;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Table;

/**
 * 測試用例
 * @author congco
 */
@Setter
@Getter
@Table(name="tb_base_transaction_test")
public class TransactionTest {

    private Long id;

    private String name;

}

applicationContext-transaction.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
       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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 定義事務管理器 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 定義事務策略 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--所有以query開頭的方法都是只讀的 -->
            <tx:method name="query*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="select*" read-only="true"/>
            <!--其他方法使用默認事務策略 -->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <!--pointcut元素定義一個切入點,execution中的第一個星號 用以匹配方法的返回類型,
            這里星號表明匹配所有返回類型。 
      1)execution(* *(..))  
      //表示匹配所有方法  
      2)execution(public *  com.keeep.isrvbase.service.*(..))  
    //表示匹配 com.keeep.isrvbase.service中所有的公有方法  
    3)execution(* com.keeep.isrvbase.service..*.*(..)) 
    //表示匹配 com.keeep.isrvbase.service包及其子包下的所有方法
  
 -->
        <aop:pointcut id="myPointcut" expression="execution(* com.keeep.isrvbase.service..*.*(..))"/>
        <!--將定義好的事務處理策略應用到上述的切入點 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
    </aop:config>

</beans>

mapper

package com.keeep.isrvbase.mapper;

import com.github.abel533.mapper.Mapper;
import com.keeep.isrvbase.pojo.TransactionTest;

/**
 * @author congco
 */
public interface TransactionTestMapper  extends Mapper<TransactionTest> {
}

service

package com.keeep.isrvbase.service;

import com.keeep.isrvbase.mapper.TransactionTestMapper;
import com.keeep.isrvbase.pojo.TransactionTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * created on 2020/4/10 上午11:58
 *
 * @author congco
 */
@Service
public class AnotherTransService {


    @Autowired
    private TransactionTestMapper mapper;
    public String testTrans() {
        try {
            TransactionTest test = new TransactionTest();
            test.setName("cong");
            this.mapper.insertSelective(test);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "over";
    }
}


//
package com.keeep.isrvbase.service.test;

import com.keeep.isrvbase.service.AnotherTransService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 * @author congco
 * @date 19-5-27 下午7:25
 */
@Service
public class TransactionTestService {


    @Autowired
    public AnotherTransService anotherTransService;

    public String queryName() {
        return "Hello Congco";
    }


    public String saveName() {
        try {
            System.out.println("開始事務");
            this.anotherTransService.testTrans();
            int i =1/0;
            this.anotherTransService.testTrans();
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        System.out.println("roll back");
        return "ok";
    }
}
 <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.9</version>
    <scope>test</scope>
   </dependency>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version> 3.2.4.RELEASE  </version>
    <scope>provided</scope>
 </dependency>

單元測試

package com.keeep.isrvbase.test;


import com.keeep.isrvbase.service.test.TransactionTestService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * created on 2020/4/10 上午11:21
 *
 * @author congco
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring/app*.xml")
public class TransactionTestServiceTest {

    @Autowired
    private TransactionTestService service;
    @Test
   public void queryName() {

        String name = this.service.queryName();
        System.out.println(name);
    }

    @Test
   public void saveName() {
        this.service.saveName();
    }
}

結(jié)果


GTWROg.png

數(shù)據(jù)庫表沒有插入新的數(shù)據(jù)

參考博客

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容