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

小咪咪 2022-03-28 05:57 614阅读 0赞

事务
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 {

  1. /**
  2. * 不加事务,在数据库中A用户的金额减了100,中间出异常,那么B用户却没有加100(不加事务的隐患)
  3. * @param money 加减的金额
  4. * @param username 转账用户
  5. * @param username2 收款用户
  6. * @return 返回的结果
  7. */
  8. public boolean tranAccount(int money, String username,String username2){
  9. boolean flag = false;
  10. Connection conn = null;
  11. PreparedStatement ps = null;
  12. String fromSql = "update account_1 set money = money-? where username=?";
  13. String fromTo = "update account_1 set money = money+? where username=?";
  14. conn = DBUtils.getConnection();
  15. try {
  16. ps = conn.prepareStatement(fromSql);
  17. ps.setDouble(1, money);
  18. ps.setString(2, username);
  19. int result1 = ps.executeUpdate();
  20. String str = null;
  21. str.length();//模拟异常
  22. ps = conn.prepareStatement(fromTo);
  23. ps.setDouble(1, money);
  24. ps.setString(2, username2);
  25. int result2 = ps.executeUpdate();
  26. if(result1!=0 && result2!=0){
  27. flag = false;
  28. }
  29. } catch (SQLException e) {
  30. e.printStackTrace();
  31. }
  32. return flag;
  33. }
  34. /**
  35. * 加事务,中间出异常,数据库中A用户的金额没有减了100,B用户也没有加100(加事务的安全性)
  36. * @param money
  37. * @param username
  38. * @param username2
  39. * @return
  40. */
  41. public boolean tranAccount2(int money, String username,String username2){
  42. boolean flag = false;
  43. Connection conn = null;
  44. PreparedStatement ps = null;
  45. String fromSql = "update account_1 set money = money-? where username=?";
  46. String fromTo = "update account_1 set money = money+? where username=?";
  47. conn = DBUtils.getConnection();
  48. try {
  49. conn.setAutoCommit(false);
  50. ps = conn.prepareStatement(fromSql);
  51. ps.setDouble(1, money);
  52. ps.setString(2, username);
  53. int result1 = ps.executeUpdate();
  54. String str = null;
  55. str.length();//模拟异常
  56. ps = conn.prepareStatement(fromTo);
  57. ps.setDouble(1, money);
  58. ps.setString(2, username2);
  59. int result2 = ps.executeUpdate();
  60. if(result1!=0 && result2!=0){
  61. flag = false;
  62. conn.commit();//正确完成的操作,提交事务
  63. }
  64. } catch (Exception e) {
  65. try {
  66. conn.rollback();//转账出错,就让事务回滚
  67. } catch (SQLException e1) {
  68. e1.printStackTrace();
  69. }
  70. e.printStackTrace();
  71. }
  72. return flag;
  73. }
  74. public static void main(String[] args) {
  75. TranDao dao = new TranDao();
  76. dao.tranAccount2(100, "A","B");
  77. }

}

发表评论

表情:
评论列表 (有 0 条评论,614人围观)

还没有评论,来说两句吧...

相关阅读