数据库事务 和 Spring AOP事务管理

数据库事务(ACID) : 

  • 原子性(Atomicity): 事务是不可分割的最小操作单位,要么同时成功,要么同时失败

  • 一致性(Consistency) :事务完成时,必须使所有的数据都保持一致状态 (就是上面案例, 不管事务执行是否成功, 总额不会变化)

  • 隔离性(Isolation) :多个事务之间,操作的可见性  (将来有多个事务可以操作同一批数据 , 隔离性越强操作越不可见, 性能越低 . 隔离性越弱操作是可见的, 性能越高 一般不改变, 默认就可以, 默认的就是在mySQL里面当别人提交了或者回滚了, 我才能看到对方对应的修改)

  • 持久性(Durability) :事务一旦提交或回滚,它对数据库中的数据的改变就是永久的

 

- 创建账户表
CREATE TABLE account(id INT PRIMARY KEY auto_increment,name VARCHAR(10),money DOUBLE(10,2));
-- 添加数据
INSERT INTO account(name,money) VALUES ('张三',1000),('李四',1000);

SELECT * FROM account;

-- 转账操作
-- 开启事务
BEGIN;
-- 1.查询李四金额
-- 2.李四金额 -500 
UPDATE account SET money =  money -500 WHERE name = '李四';

-- 出错了....

-- 3.张三金额 + 500
UPDATE account SET money = money +500 WHERE name = '张三';

-- 提交事务  提交事务后数据就会持久化修改
COMMIT;
-- 回滚事务  回滚到事务开启的状态, 不做任何修改
ROLLBACK;

==  说明:==

mysql中事务是自动提交的。

也就是说我们不添加事务执行sql语句,语句执行完毕会自动的提交事务。

可以通过这个语句查询默认提交方式:   

SELECT @@autocommit;

查询到的结果是1 则表示自动提交,数据会自动持久化数据库, 结果是0表示手动提交 , 如果不手动commit只会临时修改, 不会持久化数据。当然也可以通过下面语句修改提交方式

set @@autocommit = 0;

注意 : oracle数据库是要手动提交的

Spring AOP事务管理

  • 事务作用:在数据层保障一系列的数据库操作同成功同失败

  • Spring事务作用:在数据层或==业务层==保障一系列的数据库操作同成功同失败

数据层有事务我们可以理解,为什么业务层也需要处理事务呢?

因为业务层实际上组合了若干数据层功能, 在业务层开事务, 可以保障调用多个的数据层操作处于同一个事务, 同成功同失败 , 这就是Spring事务的作用 , 它是为了保障组合功能过程中事务的生效的.

Spring为了管理事务,提供了一个平台事务管理器 PlatformTransactionManager 接口

commit是用来提交事务,rollback是用来回滚事务。

PlatformTransactionManager只是一个接口,Spring还为其提供了一个具体的实现:

 从名称上可以看出,我们只需要给它一个DataSource对象,它就可以帮你去在业务层管理事务。其内部采用的是JDBC的事务。所以说如果你持久层采用的是JDBC相关的技术,就可以采用这个事务管理器来管理你的事务。而Mybatis内部采用的就是JDBC的事务,所以后期我们Spring整合Mybatis就采用的这个DataSourceTransactionManager事务管理器。

转账案例-需求分析

接下来通过一个案例来学习下Spring是如何来管理事务的。

先来分析下需求:

需求: 实现任意两个账户间转账操作

需求微缩: A账户减钱,B账户加钱

为了实现上述的业务需求,我们可以按照下面步骤来实现下: ①:数据层提供基础操作,指定账户减钱(outMoney),指定账户加钱(inMoney)

②:业务层提供转账操作(transfer),调用减钱与加钱的操作

③:提供2个账号和操作金额执行转账操作

④:基于Spring整合MyBatis环境搭建上述操作

转账案例-环境搭建

步骤1:准备数据库表

create database spring_db character set utf8;
use spring_db;
create table tbl_account(
    id int primary key auto_increment,
    name varchar(35),
    money double
);
insert into tbl_account values(1,'Tom',1000);
insert into tbl_account values(2,'Jerry',1000);

