1. 什么是事务?
事务是一个最小的不可再分的工作单元,是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败。事务只和 DML 语句有关,或者说 DML 语句才有事务。
2. 事务的一些使用方法
- 想使用事务首先需要开启事务,开启事务有两种方式:
//通过 sql语句手动开启 start transaction; //自动开启事务,当返回的 autocommit 的值为 OFF 是表示事务已经自动开启了 set autocommit=0; show VARIABLES like 'autocommit';
- 在开启事务之后,我们就需要使用事务:当开启了事务之后执行任何一条DML语句就已经开始了使用事务了。具体的使用过程:假设有两条 DML 语句同时执行,当第一条 DML 语句执行成功后,并没有对底层数据库中数据进行修改,只是将操作记录了一下,这个记录是在内存中完成的;当第二条DML语句执行成功后,和底层数据库文件中的数据完成同步。若第二条DML语句执行失败,则清空所有的历史操作记录,这就是事务。
- 事务的提交:事务的提交有有两种可能,第一种当所有的 DML 语句全部执行完成,第二种提交事务是使用 SQL 语句:
commit;
,在事务提交之后事务就自动关闭了 - 事务的回滚:回滚就是当前事务执行的 DML 语句全部失效,并且关闭事务。的事务回滚的 SQL 语句为:
ROLLBACK;
3. 事务的特性(ACID)
-
原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
-
一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
-
隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
-
持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
4. 事务的隔离级别
多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发虽然是必须的,但可能会导致以下的问题:
-
脏读(Dirty reads):事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。
-
不可重复读(Nonrepeatable read):事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,然后事务A再次读取的时候,发现数据不匹配了,就是所谓的不可重复读了
-
幻读(Phantom read):事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。
可以通过设置事务的隔离级别的对上述问题进行解决,事务的隔离级别有四种:
-
读未提交(read uncommitted):事物A和事物B,事物A未提交的数据,事物B可以读取到,这里读取到的数据叫做“脏数据”
,这种隔离级别最低,这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别。 -
读已提交(read committed): 事物A和事物B,事物A提交的数据,事物B才能读取到,这种隔离级别高于读未提交。换句话说,对方事物提交之后的数据,我当前事物才能读取到,这种级别可以避免“脏数据”,这种隔离级别会导致“不可重复读取”。
-
可重复读(repeatable read):事务A和事务B,事务A提交之后的数据,事务B读取不到,事务B是可重复读取数据。这种隔离级别高于读已提交。换句话说,对方提交之后的数据,我还是读取不到,这种隔离级别可以避免“不可重复读取”,达到可重复读取,但是会导致“幻像读”
-
串行化(serializable):事务A和事务B,事务A在操作数据库时,事务B只能排队等待。这种隔离级别很少使用,吞吐量太低,用户体验差,这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发
5. 设置隔离级别
- 通过配置文件设置:在
my.ini
文件中使用用transaction-isolation
选项来设置服务器的缺省事务隔离级别,该选项的值可以为:READ-UNCOMMITTED 、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE
。 - 通过命令动态设置隔离级别:
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL <隔离级别>
;
6. 隔离范围
事务隔离级别的作用范围分为两种:
- 全局级:对所有的会话有效
- 会话级:只对当前的会话有效
在设置隔离级别是使用配置文件方式那么默认为全局级,如果使用动态命令的方式则可以通过动态命令进行规定:
-- 设置会话级隔离级别
SET [SESSION] TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 设置全局级隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 查询会话级隔离界别
select @@tx_isolation;
-- 查询全局级隔离界别
select @@global.tx_isolation;
那么 MySQL的事务就简单了解到这里,这篇博客主要是为了后面学习 Spring 事务做准备。