为什么需要事务:
示例:银行转账问题(假定资金从账户Jacky转到账户Tom),至少需要两步:
- 账户Jacky的资金减少
- 然后账户Tom的资金相应增加
-- 1:创建账户表
drop table if exists accountUser;
create table accountUser
(
uno varchar(50) primary key,
uname varchar(50),
money MONEY check(money>=0)
);
-- 2:创建账户明细表
drop table if exists accountDetail;
create table accountDetail
(
uno varchar(50),
opType varchar(50),
money MONEY,
createTime datetime year to second default current year to second
);
-- 插入数据
insert into accountUser(uno,uname,money) values('001','Jacky',1000);
insert into accountUser(uno,uname,money) values('002','Tom',100);
insert into accountDetail(uno,opType,Money) values('001','deposit',1000);
insert into accountDetail(uno,opType,Money) values('002','deposit',100);
-- 查看数据
select uno,uname,money from accountUser;
select uno,opType,Money,createTime from accountDetail;
执行createInit.sql
# dbaccess demoDB createInit.sql
看到如下信息:
创建transfer.sql文件,执行转账业务
update accountUser set money=money-600 where uno='001';
insert into accountDetail(uno,opType,Money) values('001','withdrawal',600);
update accountUser set money=money+600 where uno='002';
insert into accountDetail(uno,opType,Money) values('002','deposit',600);
-- 查看数据
select uno,uname,money from accountUser;
select uno,opType,Money,createTime from accountDetail;
执行transfer.sql# dbaccess demoDB transfer.sql
第一次执行,结果如图:
第二次执行,结果如图:
发现:Jacky的账户已经不够金额进行转账了,出现了check约束异常,但是,转账业务还是继续执行,导致总金额错误。
所以,为了防止数据库中数据的不一致性,需要使用事务处理。
什么是事务:
事务(Transaction):是指作为单个逻辑工作单元可以确保除非事务性单元内的所有操作都成功完成,否则不会执行的一系列操作。
事务处理永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功,要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。
事务只有在提交(COMMIT)后,对数据库的更改才可以永久保持;事务在回滚(ROLLBACK)后,将事务未提交的操作恢复到事务开始的状态。
事务的ACID特性:
A:Atomicity(完整性,原子性。操作序列要么完整的执行,否则什么也不做)
C:Consistency(一致性,事务执行后,保证数据库从一个一致性状态到另外一个一致性状态。准确,完整)
I:Isolation(隔离,一个事务的中间状态对其他事务不可见。每个用户感觉他们是在单独使用数据库)
D:Durability(持久性,事务的有效性,不会应用硬件或者软件的失败而丢失)
解决上述示例问题:
创建存储过程,在事务中,使用异常处理判断commit还是rollback:
drop procedure if exists sp_transfer;
create procedure sp_transfer()
on exception in (-530)
rollback work;
end exception;
begin work;
update accountUser set money=money-600 where uno='001';
insert into accountDetail(uno,opType,Money) values('001','withdrawal',600);
update accountUser set money=money+600 where uno='002';
insert into accountDetail(uno,opType,Money) values('002','deposit',600);
commit work;
end procedure;