通过ApacheDBUtil模拟转账功能

通过AoacheDbUtile模拟转账功能

  1. 创建两个工具类JDBCUtile DataSourceUtile

JDBCUtile:用来管理事务和Connection对象

package cn.kz.utile;

import java.sql.Connection;

public class JDBCUtile {
    // 可以防止并发且事务在同一次连接
    // 原理ThreadLocal在获取对象的时候是通过创建对象 的副本
    // 好处:不用创建多个Connection对象就可以使用 且 达到事务在同一个连接下
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal();
	
    // 获取连接的方法
    public static Connection getConnection() throws Exception {
        Connection connection = threadLocal.get();
        // 如果从threadLocal中获取不到副本	则新建一个Connection对象
        if (connection == null) {
            connection = DataSourceUtle.getDataSource().getConnection();
            threadLocal.set(connection);
        }
        return connection;
    }

    // 开启事务
    public static void beginTransaction() throws Exception {
        Connection connection = getConnection();
        connection.setAutoCommit(false);// 开启事务

    }

    // 正常。提交事务
    public static void commitTransaction() throws Exception {
        // 连接
        Connection connection = getConnection();
        if (connection != null) {
            connection.commit();
        }
    }

    // 失败。回滚事务
    public static void rollbackTransaction() throws Exception {
        // 连接
        Connection connection = getConnection();
        if (connection != null) {
            connection.rollback();
        }
    }

    //关闭连接
    public static void close() throws Exception {
        // 连接
        Connection connection = getConnection();
        if (connection != null) {
            connection.close();
        }
        threadLocal.remove();
        connection = null;
    }

}

DataSourceUtile:用来获取DataSource对象

package cn.kz.utile;

import org.apache.commons.dbcp.BasicDataSource;

import javax.sql.DataSource;

public class DataSourceUtle {
    // dbcp连接池
    public static DataSource getDataSource(){
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/kz?serverTimezone=Hongkong");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setPassword("123456");
        dataSource.setUsername("root");
        return dataSource;
    }
}
  1. 创建一个Account bean把数据库返回的值存到该对象
package cn.kz.bean;

public class Account {
    private int id;
    private String name;
    private long balance;
	// 有参构造器
    public Account(int id, String name, long balance) {
        this.id = id;
        this.name = name;
        this.balance = balance;
    }
	// 无参构造器
    public Account() {
    }
// setter getter方法
  1. AccountDaoImpl dao层封装无逻辑的 查询和修改 数据库操作
package cn.kz.dao;

import cn.kz.bean.Account;
import cn.kz.utile.JDBCUtile;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.Connection;

public class AccountDaoImpl{
    // 通过银行卡id来查询	并返回一个Account对象
    public Account queryAccountByCard(int cardId) throws Exception {
        QueryRunner runner = new QueryRunner();
        Connection connection = JDBCUtile.getConnection();
        
        Account account= runner.query(connection,
                "select * from account where id = ?",
                new BeanHandler<Account>(Account.class),cardId);
        return account;
    }

   // 修改数据库的账户信息 传入一个Account对象	
    public void updataAccount(Account account) throws Exception{
        QueryRunner runner = new QueryRunner();
        Connection connection = JDBCUtile.getConnection();
        
        runner.update(connection,
                "update account set balance = ? where id = ?",
                new Object[]{account.getBalance(),
                account.getId()});
    }
}

  1. service层 通过逻辑来处理转账
package cn.kz.service;

import cn.kz.bean.Account;
import cn.kz.dao.AccountDaoImpl;
import cn.kz.utile.JDBCUtile;

public class AccountServiceImpl{

    /**
     * 
     * @param fromCardId	付款方的id
     * @param toCardId	收款方的id
     * @param money		转账的金额
     */
    public void transfer(int fromCardId, int toCardId, int money) {
        AccountDaoImpl accountDao = new AccountDaoImpl();
        // 开启事务
        try {
            JDBCUtile.beginTransaction();
            // 各种dml操作
            // a -1000   b +1000
            // 根据cardId查询对应的账户
            Account fromAccount = accountDao.queryAccountByCard(fromCardId);
            Account toAccount = accountDao.queryAccountByCard(toCardId);

            // 转账 	先判断付款方余额是否大于转账金额(判断付款方的钱够不够转)
            if (fromAccount.getBalance() > money) {
                // 付款方-1000
                long fromBalance = fromAccount.getBalance() - money;
                fromAccount.setBalance(fromBalance);
                // 收款方+1000
                long toBalance = toAccount.getBalance() + money;
                toAccount.setBalance(toBalance);

                accountDao.updataAccount(fromAccount);
                accountDao.updataAccount(toAccount);
                // 正常提交事务
                JDBCUtile.commitTransaction();
                System.out.println("转账成功~~~");
            } else {
                System.out.println("余额不足~~~");
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("转账失败~~~");
            try {
                JDBCUtile.rollbackTransaction();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        } finally {
            try {
                JDBCUtile.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //结束事务(正常,失败)
    }
}

  1. 测试
package cn.kz.test;

import cn.kz.service.AccountService;
import cn.kz.service.AccountServiceImpl;

public class Test {
    public static void main(String[] args) {
        // 尝试转账
        AccountService service = new AccountServiceImpl();
        service.transfer(1,2,2000);
    }
}

原来的数据
在这里插入图片描述

代码执行后
在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45412353/article/details/103584159
今日推荐