Spring事务管理

编程式事务管理

        将事务管理代码嵌到业务方法中来控制事务的提交和回滚

        缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码

声明式事务管理

        将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。

        将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。

propagation:事务传播机制

        REQUIRED(默认):支持使用当前事务,如果当前事务不存在,创建一个新事务。

        SUPPORTS:支持使用当前事务,如果当前事务不存在,则不使用事务。

        MANDATORY:中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception。

        REQUIRES_NEW:创建一个新事务,如果当前事务不存在,把当前事务挂起。

        NOT_SUPPORTED:无事务执行,如果当前事务不存在,把当前事务挂起。

        NEVER:无事务执行,如果当前有事务则抛出Exception。

        NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。

isolation:事务隔离等级

        READ_COMMITTED :读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。

        READ_UNCOMMITTED :读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。

        REPEATABLE_READ(默认值) :重复读,就是在开始读取数据(事务开启)时,不再允许修改操作

        SERIALIZABLE

                        Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免

脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

        timeout:事务超时时间,允许事务运行的最长时间,以秒为单位。默认值为-1,表示不超时

read-only:事务是否为只读,默认值为false

        rollback-for:设定能够触发回滚的异常类型

                Spring默认只在抛出runtime exception时才标识事务回滚

                可以通过全限定类名指定需要回滚事务的异常,多个类名用逗号隔开

        no-rollback-for:设定不触发回滚的异常类型

                Spring默认checked Exception不会触发事务回滚

                可以通过全限定类名指定不需回滚事务的异常,多个类名用英文逗号隔开

声明式事务管理代码实现

        实体类

package com.spring3.po;

/**
 * Created by IntelliJ IDEA.
 * 银行实体类
 *
 * @Author : zrc
 * @create 2022/8/29 14:59
 */
public class Bank {
    private int id;
    private String name;
    private int money;

    
}

        数据访问接口 

package com.spring3.dao;

import org.apache.ibatis.annotations.Param;

/**
 * Created by IntelliJ IDEA.
 *银行数据访问接口
 * @Author : zrc
 * @create 2022/8/29 14:59
 */
public interface BankDao {
    /**
     * @param id 收款账户编号
     * @param money 金额
     */
    public void addMoney(@Param("id") int id , @Param("money") int money);

    /**
     * @param id 扣款账户编号
     * @param money 金额
     */
    public void reduceMoney(@Param("id")int id , @Param("money")int money);
}

        mapper文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.spring3.dao.BankDao">
    <update id="addMoney">
        update bank set money = money+ #{money} where id =#{id};
    </update>

    <update id="reduceMoney">
        update bank set  money = money- #{money} where  id=#{id};
    </update>
</mapper>

        业务逻辑接口

package com.spring3.service;

/**
 * Created by IntelliJ IDEA.
 *账户业务逻辑接口
 * @Author : zrc
 * @create 2022/8/29 16:16
 */
public interface BankService {
    public void update(int fromId,int toId,int money);
}

        业务逻辑接口实现类

package com.spring3.service.impl;

import com.spring3.dao.BankDao;
import com.spring3.service.BankService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.xml.crypto.Data;
import java.util.Date;

/**
 * Created by IntelliJ IDEA.
 * 账户业务逻辑接口实现类
 *
 * @Author : zrc
 * @create 2022/8/29 16:17
 */
@Service
public class BankServiceImpl implements BankService {
    @Autowired
    private BankDao bankDao;

    @Override
    public void update(int fromId, int toId, int money) {
        //先执行扣款操作
        bankDao.reduceMoney(fromId, money);
        //加入空指针异常用来测试事务是否设置成功
        Date date=null;
        date.getTime();
        //再执行收款操作
        bankDao.addMoney(toId, money);
    }
}

        其中加入了空指针异常用来测试事务是否设置成功

        XML文件

                头部信息

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

                  加载配置文件并扫描注解所在的包

 <!--加载配置文件-->
    <context:property-placeholder location="classpath:database.properties"></context:property-placeholder>
    <!--扫描注解所在的包-->
    <context:component-scan base-package="com.spring3.service"></context:component-scan>
    <context:component-scan base-package="com.spring3.dao"></context:component-scan>

                创建数据库连接池,sql会话工厂,和指定包下的mapper文件   

