数据库:事务详析

一、数据准备

为了更好地讲解事务,先建个表插入一些数据:

create table account(
id char(36) primary key,
card_id varchar(20) unique,
name varchar(8) not null,
money float(10,2) default 0
);
insert into account 
values('6ab71673-9502-44ba-8db0-7f625f17a67d','1234567890','张三',1000);
insert into account (id,card_id,name) 
values('9883a53d-9127-4a9a-bdcb-96cf87afe831','0987654321','张三');

二、解释过程

当执行一组DML操作时,为了确保数据的一致性,避免数据库产生错误数据,就需要通过事务(Transaction)使该组DML操作同时成功或失败,例如:张三有两张银行卡,卡号分别是1234567890和0987654321,现从1234567890卡取出100块钱转到0987654321卡,则取出钱的卡需要减去100,转入卡需要增加100,现实生活中这两个update操作必须同时成功同时失败,如下操作:

#要求update操作同时成功同时失败
update account set money=money-100 where card_id= '1234567890';
update account set money=money+100 where card_id= '0987654321';
#这里两条SQL语句的方法实现赚钱功能,但如果其中一条语句出错就会导致资金总额出现改变,这明显是不允许的

注:MySQL数据库默认以单独的一个DML为一个事务

为了更好地分析事务是如何作用的,这里用手动启动关闭事务的方式来讲解他的作用(第一个是提交事务):

set autocommit=0;
#开启事务,在事务结束之前所有DML处于同一个事务之中
update account set money=money-100 where card_id='1234567890';
update account set money=ey+100 where card_id='0987654321';
#明显可以看出,这条sql语句是出错的,也就是没法执行money+100的操作,但上一条语句中money-100的操作却执行了
commit;
#提交事务,讲DML语句执行的结果持久化到磁盘
select * from account;

这里是回滚事务:

set autocommit=0;
#开启事务,在事务结束之前所有DML处于同一个事务之中
update account set money=money-100 where card_id='1234567890';
update account set money=ey+100 where card_id='0987654321';
rollback;
#回滚事务,撤销之前的有效操作并结束事务(也就是这一组事务的操作都无效化)

其他结束事务的方法:

1、执行了DDL语句(如建表语句)或DCL语句(如给用户授权),相当于执行了commit

2、数据库客户端程序退出或数据库崩溃时,为了保持数据一致性,也会结束事务。

事务进行中需要了解的情况:

执行DML语句且没有结束事务时,如果需要查询数据库的真实改变情况,则要求在一个新的SQL Window窗口中执行查询语句:因为事务中所做的每一个操作在事务被提交之前都是临时的,在commit或rollback语句执行之前,DML语句首先影响该用户的数据库缓冲区,因为这些操作可以被恢复,而且因为是在该用户的数据缓冲区,所以在原SQL窗口中查询得到的是数据缓冲区的结果,不是数据库真实的数据;要想拿到数据库真实的数据,需要在新SQL窗口中执行查询语句,这样针对不同的用户,MySQL服务器用读一致性来确保每个用户看到的数据和上次提交时的数据相同。

总结:
这里用手动启动关闭事务的方式只是为了方便来解释事务的原理与运作方式,但实际应用是不会出现这样的情况,开启和关闭一定会在同一组代码中被实现的,这里特别说明,也为了下一章讲JDBC中事务的实际应用做铺垫。

三、JDBC中事务的执行

public class Test {
	public static void main(String[] args) {
		Connection connection = null;
		Statement statement = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			//1、加载驱动
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "root");
			//2、建立连接
			connection.setAutoCommit(false);
			//3、开启事务
			statement = connection.createStatement();
			//4、创建SQL语句对象
			statement.addBatch("update account set money=money-100 where card_id='1234567890'");
			statement.addBatch("update account set money=mo+100 where card_id='1234567890';");
			//5、写SQL语句
			statement.executeBatch();
			//6、执行SQL语句
			connection.commit();
			//7、关闭事务
		}catch(Exception e){
			try {
				connection.rollback();
				//关闭事务也是有可能出异常的,所以一定要放在try catch里
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}finally {
		//8、释放资源
			try {
				if (statement!=null) {
					statement.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if (connection!=null) {
					connection.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值