Mysql数据库事务

定义

  • 事务:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务。
  • 一个完整的业务需要批量的DML(insert,update,delete)语句共同联合完成。
  • 事务只和DML语句有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同

事务的四大特征

  • 原子性(A):事务是最小的单位,不可再分。
  • 一致性(C):事务要求所有的DML语句操作的时候,要么同时成功,要么同时失败。及如果在同一事物中,有一步骤报错,整个事务即将回滚到该事务操作之前的状态。
  • 隔离性(I):事务A和事务B之间具有隔离性。及事务A在同数据a进行操作时,只有事务A结束,事务B才可以对数据a进行操作。
  • 持久性(D):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

对事务的操作术语

  • 开启事务:Start Transaction
  • 事务结束:End Transaction
  • 提交事务:Commit Transaction
  • 回滚事务:Rollback Transaction

事务与数据库底层数据

        在事物进行过程中,未结束之前,DML语句是不会更改底层数据,只是将历史操作记录一下,在内存中完成记录。只有在事物结束的时候,而且是成功的结束的时候,才会修改底层硬盘文件中的数据

设置事务的隔离级别

     一,修改my.ini文件

            使用transaction-isolation选项来设置服务器的缺省事务隔离级别。

READ-UNCOMMITTEDREAD-COMMITTEDREPEATABLE-READSERIALIZABLE

  •	例如:
  [mysqld]
  transaction-isolation = READ-COMMITTED

     二,通过命令动态设置隔离级别

            其语法模式为:

	SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL <isolation-level>
  		其中的<isolation-level>可以是:
  	–	READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE
  	•	例如: SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

隔离级别的作用范围

•	事务隔离级别的作用范围分为两种: 
–	全局级:对所有的会话有效 
–	会话级:只对当前的会话有效 
•	例如,设置会话级隔离级别为READ COMMITTED :
mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
或:
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
•	设置全局级隔离级别为READ COMMITTED : 
mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED

查看隔离级别

- 查看当前会话的隔离界别
-    select @@tx_isolation
- 查看系统的隔离界别
-    select @@global.tx_isolation

并发问题

    脏读

       事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

    不可重复读

       事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

    幻读

       系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

       小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

四大隔离级别

  • 读未提交:read uncommitted
事物A和事物B,事物A未提交的数据,事物B可以读取到这里读取到的数据叫做“脏数据”。这种隔离级别最低,
这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别。
  • 读已提交:read committed
- 事物A和事物B,事物A提交的数据,事物B才能读取到
- 这种隔离级别高于读未提交
- 换句话说,对方事物提交之后的数据,我当前事物才能读取到
- 这种级别可以避免“脏数据”
- 这种隔离级别会导致“不可重复读取”
- Oracle默认隔离级别
  • 可重复读:repeatable read
- 事务A和事务B,事务A提交之后的数据,事务B读取不到
- 事务B是可重复读取数据
- 这种隔离级别高于读已提交
- 换句话说,对方提交之后的数据,我还是读取不到
- 这种隔离级别可以避免“不可重复读取”,达到可重复读取
- 比如1点和2点读到数据是同一个
- MySQL默认级别
- 虽然可以达到可重复读取,但是会导致“幻像读”
  • 串行化:serializable
- 事务A和事务B,事务A提交之后的数据,事务B读取不到
- 事务B是可重复读取数据
- 这种隔离级别高于读已提交
- 换句话说,对方提交之后的数据,我还是读取不到
- 这种隔离级别可以避免“不可重复读取”,达到可重复读取
- 比如1点和2点读到数据是同一个
- MySQL默认级别
- 虽然可以达到可重复读取,但是会导致“幻像读”

在这里插入图片描述

分析四种隔离级别前的准备

创建银行账户表
 create table account(
     id int primary key,
     name varchar(50),
     balance double);
向account表中出入数据
insert into account values (1,'lilei',450),(2,'hanmei',16000),(3,'lucy',2400);

在这里插入图片描述

打开两个CMD窗口,模拟两个客户端一个设置为A一个设置为B

