事务简介
- 事务:是指一组操作的集合,他是一个不可分割的单位,事务会把这些所有的操作作为一个整体一起向系统提交或者撤销操作请求,即这些操作要么同时成功,要么同时失败,以保证数据的完整和一致性
事务操作
- 开始事务(Begin Transaction)
这是事务的起始点,标志着一系列操作将作为一个事务来处理。在这个阶段,系统会为该事务分配必要的资源,准备记录事务执行过程中的相关信息,如操作日志等,以便后续对事务进行控制和管理。 - 执行操作(Perform Operations)
在事务内部,可以包含对数据的读取、修改、插入和删除等各种操作。这些操作按照程序设计的逻辑顺序依次执行,并且在执行过程中,系统会根据事务的特性来保障数据的安全性和一致性。 - 提交事务(Commit Transaction)
当事务中的所有操作都成功执行完成后,通过提交事务将对数据所做的修改永久保存到数据库或存储系统中。此时,事务对数据的更新将对其他事务可见(取决于事务隔离级别),系统会释放事务占用的资源。 - 回滚事务(Rollback Transaction)
如果在事务执行过程中发生了错误,或者由于某种原因需要取消事务,就会执行回滚操作。回滚会将数据恢复到事务开始之前的状态,撤销在事务中已经执行的所有操作,以确保数据的一致性,同时释放事务占用的资源。
事务的四大特性(ACID)
- 事务的四大特性主要是原子性、一致性、隔离性和持久性,A(原子性)I(隔离性)D(持久性)三个主要为了保证C(一致性),确保数据的一致性
- 原子性(Atomicity)
事务是数据库操作的基本单位,原子性确保事务中的所有操作要么全部执行成功,要么全部失败回滚。就像一个原子一样,不可再分割,不存在部分完成的情况。- 例如,在银行转账事务中,从一个账户扣款和向另一个账户收款这两个操作必须同时成功或同时失败,不能出现只完成其中一个操作的情况,否则会导致数据不一致。
- 一致性(Consistency)
事务在开始和结束时,数据库的完整性约束没有被破坏。即事务必须使数据库从一个一致性状态变换到另一个一致性状态。- 例如,在数据库中存在账户余额总和的约束,转账事务完成后,账户余额总和应该保持不变。一致性通过原子性、隔离性和持久性共同保证。
- 隔离性(Isolation)
多个事务并发执行时,一个事务的执行不能被其他事务干扰。每个事务都应该感觉不到有其他事务在并发执行,就好像只有自己在操作数据库一样。不同的事务隔离级别决定了事务之间的相互影响程度,后面会详细介绍。- 例如,两个并发的转账事务,它们在各自的执行过程中应该不受对方的影响,以保证数据的准确性。
- 持久性(Durability)
一旦事务提交成功,它对数据库中数据的修改应该是永久性的,即使系统出现故障(如断电、崩溃等),数据也不会丢失。数据库系统通过日志记录、备份恢复等机制来保证持久性。- 例如,当一笔转账事务提交后,即使数据库服务器突然断电重启,转账的结果也应该被持久保存。
- 原子性(Atomicity)
并发事务问题
在并发事务环境中,可能会出现以下几种问题:
- 脏读(Dirty Read):一个事务读取了另一个事务还未提交的修改数据,此时若被读取的事务回滚,则读取到的数据是无效的,称为“脏数据”。
- 不可重复读(Unrepeatable Read):一个事务在读取数据后,另一个事务对数据进行了修改并提交,导致第一个事务再次读取数据时,获取到的数据与之前读取的不一致。
- 幻读(Phantom Read):一个事务在读取某个范围的数据后,另一个事务在该范围内插入了新的数据并提交,导致第一个事务在后续查询中,发现之前未出现的新数据,就像出现了“幻觉”一样。
事务隔离级别
四种事务隔离级别
事务的隔离级别决定了事务之间的相互影响程度,SQL标准定义了四种隔离级别,从低到高依次为:
-
读未提交(Read Uncommitted):
- 允许一个事务读取另一个事务尚未提交的数据。
- 可能会导致脏读、不可重复读和幻读等问题。
- 这种隔离级别虽然提高了并发性,但数据一致性较差。
-
读已提交(Read Committed):
- 允许一个事务只读取已经提交的数据。
- 可以解决脏读问题,但可能会导致不可重复读和幻读问题。
- 这种隔离级别在读取数据时,能够确保数据已经提交,因此提高了数据的一致性。oracle默认是这种隔离级别。
-
可重复读(Repeatable Read):
- 保证一个事务多次读取同一数据集时,结果是一致的。
- 可以解决脏读和不可重复读问题,但仍然可能会出现幻读问题。
- MySQL的InnoDB存储引擎默认使用该隔离级别,并通过Next-Key Lock锁算法来避免幻读的产生(在特定条件下)。
-
串行化(Serializable):
- 最高的隔离级别,强制所有事务串行执行。
- 可以避免所有并发访问问题,包括脏读、不可重复读和幻读。
- 但这种隔离级别会对性能产生较大的影响,因为它会导致大量的锁竞争。
-
查看事务隔离级别
- select @@tx_isolation;(查看当前数据库的隔离级别)
- select @@global.transaction_isolation;(查看全局事务隔离级别)
- select @@session.transaction_isolation;(查看会话事务隔离级别)
-
设置事务隔离级别
- 对于MySQL数据库,可以用下面命令
- --设置会话级别的事务隔离级别为READCOMMITTED
- set session transaction isolation level READ COMMITTED;
- --设置会话级别的事务隔离级别为REPEATABLE READ(MySQL默认)
- set session transaction isolation level REPEATABLE READ;
- --设置会话级别的事务隔离级别为SERIALIZABLE
- set session transaction isolation level SERIALIZABL;
- --设置会话级别的事务隔离级别为READCOMMITTED
- 对于SQL Server,可以使用以下命令
- --设置会话级别的事务隔离级别为READUNCOMMITTED
- set transaction isolation level READ COMMITTED;
- --设置会话级别的事务隔离级别为READ COMMITTED(SQL Server默认)
- set transaction isolation level READ COMMITTED;
- --设置会话级别的事务隔离级别为REPEATABLEREAD
- set transaction isolation level REPEATABLEREAD;
- --设置会话级别的事务隔离级别为SERIALIZABLE
- set transaction isolation level SERIALIZABLE;
- --设置会话级别的事务隔离级别为SNAPSHOT(SQLServer特有的隔离级别)
- set transaction isolation level SNAPSHOT;
- --设置会话级别的事务隔离级别为READUNCOMMITTED
- 对于MySQL数据库,可以用下面命令
-
选择事务隔离级别的考虑因素
- 数据一致性要求:如果应用程序需要保证数据的一致性,那么需要选择较高的隔离级别。
- 并发访问的复杂性:如果应用程序的并发访问较为复杂,那么需要选择较高的隔离级别以减少并发问题。如果并发访问较少,那么可以选择较低的隔离级别以提高性能。
- 性能需求:如果应用程序对性能要求较高,那么需要选择较低的隔离级别以减少锁竞争和等待时间。
- 数据库的大小:对于大型数据库,选择串行化隔离级别可能会导致大量的锁竞争和性能下降。因此,在大型数据库中,应谨慎选择隔离级别。