开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情
首先介绍一下什么是事务
举个很简单的例子:转账问题
张三向某网红女主播的微信转了 521 块钱,在余额充足的情况下张三的微信余额会少 521 元,而网红女主播则会多 521 元,接着网红女主播就可以用这 521 元开开心心地购物去了。但是假设:某一次微信扣了张三 521 块钱之后,同时微信的后台服务器就停电关机了,而没有给网红女主播加上 521元,而张三发现却少了 521 元。所以微信必须有一个机制能够保证转账之后双方账户余额总额不变,要是宕机了,就必须保证重启后能还给张三521 块钱,这就引出了事务的概念。
事务:
事务(Transaction)是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序,事务是恢复和并发控制的基本单位。
事务的特性:ACID特性
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
下面小编用代码演示转账问题
@Test
public void testAccount() throws Exception {
Connection conn = null;
PreparedStatement ps = null;
ResultSet result = null;
try{
//先查询帐户是否有521
String sql = "select * from account where name = ? and Money >= ?";
conn = DBUtils.getConnection();
//将事务设置为手动提交
conn.setAutoCommit(false);
ps = conn.prepareStatement(sql);
ps.setString(1, "张三");
ps.setInt(2, 521);
result = ps.executeQuery();
if(!result.next()){
throw new RuntimeException("您的余额不足");
}
//扣除A账户10000
sql = "update account set Money= Money - ? where name = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 521);
ps.setString(2, "张三");
ps.executeUpdate();
//模拟中途断电异常或者服务器宕机
System.out.println(1/0);
//B账户增加521
sql = "update account set Money = Money + ? where name = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 521);
ps.setString(2, "女主播");
ps.executeUpdate();
conn.commit();//提交(要整个事务都完成才能提交,因为提交之后就不能改变了)
}catch(Exception e){
e.printStackTrace();
conn.rollback();
}
DBUtils.close(conn, ps, result);
}
出现报错:
但是数据库中 张三缺少了521,但是网红女主播却没有多521;
如果开启了事务,还是会报错,但是再一次查询数据库时,会发现数据库变成了这样