事务
一、事务的概述:
1、事务处理(事务操作):保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。
- 提交(commit):表示确定执行事务中所有的操作
- 回滚(rollback):表示将数据恢复到事务执行之前
- MySQL中,一个SQL语句独占一个事务,且默认自动提交
- MySQL中,若一个事务不是提交或回滚结束,默认会回滚
- 事务只针对于DML(增删改)有效,对DDL无效
2、事务的ACID属性:
- 原子性(Atomicity):指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency): 事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
- 隔离性(Isolation): 一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。
- 持久性(Durability): 一个事务一旦被提交,它对数据库中数据的改变是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
二、开启和结束事务
开启事务的两种方式:
- Set autocommit =false; 当使用此方式,该方式针对当前连接中的所有操作,即设置了"set autocommit = false;"之后,所有的操作必须手动设置提交或回滚
- start transaction; 开启一个短暂的事务,每个事务都会"start transaction;"开始,以提交或回滚结束;之后的操作仍然是自动提交
三、事务隔离级别
1、事务并发问题
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
- 脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段。 之后, 若 T2 回滚, T1读取的内容就是临时且无效的。
- 不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段。 之后, T1再次读取同一个字段, 值就不同了。
- 幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入/删除了一些新的行。 之后, 如果 T1 再次读取同一个表, 就会多/少几行。
2、事务隔离级别
数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。**一个事务与其他事务隔离的程度称为隔离级别。**数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。
数据库提供的 4 种事务隔离级别:
隔离级别 | 描述 |
---|---|
read-uncommitted 读未提交 | 允许A事务读取其他事务未提交和已提交的数据。会出现脏读、不可重复读、幻读问题 |
read-committed 读已提交 | 只允许A事务读取其他事务已提交的数据。可以避免脏读,但仍然会出现不可重复读、幻读问题 |
repeatable-read 可重复读(默认) | 确保事务可以多次从一个字段中读取相同的值。在这个事务持续期间,禁止其他事务对这个字段进行更新。可以避免脏读和不可重复读。但是幻读问题仍然存在。注意:mysql中使用了MVCC多版本控制技术,在这个级别也可以避免幻读,即在当前的事务中只能看到自己事务中执行的结果 |
serializable 序列化 | 确保事务可以从一个表中读取相同的行,相同的记录。在这个事务持续期间,禁止其他事务对该表执行插入、更新、删除操作。所有并发问题都可以避免,但性能十分低下。 |
3、设置和查看隔离级别
设置数据库的隔离级别一定要是在开启事务之前
每启动一个 mysql 程序, 就会获得一个单独的数据库连接。 每个数据库连接都有一个变量 @@transaction_isolation, 表示当前连接的事务隔离级别。mysql服务也有一个全局变量@@global.transaction_isolation,表示所有连接的默认事务隔离级别。
- 查看当前mysql连接的隔离级别:
mysql 5 是:select @@tx_isolation;
mysql 8 是:select @@transaction_isolation;
- 查看全局的隔离级别:
mysql 5 是:select @@global.tx_isolation;
mysql 8 是:select @@global.transaction_isolation;
- 设置当前 mysql连接的隔离级别:
mysql 5 是:
set tx_isolation =‘read-uncommitted’;
set tx_isolation =‘read-committed’;
set tx_isolation =‘repeatable-read’;
mysql 8 是:
set transaction_isolation =‘read-uncommitted’;
set transaction_isolation =‘read-committed’;
set transaction_isolation =‘repeatable-read’;
- 设置数据库系统的全局的隔离级别:
mysql 5:set global tx_isolation =‘read-committed’;
mysql 8 : set global transaction_isolation =‘read-committed’;
注意:这里的隔离级别中间是减号,不是下划线。
- JDBC中设置隔离级别:
隔离级别的设置只对当前连接有效,对于使用MYSQL命令窗口而言,一个窗口就相当于一个连接,当前窗口设置的隔离级别只对当前窗口中的事务有效,对于JDBC操作数据库来说,一个Connection对象相当与一个连接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他连接Connection对象无关