<!--创建数据库连接池-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" scope="singleton">
        <property name="driverClassName" value="${driver}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${user}"></property>
        <property name="password" value="${password}"></property>
        <!-- 在不新建连接的条件下,池中保持空闲的最少连接数。 -->
        <property name="minIdle" value="${minIdle}"></property>
        <!-- 池里不会被释放的最多空闲连接数量。设置为0时表示无限制。 -->
        <property name="maxIdle" value="${maxIdle}"></property>
        <!-- 池启动时创建的连接数量 -->
        <property name="initialSize" value="${initialSize}"></property>
        <!-- 同一时间可以从池分配的最多连接数量。设置为0时表示无限制。 -->
        <property name="maxActive" value="${maxActive}"></property>
        <!-- 等待超时以毫秒为单位,在抛出异常之前,池等待连接被回收的最长时间(当没有可用连接时)。设置为-1表示无限等待。-->
        <property name="maxWait" value="${maxWait}"></property>
    </bean>

    <!--创建SQL会话工厂-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatisconfig.xml"></property>
    </bean>

    <!--自动扫描指定包下的Mapper接口-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.spring3.dao"></property>
    </bean>

             创建AOP事务管理

<!--创建AOP事务 管理 开始-->
    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--定义切面-->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="pointcut" expression="execution(* com.spring3.service..*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>

    <!--创建AOP事务 管理 结束-->

        创建测试类

public class BankServiceTest {
    @Test
    public void update(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BankService bankService = context.getBean(BankServiceImpl.class);
        System.out.println("开始");
        bankService.update(1,2,1000);
        System.out.println("结束");
    }

}

     测试完成:在异常上下的两个方法要么同时成功要么同时失败

用注解方式实现事务管理

        业务逻辑实现类

/**
 * Created by IntelliJ IDEA.
 * 账户业务逻辑接口实现类
 *
 * @Author : zrc
 * @create 2022/8/29 16:17
 */
@Transactional
@Service
public class BankServiceImpl implements BankService {
    @Autowired
    private BankDao bankDao;

    @Override
    public void update(int fromId, int toId, int money) {
        //先执行扣款操作
        bankDao.reduceMoney(fromId, money);
        //加入空指针异常用来测试事务是否设置成功
        Date date = null;
        date.getTime();
        //再执行收款操作
        bankDao.addMoney(toId, money);
    }
}

        XML配置文件

 <!--注解实现事务管理-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

         测试完成:在异常上下的两个方法要么同时成功要么同时失败 

总结

        使用注解实现事务处理

属性

类型

说明

propagation

枚举型:Propagation

可选的传播性设置。使用举例:

@Transactional(propagation=

                        Propagation.REQUIRES_NEW)

isolation

枚举型:Isolation

可选的隔离性级别。使用举例:

@Transactional(isolation=Isolation.READ_COMMITTED)

readOnly

布尔型

是否为只读型事务。使用举例:

@Transactional(readOnly=true)

timeout

int型(以秒为单位)

事务超时。使用举例:Transactional(timeout=10)

属性

类型

说明

rollbackFor

一组 Class 类的实例,必须是Throwable的子类

一组异常类,遇到时 必须 回滚。

使用举例:@Transactional(

rollbackFor={SQLException.class}),多个异常用逗号隔开

rollbackForClassName

一组 Class 类的名字,必须是Throwable的子类

一组异常类名,遇到时 必须 回滚。使用举例:@Transactional(

rollbackForClassName={

"SQLException"}),多个异常用

逗号隔开

noRollbackFor

一组 Class 类的实例,必须是Throwable的子类

一组异常类,遇到时 必须不 回滚

noRollbackForClassName

一组 Class 类的名字,必须是Throwable的子类

一组异常类名,遇到时 

                必须不 回滚

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值