文章目录
事务定义
事务是最小的不可分割的工作单元,事务能保证一个业务的完整性
执行一个事务时,事务中只要有一个操作失败,整个事务就会失败
事务例子银行转账系统,先扣费再转账,如果扣费成功了,但是转账失败了,假如扣费是一个事务,转账为一个事务,就会导致程序扣费成功了,但是没有转账成功,这样会造成要取钱的李明(客户)发现资产不翼而飞了。所以我们应该把扣钱和转账看成一个事务来处理。当成一个事务的话,事务中其中一步失败了会导致整个事务失败。
-- 扣费操作
UPDATE user SET money=money-100 WHERE name='张华';
-- 转账操作
UPDATE user SET monry=monry+100 WHERE name='李明';
事务四大特征
-
A(automicity 原子性)
事务所有操作在数据库中反映出来
即全部成功或全部失败
-
C(consistency 一致性)
事务中的操作必须保证数据库中数据的一致性
即执行之后不能让一方少了 2000 块,另一方多了 1000 块,要保证数据的一致
-
I(isolation 隔离性)
两个事务之间具有隔离性
mysql 事务的四大隔离级别
-
D(durability 耐久性)
事务一旦结束,比如 commit 后就无法再回滚了
事务一旦提交就会持久性存储在磁盘中,提交前存储在内存中
autocommit
mysql 默认是有事务的,autocommit=1 表示自动提交,我们来查看一下 mysql 默认提交事务与否
SELECT @@autocommit;
mysql 设置默认事务不自动提交如下
SET autocommit=0;
只有设置为不自动提交的时候,可以用 rollback 回滚
ROLLBACK;
不设置为默认提交,可以通过 commit 来提交数据
commit;
BEGIN
使用begin;
开启事务,如下语句一起去执行之后,是把下面看成一个事务,并且可以通过 roolback 回滚,实际中这种比较常用
BEGIN;
UPDATE user SET money=money-100 WHERE name='张华';
UPDATE user SET monry=monry+100 WHERE name='李明';
START TRANSACTION
使用start transaction;
下面语句一起去执行后也一样起到事务的效果,rollback 一块回滚,实际中这种比较常用
START TRANSACTION;
UPDATE user SET money=money-100 WHERE name='张华';
UPDATE user SET monry=monry+100 WHERE name='李明';
我们最后一旦 commit 了事务就无法回滚了
事务隔离级别的设置查询事务隔离级别,设置全局后当前事务会话级不会影响,设置会话级后全局事务不会影响
-- 全局事务查询
SELECT @@global.tx_isolation;
-- 会话级事务查询
SELECT @@tx_isolation;
SELECT @@SESSION.tx_isolation;
修改事务隔离级别,下面以读提交举例,其他的隔离级别设置在下面标题内容中有写
-- 设置全局的事物隔离级别为读提交
SET global transaction isolation level READ UNCOMMITTED;
-- 设置会话级
SET session transaction isolation level READ UNCOMMITTED;
事务四种隔离级别
查看数据库事务的隔离级别
-- MYSQL5.6
-- 系统级别
SELECT @@global.tx_isolation;
-- 会话级别
SELECT @@tx_isolation;
-- MYSQL8.0
-- 系统级别
SELECT @@GLOBAL.TRANSACTION_ISOLATION;
-- 事务级别
SELECT @@transaction_isolation;
mysql 事务的默认隔离级别为 pepeatable read(重复读,可能产生幻读的问题)
读未提交 READ UNCOMMITTED(产生脏读的问题)
并发事务提交前可读,且可写
此隔离级别表示允许一个事务允许读到另一个事务未提交的数据
脏读,两边事务开启,一个事务中读到了另一个事务未提交的数据,实际开发中是不允许脏读出现的!
修改 MYSQL8.0 的隔离级别为 read uncommitted
SET global transaction isolation level READ UNCOMMITTED;
读提交 READ COMMITTED(产生不可重复读的问题)
并发事务提交后可读,且可写
此隔离级别表示允许一个事务允许读到另一个事务已提交的数据
对于读未提交的隔离级别是在提交前就能读取数据, 那现在读提交的隔离级设置成了提交后另一个事务才可读,但是这样会产生不可重复读的问题,比如一个事务中两次读取,但是两次读之间其他事务操作同样的数据并提交,这样第一个事务两次读的数据不一致,操作就会出现问题
修改 MYSQL8.0 的隔离级别为 read committed
SET global transaction isolation level READ COMMITTED;
重复读 REPEATABLE READ(产生幻读的问题)
并发事务可写不可读
此隔离级别表示允许一个事务不会读到另一边的事物提交的数据,但是这边事务在操作数据库时候可能会产生冲突的异常
既然读提交会导致一个事务中两次读取数据不一致,那我们这样,在第一个事务中读取不到第二个事务提交的数据,这样第一个事务两次读取都是一样的,但是会产生幻读,就是第二次读取到的数据虽然是某个值,但是实际它已经改变了,这就是幻读
修改 MYSQL8.0 的隔离级别为 repeatable read,这个也是 mysql 默认的事物隔离级别
SET global transaction isolation level REPEATABLE READ;
串行化 SERIALIZABLE
并发事务不可读不可写
串行化,当表被一个事务操作的时候(提交之前),其他事务在里头的操作是不可进行的,会进入排队状态。串行化会出现一个问题就是性能很差
修改 MYSQL8.0 的隔离级别为 serializable
SET global transaction isolation level SERIALIZABLE;
性能比较
read uncommitted(脏读) 好于 read committed(不可重复读) 好于 repeatable read(幻读) 好于 serializable(串行化)
实际项目中的事务-
mysql 默认是重复读,但实际项目中很多使用的确是读提交(oracle 默认事务就是读提交),而不会采用读未提交和串行化,这是为什么呢?
答:读未提交肯定不行,读到了别人没有提交的数据。串行化的话每次事务操作操作就被锁住性能太低了
-
为什么我们不采用 mysql 默认的重复读做项目隔离级别呢?
答:①因为读提交的重复读问题我们本身是可以接收的,不需要解决,就是事务中读到了另一个事务修改后的数据,读出来本身没有大问题
-
为什么 mysql 默认隔离级别是重复读?
答:大致就是之前的版本数据库低的模式有 bug 存在
一般数据库会采用读提交作为默认的事物隔离级别,比如 oracle,sql server,但是 mysql 的隔离级别却是重复读,