一、事务的特性
1、事务的特性
* 有四个特性:
-原子性:在事务里面操作,要么都成功,要么都失败
-一致性:在事务操作过程中,数据要保持一致
--比如 小金给小丽转账10000,过程出现了异常,钱不会丢失
-隔离性:在多个事务同时对一张表操作的时候,多个事务直接互相不影响
-持久性:提交事务之后,数据就会真正生效
二、事务的隔离性产生的问题
2、事务的隔离性
* 不考虑事务的隔离性,产生一些问题,五个问题,其中三个读的问题
* 掌握三个读的问题,以及如果解决这三个读的问题
* 三个读的问题
-第一个问题:脏读:一个事务获取到了另一个事务里面没有提交的数据(一个事务操作数据但是还没有提交的时候,另一个事务能够查询到修改过后的结果,导致如果修改的那个事务回滚,修改的结果不变,但是后一个事务查询的结果是看到修改的值,那么会导致一直假转账现象。 故存在的问题是 脏读)
-第二个问题:不可重复读:一个事务里面查询到了,另一事务里面update的操作,导致这个事务里面两次查询的结果不一致(一个事物修改了数据也提交了数据,但是另一个事务在修改完成没提交的时候去读一次,提交后又读取一次,导致两次查询的结果不一致。 故存在的问题是 不可重复读)
-第三个问题:虚读(幻读):一个事务里面查询到了,另一个事务里面insert操作,导致这个事务里面两次查询的结果不一致(一个事务进行操作数据,也提交了数据,但是另外一个事务在没结束之前,读取到的数据一直都是修改之前的数据,要想读取到最新数据,需要结束当前事务再去读取数据的时候才会是更新过后的数据。 故存在的问题是 虚读/幻读)
* 解决方式:通过设置事务的隔离级别解决这些读的问题
Serializable:串行的.避免脏读、不可重复读和虚读发生
Repeatable read:重复读. 避免脏读、不可重复读.但是虚读还是有可能发生的
Read committed:已提交读.避免脏读.但是不可重复读和虚读有可能发生
Read uncommitted:未提交读.脏读、不可重复读、虚读都可能发生
* 隔离级别的优先级:Serializable -- Repeatable read -- Read committed -- Read uncommitted
* 查询当前事务隔离级别:select @@tx_isolation;
-mysql数据库默认的隔离级别是:Repeatable read
* set session transaction isolation level 设置事务隔离级别
(1)演示脏读
* 第一步操作:打开两个cmd窗口,分别登录mysql
* 第二步操作:切换到要操作的数据库,在左边的窗口 设置隔离级别是 Read uncommitted,
同时查看两个窗口里面的隔离级别
set session transaction isolation level read uncommitted
* 第三步操作:在两个窗口里面分别开启事务
* 第四步操作:在右边的窗口里面做转账的操作,小奥给小苍转账10000
update account set sal=sal-1000 where name='小奥'
update account set sal=sal+1000 where name='小苍'
* 第五步操作:在左边的窗口里面查看数据,可以查看到,但是右边窗口做回滚,左边在窗口数据没有了
================================这种效果就是脏读=====================================
(2)解决脏读:设置事务的隔离级别
* 设置Read committed,解决脏读
* 演示不可重复读和避免脏读
* 第一步操作:打开两个cmd窗口,分别登录mysql
* 第二步操作:切换到要操作的数据库,在左边的窗口设置隔离级别是Read committed
同时查看两个窗口的隔离级别
set session transaction isolation level read committed
* 第三步操作:在两个窗口里面分别开启事务
* 第四步操作:在左边窗口查看表中的数据,
* 在右边窗口执行转账操作 小奥给小苍转账10000,在右边窗口里面提交事务
update account set sal=sal-1000 where name='小奥'
update account set sal=sal+1000 where name='小苍'
========================================避免了脏读====================================
* 再到左边窗口里面查看数据
- 在左边窗口里面通过事务查看数据,这两次查看的结果不一样了
* 多个事务之间互相影响到了,这个问题就是======================不可重复读==================
(3)解决不可重复读
* 设置事务的隔离级别是Repeatable read
* 演示避免不可重复读
* 第一步操作:打开两个cmd窗口,分别登录mysql
* 第二步操作:切换到要操作的数据库,在左边的窗口设置隔离级别是Repeatable read
同时查看两个窗口的隔离级别
set session transaction isolation level repeatable read
* 第三步操作:在两个窗口里面分别开启事务
* 第四步操作:在左边窗口查看表中的数据,
- 在右边窗口执行转账操作 小奥给小苍转账10000,在右边窗口里面提交事务
update account set sal=sal-1000 where name='小奥'
update account set sal=sal+1000 where name='小苍'
===========================================避免了脏读================================
* 再到左边窗口里面查看数据,数据没有变化,只有提交了当前事务之后数据才会变化
===============================避免了不可重复读,但是存在虚读========================
(4)解决虚读,
*设置隔离级别是Serializable:串行的
-set session transaction isolation level serializable
* 第一步操作:打开两个cmd窗口,分别登录mysql
* 第二步操作:切换到要操作的数据库,在左边的窗口设置隔离级别是Serializable
同时查看两个窗口的隔离级别
set session transaction isolation level serializable
* 第三步操作:在两个窗口里面分别开启事务
* 第四步操作:在右边窗口里面执行更新操作,
在左边窗口里面查询表中的记录,出现了等待状态,在右边事务只有提交之后,左边的窗口类里面查询语句才会执行
==========================================避免这三个读的问题===========================
- 因为这个级别都不允许有多个事务同时进行操作
** 记住事务的特性和事务的四个隔离级别
(5)使用jdbc也可以设置事务的隔离级别(了解)
** 通过Connection里面setTransactionIsolation(int level)设置事务的隔离级别
** 通过Connection里面常量设置隔离级别
static int TRANSACTION_READ_COMMITTED
指示不可以发生脏读的常量;不可重复读和虚读可以发生。
static int TRANSACTION_READ_UNCOMMITTED
指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。
static int TRANSACTION_REPEATABLE_READ
指示不可以发生脏读和不可重复读的常量;虚读可以发生。
static int TRANSACTION_SERIALIZABLE
指示不可以发生脏读、不可重复读和虚读的常量。