本文概览:事务分为扁平事务、保存点扁平事务、事务的嵌套。事务隔离中脏读、不可重复读、幻读三个读数据问题 定义及其解决方法

1 Mysql事务

1.1 事务种类

1.1.1 单事务

单事务,不涉及到事务的调用,即就是一个独立的事务。

1、提交回滚策略

单事务是最简单的一种,通过开启事务Begin和事务终止Commit/Rollback来控制一个事务。事务内的所有操作要么都更新数据库成功,要么都更新数据库失败。

2、主要缺点

单事务是不能提交或回滚事务的某些操作。可以通过带保存点实现

1.1.2 带有保存点的单事务

可以在事务中设置一个保存点,然后回滚时,可以只回滚到此保存点,其他的操作都可以进行提交。如果存在多个保存点p1、p2等,那么回滚时可以指定保存点。比如回滚到p1或者只回滚到p2。

 

1.2 事务相关的sql

1. 提交和回滚

  • BEGIN或START TRANSACTION;显示地开启一个事务;
  • COMMIT或COMMIT WORK,事务提交;
  • ROLLBACK或ROLLBACK WORK,事务回滚;

2. 保存点

  • SAVEPOINT identifier;SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;
  • RELEASE SAVEPOINT identifier;删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
  • ROLLBACK TO identifier;把事务回滚到指定保存点;

3. 设置隔离级别

  • SET TRANSACTION:用来设置事务的隔离级别。InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。

1.3 事务隔离级别

在数据库操作中,为了有效保证并发事务读取数据的正确性,引入了事务隔离级别。

1、不同事务之前会互相影响,会存在三个问题:

(1)脏读,A事务读取B事务未提交数据。造成问题就是,B事务回滚,那么A事务读取数据是不合法的。

(2)不可重复读。A事务读取 B事务提交的  update /delet/inset数据。A事务读取一个数据,B事务读取并修改这个数据,然后提交,A事务第二次读取就是最新的数据。

(3)幻读。在保证可重复读基础上,即A事务读不会读取到B事务的已提交数据时,但是A事务在做  insert或delete 数据时会感知事务B提交数据的存在。幻读举例如下:

1

2、为了解决上面的问题,引入了隔离级别

(1)读未提交 Read Uncommited,RU

没有做任何隔离

(2) 读提交(Read commited,RC)

解决脏读。

(3)可重复读(Repeatable Read, RR)

解决脏读、不可重复读问题

(4)串行化(Serializable),即串行的执行事务,事务没有并发性了。

解决脏读、不可重复读、幻读 的问题。可以当成对表加上了一个表锁。

3、查看事务级别

查看当前会话的事务级别

查看mysql事务级别

1.4 事务相关问题

1.4.1 一个事务在没有提交时,执行完sql是否已经更新到数据库

假设一个事务对数据库进行更新操作sql1,那么在执行完sql1还没有进行事务提交时,此时sql1对数据库操作中数据是否发生了变化?.

发生了变化,但是其他事务是否可以看到是根据事务隔离性来确定的。

2 JDBC事务的操作

事务是针对一个连接Connection,所以JDBC通过Connection来实现事务。JDBC封装了一个Conncection接口,由这个类来完成sql执行(通过Statement/PreparedStatement来执行sql)、事务提交(connection#commit())、事务回滚(conection#rollback())。

2.1 扁平事务

1、怎么使用事务   

将自动提交设置为false,即conn.setAutoCommit(false),然后手动conn.commit()、或者conn.rollback()。

2、谁在执行事务

如下代码,可以通过操作Connection来执行事务提交(conncetion.commit())和回滚(connection.rollback())。所以 一个事务内的所有sql,都是由同一个Connection来执行。

2.2 带有保存点事务

代码如下

3 Spring事务

当存在多个事务,进行嵌套调用时,根据提交和回滚策略可以划分为不同事务类型,这里主要介绍扁平事务、嵌套事务、独立事务三种类型嵌套调用事务,对于mysql并没有支持这三种嵌套调用相关的事务,但是在spring中通过@Transactional的传播属性来实现这三种事务。举例来说明这三种事务,如下是一个事务的嵌套,在父事务中又调用了三个子事务。

1、扁平类型

对于扁平类型事务,这三个子事务以及父事务,要么都提交,要么都失败。

2、嵌套事务

嵌套事务作用:对于一个事务中存在很多个子事务,为了保证一个子事务失败,不会造成所有的事务都回滚。

嵌套事务的特点:

  • 内层事务之间是独立的,所以其中一个内层事务失败,不影响其他内层事务和外层事务提交。只是回滚这个内层事务即可
  • 外层事务回滚,所有子事务都需要回滚,即使子事务已经提交了。
  • 只有外层事务提交成功后,子事务的commit操作才会生效。

对于上面例子,假设现在子事务1成功执行,子事务2失败,子事务3成功。子事务2失败了不影响后面的事务3的提交,最终结果就是根据父事务执行结果分为两种情况:

  • 情况1 父事务commit成功,那么此时子事务1和3的操作更新到数据库,因为事务2回滚了,所以子事务2不起作用
  • 情况2 父事务回滚了,那么子事务1、2、3的commit操作全部无效

3、独立事务

子事务和子事务之间,子事务和外层事务之间,都是独立的互不影响提交,即在嵌套事务的基础上,进行了增强,如下场景:

  • 子事务2提交了,父事务回滚了,此时事务2还是会提交,但是在嵌套事务中,此时事务2也会回滚。

分类&标签