计算机学习

您现在的位置是:首页 > mysql > 正文

mysql

事务的隔离级别

hhb2023-02-20mysql228
一个事务具有

一个事务具有ACID特性,也就是(Atomicity、Consistency、Isolation、Durability,即原子性一致性隔离性持久性),本文主要讲解一下其中的Isolation,也就是事务的隔离性

四种隔离级别分别是:


  • 读未提交(read uncommitted)

  • 一个事务还没提交时,它修改的数据都可以被别的事物看到。

  • 读已提交(read committed)

  • 一个事务提交之后,它修改的数据才会被别的事物看到。

  • 可重复读(repeatable read)

  • 一个事务执行过程中看到的数据,总是和这个事务开启时看到的数据是一致的。在可重复读的隔离级别下,未提交的事务对其他事务也是不可见的。

  • 串行化(serializable)

  • 数据的都会加锁会加读锁会加写锁。当遇到读写锁冲突时,后访问的事务必须等前一个事务执行完成后,再继续执行。以上四种隔离级别,由上往下隔离强度越来越大,但是执行效率会随之降低。在设置隔离级别时候,需要在隔离级别执行效率两者做平衡取舍。


  • 程序测试这四个隔离级别

  • 事务1

  • $cc = $this->db->query("select @@session.tx_isolation;")->row_array();
    var_dump($cc);
    echo '第一个事务<br/>';
    echo date('Y-m-d H:i:s')."start0<br/>";
    $this->db->trans_begin();
    echo date('Y-m-d H:i:s')."end0<br/>";
    
    $num = rand(0, 1000);
    var_dump($num);
    
    //查询id=1记录对应的password的值
    echo date('Y-m-d H:i:s')."select-start1<br/>";
    $info = $this->db->select('*')->from($this->table_name)->where('id', 1)->get()->row_array();
    echo date('Y-m-d H:i:s')."select-end1<br/>";
    var_dump($info);
    
    //把id=1的记录的password字段值改成$num对应的值
    echo date('Y-m-d H:i:s')."update-start1<br/>";
    $this->db->update($this->table_name, ['password' => $num], ['id' => 1]);
    echo date('Y-m-d H:i:s')."update-end2<br/>";
    
    //update后,再次查询id=1记录对应的password的值
    echo date('Y-m-d H:i:s')."select-start2<br/>";
    $info = $this->db->select('*')->from($this->table_name)->where('id', 1)->get()->row_array();
    echo date('Y-m-d H:i:s')."select-end2<br/>";
    var_dump($info);
    //睡上8秒
    sleep(8);
    echo date('Y-m-d H:i:s')."事务提交的时间<br/>";
    $this->db->trans_commit();


     

事务2

$cc = $this->db->query("select @@session.tx_isolation;")->row_array();
var_dump($cc);
echo '第二个事务<br/>';
echo date('Y-m-d H:i:s')."start0<br/>";
$this->db->trans_begin();
echo date('Y-m-d H:i:s')."end0<br/>";

//查询id=1记录对应的password的值
echo date('Y-m-d H:i:s')."start1<br/>";
$info = $this->db->select('*')->from($this->table_name)->where('id', 1)->get()->row_array();
echo date('Y-m-d H:i:s')."end1<br/>";
var_dump($info);

//睡上12秒(等待第一个事务提交后再执行)
sleep(12);

//再次查询id=1记录对应的password的值
echo date('Y-m-d H:i:s')."start2<br/>";
$info = $this->db->select('*')->from($this->table_name)->where('id', 1)->get()->row_array();
echo date('Y-m-d H:i:s')."end2<br/>";
var_dump($info);
$this->db->trans_commit();

  • 一 读未提交

  • 先把mysql的隔离级别改成:读未提交

  • SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;#修改全局的事务隔离级别SQL语句
    select @@session.tx_isolation;#查看mysql的隔离级别

image.png

    同时运行上面2个事务

image.png

可以看到第一个事务的update操作没提交前(事务提交时间:2023-02-20 01:23:18),事务2(读取的时间点:2023-02-20 01:23:11)已经读取到了事务1修改后的值。

二 读已提交

设置当前隔离级别为:读已提交

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
select @@session.tx_isolation;

1676869253691.png



可以看到第一个事务修改后的值提交hou,第二个事务也能查到第一个事务修改后的值.

三 可重复读

SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
select @@session.tx_isolation;


1676869554660.png

从图可以看到,两个事务第一查询的时候都是:888,第一个事务把值改成484,提交后,第二个事务第2次查询到的值还是原来的值:888,而不是第一个事务修改后的值:484.

四 串行化(serializable)

2个事务,如果都是读操作,2个事务不冲突,就不用等另外一个事务执行完后再执行.如果其中有一个事务有写操作的.只有读操作的事务必须等待有写操作的事务执行完后再执行。如果有多个事务进行写操作,那只会有一个事务的写操作成功.其它写操作的事务会报 Deadlock found when trying to get lock; try restarting transaction


发表评论

评论列表