首先了解一下事务

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

性质(ACID)

  • 原子性:事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行。
  • 一致性:几个并行执行的事务,其执行结果必须与按某一顺序 串行执行的结果相一致。
  • 隔离性:事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的
  • 持久性:对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障

事务级别:

  1. Read Uncommitted –1个事务,1个X锁,即对写数据枷锁。读无锁。
    对写的加锁,避免了数据丢失,但是事务内可读,存在读取未提交和已回滚数据,出现脏数据,事务中的最低级事务.
  2. Read Committed –1个事务,2个锁。事务内X锁。
    读写都加锁,避免了事务丢失和脏数据,。若是在多数据单元处理时,一条记录加事务,未加事务的记录,可以做写操作,不能重复读。否则数据前后读取不一致。
  3. Repeatable read —2个事务,2个锁。
    避免了数据的丢失,脏,以及不可重复读情况。但是在事务内操作的情况下,数据库增加记录不可控,即会出现符合是事务内搜索条件的记录,但是不添加进事务。事务执行完,即有满足条件为修改的数据,为幻读。
  4. Serializable 串行化。即不可并行操作数据库。
    避免上述问题,但是影响数据库的效率。

通俗点说:

不可重复读是指对于数据库中的某个数据,一个事务执行过程中多次查询返回不同查询结果,这就是在事务执行过程中,数据被其他事务提交修改了。
不可重复读同脏读的区别在于,脏读是一个事务读取了另一未完成的事务执行过程中的数据,而不可重复读是一个事务执行过程中,另一事务提交并修改了当前事务正在读取的数据。

幻读是事务非独立执行时发生的一种现象,例如事务T1批量对一个表中某一列列值为1的数据修改为2的变更,但是在这时,事务T2对这张表插入了一条列值为1的数据,并完成提交。此时,如果事务T1查看刚刚完成操作的数据,发现还有一条列值为1的数据没有进行修改,而这条数据其实是T2刚刚提交插入的,这就是幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点同脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

修改隔离级别的方法

全局修改需要修改MySql的全局文件mysql.ini,修改内容如下

1 #可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
2 [mysqld]
3 transaction-isolation = REPEATABLE-READ

查看当前事务级别

#查看当前事务级别
#select @@tx_isolation; 旧版本
SELECT @@transaction_isolation;#新版
#查看全局
SELECT @@global.transaction_isolation; 

可以使用下面的命令修改当前会话Session的隔离级

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
 
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)

Spring中的Transactional注解

image.png

###事物传播行为介绍:

  @Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
  @Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务
  @Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
  @Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常
  @Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
  @Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.

事务隔离级别:

  @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
  @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
  @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
  @Transactional(isolation = Isolation.SERIALIZABLE):串行化

  MYSQL: 默认为REPEATABLE_READ级别
  SQLSERVER: 默认为READ_COMMITTED

脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据