jdbc事务:模拟银行转账业务

事务
1.事务简介
事务(Transaction):数据库中保证数据操作可靠的机制。常运用于交易业务。JDBC支持数据库中的事务概念,并且在JDBC中,事务默认是自动提交的。

这样就可能存在问题:某些业务逻辑必须在一个事务中完成。
假设支付宝A账号上有3000元,需要转账1000元给另一个支付宝B账号,
正确的流程是

事务必须遵循的特性介绍:ACID
原子性(Atomicity):事务必须是原子工作单元;对于同一个事务中的数据修改,要么全都执行,要么全都不执行
一致性(Consistency):事务在完成时,必须使所有的数据都保持一致状态。如数据库原来有什么样的约束,事务执行之后还需要存在这样的约束
隔离性(Isolation):由并发事务所作的修改必须与任何其它并发事务所作的修改隔离
持久性(Durability):事务完成之后,它对于系统的影响是永久性的 (持久保存到数据库文件)

事务是数据库的概念,JDBC支持事务,本质还是在数据库中实现的

2.JDBC事务API
JDBC中和事务相关API:
Connection.getAutoCommit() :获得当前事务的提交方式,默认为true
Connection.setAutoCommit():设置事务的提交属性,参数是true:自动提交;false:不自动提交
Connection.commit():提交事务
Connection.rollback():回滚事务

3.JDBC事务编程
JDBC处理事务的通常模式:
1).先将事务的自动提交关闭;
2).执行事务中的若干SQL语句;
3).事务提交或SQL失败则回滚;
4).恢复JDBC的事务提交状态或释放资源。

核心代码:
try{
// 1.定义用于在事务中执行的SQL语句
String sql1 = “update account set amount = amount - " + amount + " where id = '” + from+ “’”;
String sql2 = “update account set amount = amount + " + amount + " where id = '” + to+ “’”;
boolean autoCommit = con.getAutoCommit(); // 2.获得自动提交状态
con.setAutoCommit(false); // 3.关闭自动提交
stmt.executeUpdate(sql1); // 4.执行SQL语句
stmt.executeUpdate(sql2);
con.commit(); // 5.提交
con.setAutoCommit(autoCommit); // 6.将自动提交功能恢复到原来的状态
//其他语句
}catch(SQLException e){
conn.rollback();//异常时回滚
}

案例:
使用JDBC连接数据库,实现账号转账业务。从A账户转账给B账户1000元钱

方案:可以使用事务将两次更新操作封装成一个逻辑单元,要么都执行,要么都不执行,保证了数据的完整性

步骤:
步骤一
创建Account表,并插入测试数据。在Oracle数据库中,创建表并插入测试数据,SQL语句如下所示:
create table account (
id char(1),
amount number(10)
);
insert into account values(‘A’, 3000);
insert into account values(‘B’, 1000);
commit;–注意要提交
步骤二:
新建JDBCDemo3工程,并导入JDBC及连接池相关Jar包
步骤三:
准备连接池工具类DbUtil_Pool
步骤四:
准备JDBC操作数据库基本代码,创建 Transfer 类,并创建tran(String from,String to,int amount) 转账方法:
步骤五:实现转账功能
使用Connection的setAutoCommit方法、commit方法以及rollback方法来控制事务,以确保转账功能正确实现,代
步骤六:
测试转账功能

然后查看Oracle数据库中的account表,会发现A账户的金额减少了1000元,B账户的金额增加了1000元

完整代码
package cn.lyc.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import cn.lyc.util.DBUtils;

/**

  • 模拟银行转账业务
  • @author JLB

*/
public class TranDao {

/**
 * 不加事务,在数据库中A用户的金额减了100,中间出异常,那么B用户却没有加100(不加事务的隐患)
 * @param money  加减的金额
 * @param username 转账用户
 * @param username2 收款用户
 * @return  返回的结果
 */
public boolean tranAccount(int money, String username,String username2){
	boolean flag = false;
	
	Connection conn = null;
	PreparedStatement ps = null;
	String fromSql = "update account_1 set money = money-? where username=?";
	String fromTo = "update account_1 set money = money+? where username=?";
	conn = DBUtils.getConnection();
	try {
		ps = conn.prepareStatement(fromSql);
		ps.setDouble(1, money);
		ps.setString(2, username);
		int result1 = ps.executeUpdate();
		
		String str = null;
		str.length();//模拟异常
		
		ps = conn.prepareStatement(fromTo);
		ps.setDouble(1, money);
		ps.setString(2, username2);
		int result2 = ps.executeUpdate();
		if(result1!=0 && result2!=0){
			flag = false;
		}
	} catch (SQLException e) {
		e.printStackTrace();
	}
	
	return flag;
}


/**
 * 加事务,中间出异常,数据库中A用户的金额没有减了100,B用户也没有加100(加事务的安全性)
 * @param money
 * @param username
 * @param username2
 * @return
 */
public boolean tranAccount2(int money, String username,String username2){
	boolean flag = false;
	
	Connection conn = null;
	PreparedStatement ps = null;
	String fromSql = "update account_1 set money = money-? where username=?";
	String fromTo = "update account_1 set money = money+? where username=?";
	conn = DBUtils.getConnection();
	
	try {
		conn.setAutoCommit(false);
		ps = conn.prepareStatement(fromSql);
		ps.setDouble(1, money);
		ps.setString(2, username);
		int result1 = ps.executeUpdate();
		
		String str = null;
		str.length();//模拟异常
		
		ps = conn.prepareStatement(fromTo);
		ps.setDouble(1, money);
		ps.setString(2, username2);
		int result2 = ps.executeUpdate();
		if(result1!=0 && result2!=0){
			flag = false;
			conn.commit();//正确完成的操作,提交事务
		}
	} catch (Exception e) {
		try {
			conn.rollback();//转账出错,就让事务回滚
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		e.printStackTrace();
	}
	
	return flag;
}
public static void main(String[] args) {
	TranDao dao = new TranDao();
	dao.tranAccount2(100, "A","B");
}

}

猜你喜欢

转载自blog.csdn.net/qq_42902470/article/details/86169489