在这里插入图片描述

  • 1,读未提交
        在客户端A的操作
    在这里插入图片描述
        在客户端B的操作,此时A的事务未提交。
    在这里插入图片描述
        完成上图的操作,但是客户端B并未提交事务,现在在客户端A查询数据。
    在这里插入图片描述
        客户端A查询到了客户端更新的未提交事务的数据。如果此时客户端B回滚事务。则客户端A读取到的数据就是脏数据。
    在这里插入图片描述
        在客户端A执行更新语句update account set balance = balance - 50 where id =1,lilei的balance没有变成350,居然是400,是不是很奇怪,数据不一致啊,如果你这么想就太天真 了,在应用程序中,我们会用400-50=350,并不知道其他会话回滚了,要想解决这个问题可以采用读已提交的隔离级别
    在这里插入图片描述
  • 2,读已提交
          打开一个客户端A,并设置当前事务模式为read committed(未提交读),查询表account的所有记录:
    在这里插入图片描述
          在客户端A的事务提交之前,打开另一个客户端B,更新表account:
    在这里插入图片描述
          这时,客户端B的事务还没提交,客户端A不能查询到B已经更新的数据,解决了脏读问题:
    在这里插入图片描述
          客户端B的事务提交
    在这里插入图片描述
           客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题
    在这里插入图片描述
  • 3,可重复读
           打开一个客户端A,并设置当前事务模式为repeatable read,查询表account的所有记录
    在这里插入图片描述
           在客户端A的事务提交之前,打开另一个客户端B,更新表account并提交
    在这里插入图片描述
           在客户端A查询表account的所有记录,与步骤(1)查询结果一致,没有出现不可重复读的问题
    在这里插入图片描述
          在客户端A,接着执行update account set balance = balance - 50 where id = 1,balance没有变成400-50=350,lilei的balance值用的是步骤(2)中的350来算的,所以是300,数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
    在这里插入图片描述
          重新打开客户端B,插入一条新数据后提交
    在这里插入图片描述
          在客户端A查询表account的所有记录,没有 查出 新增数据,所以没有出现幻读
    在这里插入图片描述
  • 4,串行化
           打开一个客户端A,并设置当前事务模式为serializable,查询表account的初始值:
    在这里插入图片描述
           打开一个客户端B,并设置当前事务模式为serializable,插入一条记录报错,表被锁了插入失败,mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。
    在这里插入图片描述
    在这里插入图片描述

参考链接

MySQL的四种事务隔离级别
查看和设置mysql 事务的隔离级别
MySQL——事务(Transaction)详解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL数据库事务是一组数据库操作命令的集合,这些命令要么全部执行成功,要么全部回滚。事务具有以下特性: 1. 原子性(Atomicity):事务的所有操作要么全部成功执行,要么全部回滚,不会出现部分执行的情况。 2. 一致性(Consistency):事务执行后,数据库的状态保持一致,即满足预设的约束条件。 3. 隔离性(Isolation):并发执行的事务之间相互隔离,每个事务都感觉不到其他事务的存在。 4. 持久性(Durability):事务一旦提交,其结果将永久保存在数据库,即使系统发生故障也不会丢失。 在MySQL,可以使用以下语句来控制事务的开始、提交和回滚: 1. 开始事务:`START TRANSACTION;` 或 `BEGIN;` 2. 提交事务:`COMMIT;` 3. 回滚事务:`ROLLBACK;` 以下是一个示例,演示了如何在MySQL使用事务: ```sql -- 开始事务 START TRANSACTION; -- 执行一系列数据库操作命令 INSERT INTO table1 (column1, column2) VALUES ('value1', 'value2'); UPDATE table2 SET column1 = 'new_value' WHERE condition; DELETE FROM table3 WHERE condition; -- 提交事务 COMMIT; ``` 如果在事务执行过程发生了错误,可以使用回滚操作将事务恢复到开始之的状态: ```sql -- 开始事务 START TRANSACTION; -- 执行一系列数据库操作命令 INSERT INTO table1 (column1, column2) VALUES ('value1', 'value2'); UPDATE table2 SET column1 = 'new_value' WHERE condition; DELETE FROM table3 WHERE condition; -- 发生错误,回滚事务 ROLLBACK; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值