javaweb银行转账案例(事务处理)JDBC常见知识点(三)

    xiaoxiao2021-12-14  20

    JDBC常见知识点(三)

    导读{

    【1】事务实例: 银行转账(经典题目)

    【1.1】如何使用JDBC处理事务?

    【1.2】通过 Connection 接口中提供了三个方法来针对 JDBC 处理事物。

    [1.4]介绍ThreadLocaL类

    (1)为什么使用ThreadLocaL 类?
    (2)ThreadLocaL类介绍:

    代码演示:在使用数据源(DataSource )时,如果是业务处理,使用C3P0 时,不需要拿 数据源对象。

    }

    【1】事务实例: 银行转账(经典题目)

    【1.1】如何使用JDBC处理事务?

    (1)在数据库操作中,一项事务是由一条或多条操作数据库的SQL语句组成的一个不可分割的工作单元 (2)只有当事务中的所有操作都正常完成,整个事务才能被提交到数据库中,如果有一项操作没有完成,则整个事务会被撤销 例如 银行的转账业务 

    【1.2】通过 Connection 接口中提供了三个方法来针对 JDBC 处理事物。

    其中有三个方法: setAutoCommit(boolean autoCommit)// 设置自动提交 我们需要将这个方法设置为 false 不自动提交 //开启事务 public static void startTransaction(){ try { //获取连接 Connection conn = getConnection(); //开启事务 conn.setAutoCommit(false); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } commit() // 提交   当我们的事务完成的时候,提交 //提交事务 public static void commit(){ try { //从集合tc中得到一个连接 Connection conn = tc.get(); if(conn != null){ conn.commit(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } rollback()  // 回滚  当我们的事务出现异常的时候,回滚 //回滚事务 public static void rollback(){ try { //从集合tc中得到一个连接 Connection conn = tc.get(); if(conn != null){ conn.rollback(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 【1.3】银行转账的业务逻辑 用户 zs 要向 ls 的账户上转200 元钱,该转账业务需要分成两步: 第一步:zs 的账户上需要减少 200 元钱 第二步:ls 的账户上需要增加 200 元钱 这两步操作需要都成功,事务才成功。也就是说,要么都执行成功,要么都没有执行成功。 那么就会出现两种结果,一种是commit() 执行成功,要么就需要执行 rollback () ;

    [1.4]介绍ThreadLocaL类

    (1)为什么使用ThreadLocaL 类?
    Web应用程序, 多用户并发访问 。一个客户端访问时,服务器启动一个线程,比如转账,在这个线程中独立完成这个事务操作,另外一个客户端也来访问时,服务器也启动另外一个线程,在另外一个线程中独立完成转账事 务操作。 要想多线程中,每个事务执行成功,必须保证每个线程有独立的Connection对象。
    (2)ThreadLocaL类介绍:
    ThreadLocaL 类:在一个线程中记录本地变量。我们可以将一个Connection对象放到这个ThreadLocaL集合中,只要是这个线程中的对象都可以共享这个Connection对象,线程结束后,删除这个Connection对象。这样 保证:一个事务一个连接。 TreadLoacl本质上是一个Map,键是当前线程对象,值可以是我们的当前连接对象。 //创建一个ThreadLoacl对象,用当前线程作为key private static ThreadLocal<Connection> tc = new ThreadLocal<Connection>();

    代码演示:在使用数据源(DataSource )时,如果是业务处理,使用C3P0 时,不需要拿 数据源对象。

    Java Web应用开发的三层架构: 1、表示层(Web层):jsp和servlet 2、业务逻辑层(Service层):XXXService,事务操作是在service层完成的。 3、数据访问层(dao层):XXXDao 按照编写正常代码演示: bean-->Utils ---> Dao--->service--->Servlet 先看下数据库表: test数据库中 account 表 三个字段  id 主键自动递增,name 姓名 , money 账户的金额 double 类型  Account.java package cn.edu.aynu.rjxy.bean;public class Account { private int id; private String name; private double money; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } } JDBCUtils.java package cn.edu.aynu.rjxy.utils;import java.sql.Connection;import java.sql.SQLException;import javax.sql.DataSource;import com.mchange.v2.c3p0.ComboPooledDataSource;public class JDBCUtils { //创建一个ThreadLoacl对象,用当前线程作为key private static ThreadLocal<Connection> tc = new ThreadLocal<Connection>(); //从c3p0-config.xml文件中读取默认配置创建数据库连接池对象 private static DataSource ds = new ComboPooledDataSource(); //得到数据库连接池对象 public static DataSource getDataSource(){ return ds; } //从连接池中获取连接 public static Connection getConnection() throws Exception{ //从集合tc中获取一个Connection Connection conn = tc.get(); if(conn == null){ conn = ds.getConnection(); //将conn存放到集合tc中 tc.set(conn); System.out.println("首次创建连接:"+conn); } return conn; } //开启事务 public static void startTransaction(){ try { //获取连接 Connection conn = getConnection(); //开启事务 conn.setAutoCommit(false); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } //提交事务 public static void commit(){ try { //从集合tc中得到一个连接 Connection conn = tc.get(); if(conn != null){ conn.commit(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } //回滚事务 public static void rollback(){ try { //从集合tc中得到一个连接 Connection conn = tc.get(); if(conn != null){ conn.rollback(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //关闭连接释放资源 public static void close(){ //从集合tc中得到一个连接 Connection conn = tc.get(); if(conn != null){ try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ //从集合tc中移除连接对象 tc.remove(); conn = null; } } }} AccountDao,java package cn.edu.aynu.rjxy.dao;import java.sql.Connection;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanHandler;import cn.edu.aynu.rjxy.bean.Account;import cn.edu.aynu.rjxy.utils.JDBCUtils;public class AccountDao { //根据账户名查询账户信息 public Account find(String name) throws Exception{ QueryRunner run = new QueryRunner(); // 处理事务,不需要传 数据源对象 Connection conn = JDBCUtils.getConnection(); System.out.println("find()得到连接:"+conn); String sql = "select * from account where name=?"; Account account = (Account)run.query(conn, sql, new BeanHandler(Account.class), new Object[]{name}); return account; } //转账(可能转入也可能转出) public void update(Account account) throws Exception { QueryRunner run = new QueryRunner(); Connection conn = JDBCUtils.getConnection(); System.out.println("update()得到连接:"+conn); String sql = "update account set money=? where name=?"; run.update(conn, sql, new Object[]{account.getMoney(),account.getName()}); }} AccountService.java  转账的业务逻辑 package cn.edu.aynu.rjxy.service;import cn.edu.aynu.rjxy.bean.Account;import cn.edu.aynu.rjxy.dao.AccountDao;import cn.edu.aynu.rjxy.utils.JDBCUtils;public class AccountService { //转账事务 public static void transfer(String fromName,String toName,double balance){ try { //开启事务 JDBCUtils.startTransaction(); AccountDao dao = new AccountDao(); //查询两个账户的金额 Account accountFrom = dao.find(fromName); Account accountTo = dao.find(toName); //判断是否可以转账 if(balance<accountFrom.getMoney()){ //可以转账 //设置转出账户的金额 accountFrom.setMoney(accountFrom.getMoney()-balance); //设置转入账户的金额 accountTo.setMoney(accountTo.getMoney()+balance); //执行数据库更改操作 dao.update(accountFrom); dao.update(accountTo); //提交事务 JDBCUtils.commit(); System.out.println("事务提交成功"); }else{ System.out.println("转出账户金额不足"); } } catch (Exception e) { //回滚事务 JDBCUtils.rollback(); System.out.println("事务提交失败"); e.printStackTrace(); }finally{ //释放资源 JDBCUtils.close(); } }} 测试转账是否能够完成 import cn.edu.aynu.rjxy.service.AccountService;public class TestTransfer { /** * @param args */ public static void main(String[] args) { //实现从zs账户上转账200到ls账户上 AccountService.transfer("zs", "ls", 200); }} 演示事务处理成功情况:    演示错误情况,将 zs 用户名写成 zss    可以看到,事务没有执行成功。 源码:https://github.com/gengzi/files/tree/master/银行转账(案例) 数据库: https://github.com/gengzi/files/tree/master/银行转账(案例)
    转载请注明原文地址: https://ju.6miu.com/read-970409.html

    最新回复(0)