MySQL 中的事务

75 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情

Snipaste_2022-12-12_20-46-45.jpg 首先介绍一下什么是事务 举个很简单的例子:转账问题
张三向某网红女主播的微信转了 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);
}

出现报错:

Snipaste_2022-12-12_20-38-27.jpg 但是数据库中 张三缺少了521,但是网红女主播却没有多521;

Snipaste_2022-12-12_20-44-04.jpg

如果开启了事务,还是会报错,但是再一次查询数据库时,会发现数据库变成了这样

Snipaste_2022-12-22_20-44-04.jpg