简介
事务(Transaction)是指数据库管理系统(DBMS)中执行的一个操作序列,这些操作要么全部成功执行,要么全部不执行,且在执行过程中保持数据的一致性。
例如:
张三给李四转账,张三账户余额少1000,而李四账户余额增加1000。这一组操作必须在一个事务范围内,要么都成功,要么都失败。
事务操作
首先我们拥有一个数据库my_db
创建数据表account
,插入数据
-- 首先删除表(如果存在)
DROP TABLE IF EXISTS account;
-- 创建表
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID',
name VARCHAR(10) COMMENT '姓名',
money DOUBLE(10,2) COMMENT '余额'
) COMMENT '账户表';
insert into account(name, money) VALUES ('张三',2000), ('李四',2000);
未控制事务
正常情况
-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';
异常情况
把数据都恢复到2000, 然后再次一次性执行上述的SQL语句,中间添加文本 程序异常...
模拟操作出现异常的情况
恢复数据
update account set money =2000 where name = '张三' or name = '李四'
-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money -1000 where name = '张三';
程序异常...
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';
张三的钱没了,李四的钱也没有加上
控制事务
(正常情况)
再次将数据恢复到初始状态
update account set money =2000 where name = '张三' or name = '李四'
查看当前事务提交方式,为1是自动提交
select @@autocommit;
设置为手动提交
set @@autocommit = 0;
这样我们的sql就不会自动提交会变为手动提交
再次执行正常情况下的sql语句
我们还没有提交,所以再次查看时数据并没有变化
-- 提交事务
commit
提交后再次查看
(异常情况)
数据恢复到初始状态
update account set money =2000 where name = '张三' or name = '李四'
commit
执行异常情况下的sql语句
一旦执行出错,我们就需要回滚事务
-- 回滚事务
rollback ;
还有一种开启事务的方法
-- 开启事务
START TRANSACTION 或 BEGIN ;
事务特性
原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立
环境下运行。
持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
并发事务问题
脏读:一个事务读到另一个事务还没有提交的数据 (事务B读取到了A未提交的数据)
不可重复读: 一个事务先后读取同一条记录,但两次读取的数据不同,称为不可重复读(事务A两次读取同一条数据,但是读取到的数据却是不一样的。)
幻读: 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,又发现这行数据已经存在,好像出现幻影
隔离级别
- 读未提交(Read Uncommitted):在这个级别下,一个事务可以读取另一个事务未提交的数据。这意味着一个事务可能会看到其他事务的中间结果。这种隔离级别最低,可能导致脏读、不可重复读和幻读问题。
- 读已提交(Read Committed):这是大多数数据库系统默认的隔离级别。在这个级别下,一个事务只能读取到已经提交的数据。这避免了脏读问题,但是仍然可能出现不可重复读和幻读问题。
- 可重复读(Repeatable Read):在这个级别下,一个事务在执行期间多次读取相同的数据,将会看到同样的结果,即使其他事务已经对该数据进行了更新并提交。这可以避免脏读和不可重复读问题,但仍然可能出现幻读问题。
- 串行化(Serializable):这是最高的隔离级别。在这个级别下,所有的事务按照串行化的方式执行,因此可以避免脏读、不可重复读和幻读问题。但是,由于串行化执行会导致性能下降,因此一般情况下不建议使用这个隔离级别,除非特别需要确保数据的完整性和一致性。
-- 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
MySQL默认的隔离级别是可重复读
-- 当前会话设置隔离级别
set session transaction isolation level read uncommitted ;
-- 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;