美文网首页
Spring事务配置&&回滚失效的原因之一

Spring事务配置&&回滚失效的原因之一

作者: CongCo | 来源:发表于2019-04-08 11:27 被阅读0次
    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)
    读取未提交数据(会出现脏读, 不可重复读) 基本不使用
    @Transactional(isolation = Isolation.READ_COMMITTED)
    读取已提交数据(会出现不可重复读和幻读)
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    可重复读(会出现幻读)
    @Transactional(isolation = Isolation.SERIALIZABLE)
    串行化
    
    MYSQL: 默认为REPEATABLE_READ级别
    SQLSERVER: 默认为READ_COMMITTED
    
    脏读 : 一个事务读取到另一事务未提交的更新数据  
    不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,后续读取可以读到另一事务已提交的更新数据.   
    相反, "可重复读"在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据   
    幻读 : 一个事务读到另一个事务已提交的insert数据
    

    Spring事务的传播行为

    事物传播行为介绍: 
    @Transactional(propagation=Propagation.REQUIRED) 
    如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
    @Transactional(propagation=Propagation.NOT_SUPPORTED) 
    容器不为这个方法开启事务
    @Transactional(propagation=Propagation.REQUIRES_NEW) 
    不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
    @Transactional(propagation=Propagation.MANDATORY) 
    必须在一个已有的事务中执行,否则抛出异常
    @Transactional(propagation=Propagation.NEVER) 
    必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
    @Transactional(propagation=Propagation.SUPPORTS) 
    如果其他bean调用这个方法,在其他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();
        }
    }
    

    结果

    GTWfmQ.png
    GTWROg.png
    数据库表没有插入新的数据

    参考博客

    相关文章

      网友评论

          本文标题:Spring事务配置&&回滚失效的原因之一

          本文链接:https://www.haomeiwen.com/subject/gvluiqtx.html