《Spring系列》第15章 声明式事务(一) 基础使用

一、ACID特性

⑴ 原子性(Atomicity)
       原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,
    因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

⑵ 一致性(Consistency)
  一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
	转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

⑶ 隔离性(Isolation)
  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

  即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

  关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。

⑷ 持久性(Durability)
  持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

  例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,
  即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

二、事务

Spring的事务管理有两种方式:一种是传统的编程式事务管理,即通过编写代码实现的事务管理;另一种是基于 AOP 技术实现的声明式事务管理。由于在实际开发中,编程式事务管理很少使用,所以我们只对 Spring 的声明式事务管理进行详细讲解。

Spring 声明式事务管理在底层采用了 AOP 技术,其最大的优点在于无须通过编程的方式管理事务,只需要在配置文件中进行相关的规则声明,就可以将事务规则应用到业务逻辑中。

Spring 实现声明式事务管理主要有两种方式:

  • 基于 XML 方式的声明式事务管理。
  • 通过 Annotation 注解方式的事务管理。

1.基于XML的声明式事务

目前已经很少写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:contxt="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.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
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/tx/spring-aop.xsd
">

    <!--开启包扫描-->
    <contxt:component-scan base-package="com.jianan"/>

    <!--数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="url" value="jdbc:mysql:///jianan"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>

    <!--连接-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入 dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--事务管理-->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置通知-->
    <tx:advice id="advice">
        <tx:attributes>
            <tx:method name="update" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>

    <!--aop配置-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.jianan.spring5.tx.UserDao.*(..))" />
        <!--配置切面-->
        <aop:advisor advice-ref="advice" pointcut-ref="pt" />
    </aop:config>

</beans>

2.基于注解的声明式事务

  1. @EnableTransactionManagement开启事务管理
  2. @Transactional 事务

三、@Transactional 注解介绍

  1. @Transactional,这个注解添加到类上面,也可以添加方法上面
  2. 如果把这个注解添加类上面,这个类里面所有的方法都添加事务
  3. 如果把这个注解添加方法上面,为这个方法添加事务

看一下其源码

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    // 事务传播行为
    Propagation propagation() default Propagation.REQUIRED;

    // 事务的隔离级别
    Isolation isolation() default Isolation.DEFAULT;
    
    // 超时时间
    int timeout() default -1;

    boolean readOnly() default false;
  
    // 回滚异常
    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};
    
    // 不回滚异常
    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

1) propagation 事务传播行为

多事务方法直接进行调用,这个过程中事务 是如何进行管理的,举例就是当一个方法A,调用到另外一个事务方法B,方法A的事务是如何传播到方法B的

Spring提供了7种传播行为

行为描述
Propagation.REQUIRED如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务
假如方法A存在事务,方法A调用事务方法B,此时A B 共用一套方法
假如方法A不存在事务,方法A调用事务方法B,此时B创建一个新的事务
默认值
Propagation.REQUIRES_NEW重新创建一个新的事务,如果当前存在事务,延缓当前的事务
方法A调用事务方法B,此时无论方法A是否有事务,都会直接为B创建新的事务
Propagation.SUPPORTS如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行
Propagation.NOT_SUPPORTED以非事务的方式运行,如果当前存在事务,暂停当前的事务
Propagation.MANDATORY如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常
Propagation.NEVER以非事务的方式运行,如果当前存在事务,则抛出异常
Propagation.NESTED如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务

上面的七种行为,对应Java种的Propagation枚举类

public enum Propagation {
    REQUIRED(0),// 意思代表必须,方法必须有事务
    SUPPORTS(1),// 意思为支持 也就是方法B跟随方法A的事务状态
    MANDATORY(2),// 意思为强制的  也就是方法B必须使用事务,那么就看方法A有没有,有就加入,没有就报错
    REQUIRES_NEW(3),// 意思代表必须新的,也就是方法B必须创建新的事务
    NOT_SUPPORTED(4),// 意思为不支持,也就是暂停事务,全部以非事务运行
    NEVER(5),// 意思为绝不  就是以非事务运行
    NESTED(6);// 意思为嵌套  就是方法A有事务,方法B就嵌套一个事务

    private final int value;

    private Propagation(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }
}

2) isolation 事务隔离级别

事务隔离级别对应Java中的4种隔离级别,这些隔离级别就是为了问题 脏读幻读不可重复读

解释描述
脏读读未提交的
不可重复读主要针对查询,不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,
这是由于 在查询间隔,被另一个事务修改并提交了
幻读主要针对修改,在事务修改后,发现还有1行未修改,因为另一个事务插入了新的一条,好似幻觉一样

数据库隔离级别

隔离级别描述脏读不可重复幻读备注
Serializable串行化
Repeatable read可重复读×默认值
Read committed读已提交××
Read uncommitted读未提交×××

3) timeout 超时时间

  1. 事务需要在一定时间内进行提交,如果不提交进行回滚
  2. 默认值是 -1 ,设置时间以秒单位进行计算

4) readOnly 是否只读

  1. 读:查询操作,写:添加修改删除操作
  2. readOnly 默认值 false,表示可以查询,可以添加修改删除操作
  3. 设置 readOnly 值是 true,设置成 true 之后,只能查询

5) rollbackFor 回滚

设置进行回滚的异常

6) noRollbackFor 不回滚

设置不进行回滚的异常

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为人师表好少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值