Spring事务以及事务项目配置

在声明式的事务处理中,要配置一个切面,其中就用到了propagation,表示打算对这些方法怎么使用事务,是用还是不用,其中propagation有七种配置,REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。默认是REQUIRED。

Spring中七种Propagation类的事务属性详解:

REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。  
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。  
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。  
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。  
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。  
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。  
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

Spring框架的 事务有4种隔离级别isolation:

隔离级别	名称	                    含义	                                              脏读	不可重复读	幻读
读未提交	ISOLATION_READ_UNCOMMITTED	T1读取T2未提交的东西                                     V	    V	     V
读已提交	ISOLATION_READ_COMMITTED	mysql默认,事务提交后可读	                  		    X	    V	     V
可重复读	ISOLATION_REPEATABLE_READ	针对update操作;会出现幻读现象,幻读针对的是insert操作 	X    	X	     V
串行化	ISOLATION_SERIALIZABLE	    解决了脏读、不可重复读和幻读,但是效率比较低	            X	    X	     X

1. 第一种:小型的项目事务处理及配置

	<!--使用spring事务处理-->
    <!--声明事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--连接数据库,告诉数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--开启事务注解驱动,告诉spring使用注解驱动,生成代理对象
    transaction-manager:事务管理器id
    -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
// 可以加载类上,这样这个类所有的方法就都是有事务的,不过一般不这么做
// @Transactional
@Service("buyGoodService")
public class BuyGoodServiceImpl implements BuyGoodService {
    @Autowired
    private SaleDao saleDao;
    @Autowired
    private GoodsDao goodsDao;

    /**
     * propagation = Propagation.REQUIRED 传播行为,如果存在一个事务,则支持当前事务。如果没有事务则开启。
     * isolation = Isolation.DEFAULT 事务隔离级别
     * readOnly = false 只读
     * rollbackFor 表示发生指定的异常一定回滚
     *  处理逻辑是:
     *      1、spring会先检异常是不是在rollbackFor属性值中,如果在,不管什么异常都会执行回滚
     *      2、如果不在rollbackFor中,spring会判断是不是RuntimeException运行时异常,是的话也会回滚
     *
     */
   /* @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            rollbackFor = {
                    NullPointerException.class,NotEnoughException.class
            }
    )*/
    // 因为上面的配置信息都是默认的,所以直接写一个注解就行
    // 抛出运行时异常

    /*
    * 因为加了事务,顺序执行到if语句时,会抛出异常,所以就会进行事务回滚rollbackFor
    * 数据就不会提交到数据库中
    * */
    @Transactional
    @Override
    public void buyGoods(Integer id,Integer snum){
        // 记录信息,向sale表添加记录
        // 目前这样写是不对的,因为还需要判断goods的数量是否充足才能添加
        Sale sale = new Sale(id,snum);
        saleDao.insertSale(sale);

        // 判断goods的id是否存在,和数量书否充足
        Goods goods = goodsDao.selectGood(id);
        if(goods == null){
            throw new NullPointerException("编号为"+id+"的商品不存在");
        }else if(goods.getGamount() < snum){
            throw new NotEnoughException("编号为"+id+"的商品数量不够,"+"购买数量:"+snum+",原剩余数量:"+goods.getGamount());
        }

        Goods buyGoods = new Goods(id,snum);
        // 更新goods的数量
        goodsDao.updateGoods(buyGoods);
    }
}

第二种:大型项目事务配置
无需在业务中配置,事务与业务代码分离

	<!-- 导入以来Aop框架 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>

	<!--
        大型项目:声明业务方法的事务属性(隔离级别,传播行为,超时时间)
    -->
    <tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
        <!--配置事务属性-->
        <tx:attributes>
            <!--
                tx:method:给事务配置属性,可以有多个method,给多个方法配置事务
                name="buyGoods"  需要事务的方法名
                propagation:隔离级别
                isolation:传播行为
                rollback-for:指定的异常,全限定名称,发生异常一定回滚
            -->
            <tx:method name="buyGoods" propagation="REQUIRED" isolation="DEFAULT"
                       rollback-for="java.lang.NullPointerException,com.wsy.excep.NotEnoughException"/>

            <!--多个开头一样的方法配置 开头重复部分*-->
            <tx:method name="add*" propagation="REQUIRES_NEW"/>
            <tx:method name="delete*"/>
            <!--select方法设置成只读最好-->
            <tx:method name="select*" read-only="true"/>
            <!--除了以上配置好的以外的-->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--配置Aop-->
    <aop:config>
        <!--配置切入点表达式,说明哪些包中的哪些类要使用事务
            id:自定义名称
            expression:切入点表达式
            execution(* *..service..*.*(..)):这样写就能保证无论service在哪个包下,
            service包以及子包的所有类都会加入事务
        -->
        <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
        <!--配置增强器,关联上面的advice和pointcut
            advice-ref:上面<tx:advice>的id
            pointcut-ref:pointcut的id
        -->
        <aop:advisor advice-ref="transactionInterceptor" pointcut-ref="servicePt"/>
    </aop:config>
execution(* *..service..*.*(..))
这样写就能保证无论service在哪个包下,service包以及子包的所有类都会加入事务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值