MySQL事务

78 阅读5分钟

事务的定义: 指作为单个逻辑工作单元(一个最小的不可再分的工作单元)执行的一系列操作,要么完全地执行,要么完全地不执行。

事务四大特征:

  • 原子性(A):事务是最小单位,不可再分
  • 一致性(C):事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败
  • 隔离性(I):事务A和事务B之间具有隔离性
  • 持久性(D):是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)

事务的并发问题:

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

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

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

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

事务隔离性特征之事务隔离级别:

事务的隔离性定义了四大隔离级别,分别是:

1、 读未提交:read uncommitted

2、 读已提交:read committed

3、 可重复读:repeatable read

4、 串行化:serializable

读未提交1. 事物A和事物B,事物A未提交的数据,事物B可以读取到 2. 这里读取到的数据叫做“脏数据” 3. 这种隔离级别最低,这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别
读已提交1. 事物A和事物B,事物A提交的数据,事物B才能读取到 2. 这种隔离级别高于读未提交 3. 换句话说,对方事物提交之后的数据,我当前事物才能读取到 4. 这种级别可以避免“脏数据” 5. 这种隔离级别会导致“不可重复读取” 6. Oracle默认隔离级别
可重复读1. 事务A和事务B,事务A提交之后的数据,事务B读取不到 2. 事务B是可重复读取数据 3. 这种隔离级别高于读已提交 4. 换句话说,对方提交之后的数据,我还是读取不到 5. 这种隔离级别可以避免“不可重复读取”,达到可重复读取 6. 比如1点和2点读到数据是同一个 7. MySQL默认级别 8. 虽然可以达到可重复读取,但是会导致“幻像读”
串行化1. 事务A和事务B,事务A在操作数据库时,事务B只能排队等待 2 这种隔离级别很少使用,吞吐量太低,用户体验差 3. 这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发。注意:这里的排队等待是指在操作一张表时串行化会给被操作的表加表锁而不是针对数据库加锁。

设置及查看事务隔离级别:

1. 设置事务隔离级别

注意:设置数据库的隔离级别一定要是在开启事务之前!

方式一

可以在my.ini文件中使用transaction-isolation选项来设置服务器的缺省事务隔离级别。

该选项值可以是:

image.png

方式二:

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

隔离级别也可以在运行的服务器中动态设置,应使用SET TRANSACTION ISOLATION LEVEL语句。

其语法模式为:

image.png

如果是使用JDBC对数据库的事务设置隔离级别的话,也应该是在调用Connection对象的setAutoCommit(false)方法之前。调用Connection对象的setTransactionIsolation(level)即可设置当前链接的隔离级别,至于参数level,可以使用Connection对象的字段:

image.png

在JDBC中设置隔离级别的部分代码:

image.png 后记:隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。

2. 查看事务隔离级别

image.png

3. 事务隔离级别和一致性关系:

image.png

需要注意的面试题:

  1. 对于mysql来说只有innodb引擎才支持事务,最常用

  2. 使用spring配置事务时,查询方法需要注解readOnly=true,这样的效率会比较高。

@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=true)// 其他方法都需要注解readOnly=false