步骤2:创建项目导入jar包 项目的pom.xml添加相关依赖

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
    </dependency>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.0</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

  </dependencies>

 

 

事务管理

上述环境,运行单元测试类,会执行转账操作,Tom的账户会减少100,Jerry的账户会加100。

这是正常情况下的运行结果,但是如果在转账的过程中出现了异常,如:

这个时候就模拟了转账过程中出现异常的情况,正确的操作应该是转账出问题了,Tom应该还是900,Jerry应该还是1100,但是真正运行后会发现,并没有像我们想象的那样,Tom账户为800而Jerry还是1100,100块钱凭空消息了,银行乐疯了。如果把转账换个顺序,银行就该哭了。

不管哪种情况,都是不允许出现的,对刚才的结果我们做一个分析:

①:程序正常执行时,账户金额A减B加,没有问题

②:程序出现异常后,转账失败,但是异常之前操作成功,异常之后操作失败,整体业务失败

当程序出问题后,我们需要让事务进行回滚,而且这个事务应该是加在业务层上,而Spring的事务管理就是用来解决这类问题的。

Spring事务管理具体的实现步骤为:

步骤1:在需要被事务管理的方法上添加注解

 步骤2:在JdbcConfig类中配置事务管理器

 

步骤3:开启事务注解   在SpringConfig的配置类中开启

步骤4:运行测试类

会发现在转换的业务出现错误后,事务就可以控制回滚,保证数据的正确性。

知识点1:@EnableTransactionManagement

名称@EnableTransactionManagement
类型配置类注解
位置配置类定义上方
作用设置当前Spring环境中开启注解式事务支持

知识点2:@Transactional

名称@Transactional
类型接口注解 类注解 方法注解
位置业务层接口上方 业务层实现类上方 业务方法上方
作用为当前业务层方法添加事务(如果设置在类或接口上方则类或接口中所有方法均添加事务)

Spring事务角色

重点要理解两个概念,分别是事务管理员事务协调员

  • 事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法

  • 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法

==注意:== 目前的事务管理是基于DataSourceTransactionManagerSqlSessionFactoryBean使用的是同一个数据源。

  • 未开启Spring事务之前:

 

  • 开启Spring的事务管理后

 

Spring事务属性

在这一节中,我们主要学习三部分内容事务配置转账业务追加日志事务传播行为

一  :  事务配置

上面这些属性都可以在@Transactional注解的参数上进行设置。

  • readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true。

  • timeout:设置超时时间单位秒,在多长时间之内事务没有提交成功就自动回滚,-1表示不设置超时时间。

  • rollbackFor:当出现指定异常进行事务回滚

  • noRollbackFor:当出现指定异常不进行事务回滚

    • 思考:出现异常事务会自动回滚,这个是我们之前就已经知道的

    • noRollbackFor是设定对于指定的异常不回滚,这个好理解

    • rollbackFor是指定回滚异常,对于异常事务不应该都回滚么,为什么还要指定?

      • 这块需要更正一个知识点,并不是所有的异常都会回滚事务,比如下面的代码就不会回滚

 

 

出现这个问题的原因是,Spring的事务只会对Error异常RuntimeException异常及其子类进行事务回顾,其他的异常类型是不会回滚的,对应IOException不符合上述条件所以不回滚

  • 此时就可以使用rollbackFor属性来设置出现IOException异常进行回滚

  • rollbackForClassName等同于rollbackFor,只不过属性为异常的类全名字符串

  • noRollbackForClassName等同于noRollbackFor,只不过属性为异常的类全名字符串

  • isolation设置事务的隔离级别

    • DEFAULT :默认隔离级别, 会采用数据库的隔离级别

    • READ_UNCOMMITTED : 读未提交

    • READ_COMMITTED : 读已提交

    • REPEATABLE_READ : 重复读取

    • SERIALIZABLE: 串行化

介绍完上述属性后,还有最后一个事务的传播行为,为了讲解该属性的设置,我们需要完成下面的案例。

二 :  转账业务追加日志案例

事务传播行为

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值