转账事务控制

1.数据准备

CREATE TABLE `account` (`aid` int(11) NOT NULL AUTO_INCREMENT,`uname` varchar(255) DEFAULT NULL,`upwd` varchar(255) DEFAULT NULL,`balance` decimal(8,2) DEFAULT NULL,PRIMARY KEY (`aid`)
) ENGINE=InnoDB;INSERT INTO `account` VALUES (1, 'tesDest',
'112342', 1200.00);
INSERT INTO `account` VALUES (2, 'segvcw', '223352',
680.50);

2.项目准备

创建Web项目,技术栈:JDBC + druid连接池 + Servlet + Ajax 使用带事务处理的JDBC工具类,

3.项目文件


4.完整代码

TransactionDao

package com.huawei.servlet;import com.huawei.entity.Account;
import com.huawei.service.TransactionService;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** @avthor HuangJun* @date 2022/5/2 14:58*/
@WebServlet(value = "/transfer.do")
public class TransferServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.接收表单参数String fromAcc = req.getParameter("fromAcc");String moneyStr = req.getParameter("money");String toAcc = req.getParameter("toAcc");resp.setContentType("text/json;charset=utf-8");double money = 0.0;if (moneyStr != null && !"".equals(moneyStr)) {money = Double.parseDouble(moneyStr);}PrintWriter out = resp.getWriter();//2.创建业务层对象 调用业务层方法TransactionService tranService = new TransactionService();if (tranService.chageAccount(fromAcc)) {if (tranService.chageAccount(toAcc)) {if (tranService.balanceVerify(fromAcc, money)) {//3.根据业务方法的返回值进行处理boolean isFlag = tranService.transactionAccount(fromAcc, toAcc, money);if (isFlag) {System.out.println("转账成功!");//以响应输出成功标志到前端out.println("<h3>转账成功</h3>");} else {System.out.println("转账失败!");//以响应输出失败标志到前端out.println("<h3>转账失败</h3>");throw new RuntimeException("转账失败");//TODO 如果没有手动引发异常 转账过滤器是无法回滚的}} else {out.println("<h3>" + fromAcc + "账户余额不足</h3>");}} else {out.println("<h3>" + toAcc + "账户不存在</h3>");}} else {out.println("<h3>" + fromAcc + "账户不存在</h3>");}}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}
}

Account

package com.huawei.entity;/*** @avthor HuangJun* @date 2022/5/2 15:05*/public class Account {private int aid;private String uname;private String upwd;private double balance;public Account() {}public int getAid() {return aid;}public void setAid(int aid) {this.aid = aid;}public String getUname() {return uname;}public void setUname(String uname) {this.uname = uname;}public String getUpwd() {return upwd;}public void setUpwd(String upwd) {this.upwd = upwd;}public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}@Overridepublic String toString() {return "Account{" +"aid=" + aid +", uname='" + uname + '\'' +", upwd='" + upwd + '\'' +", balance=" + balance +'}';}
}

TransactionFilter

package com.huawei.filter;import com.huawei.util.DBUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @avthor HuangJun* @date 2022/5/1 19:04*/
@WebFilter(urlPatterns = "/*")
public class TransactionFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {try {//TODO 只会针对insert update deleteSystem.out.println("---------请求执行--------");DBUtils.beginTransaction();//开启事务filterChain.doFilter(servletRequest, servletResponse);DBUtils.commitAndClose();// 提交事务System.out.println("---------给出响应--------");} catch (Exception e) {DBUtils.rollbackAndClose();//回滚事务e.printStackTrace();}}@Overridepublic void destroy() {}
}

TransactionService

package com.huawei.service;import com.huawei.dao.TransactionDao;
import com.huawei.entity.Account;/*** @avthor HuangJun* @date 2022/5/2 15:01*/public class TransactionService {private TransactionDao tranDao;public TransactionService() {tranDao = new TransactionDao();}//确认账户是否存在public boolean chageAccount(String accNo) {//TODOboolean flag = false;Account account = tranDao.queryAccountByWhere(accNo);if (account != null) {flag = true;}return flag;}//确认账户余额是否足够public boolean balanceVerify(String accNo, double balance) {//TODOboolean flag = false;Account account = tranDao.queryAccountByWhere(accNo);if (account == null) {return flag;} else {if (account.getBalance() < balance) {return flag;} else {flag = true;}}return flag;}//转账方法public boolean transactionAccount(String accNo, String toAccount, double balance) {//TODOboolean flag = false;try {tranDao.transationOut(accNo, balance);
//            int i=1/0;//手动引发异常tranDao.transationIn(toAccount, balance);flag = true;} catch (Exception e) {e.printStackTrace();}return flag;}
}

TransferServlet

package com.huawei.servlet;import com.huawei.entity.Account;
import com.huawei.service.TransactionService;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** @avthor HuangJun* @date 2022/5/2 14:58*/
@WebServlet(value = "/transfer.do")
public class TransferServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.接收表单参数String fromAcc = req.getParameter("fromAcc");String moneyStr = req.getParameter("money");String toAcc = req.getParameter("toAcc");resp.setContentType("text/json;charset=utf-8");double money = 0.0;if (moneyStr != null && !"".equals(moneyStr)) {money = Double.parseDouble(moneyStr);}PrintWriter out = resp.getWriter();//2.创建业务层对象 调用业务层方法TransactionService tranService = new TransactionService();if (tranService.chageAccount(fromAcc)) {if (tranService.chageAccount(toAcc)) {if (tranService.balanceVerify(fromAcc, money)) {//3.根据业务方法的返回值进行处理boolean isFlag = tranService.transactionAccount(fromAcc, toAcc, money);if (isFlag) {System.out.println("转账成功!");//以响应输出成功标志到前端out.println("<h3>转账成功</h3>");} else {System.out.println("转账失败!");//以响应输出失败标志到前端out.println("<h3>转账失败</h3>");throw new RuntimeException("转账失败");//TODO 如果没有手动引发异常 转账过滤器是无法回滚的}} else {out.println("<h3>" + fromAcc + "账户余额不足</h3>");}} else {out.println("<h3>" + toAcc + "账户不存在</h3>");}} else {out.println("<h3>" + fromAcc + "账户不存在</h3>");}}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}

DaoTest

package com.huawei.test;import com.huawei.dao.TransactionDao;
import com.huawei.entity.Account;/*** @avthor HuangJun* @date 2022/5/2 15:15*/public class DaoTest {public static void main(String[] args) {TransactionDao dao=new TransactionDao();Account account= dao.queryAccountByWhere("test1");System.out.println(account);//        dao.transationIn("test1",200);dao.transationOut("test1",200);}
}

db.properties

jdbc.url=jdbc:mysql://localhost:3306/teach?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=123456
jdbc.driverClassName=com.mysql.cj.jdbc.Driverdruid.url=jdbc:mysql://localhost:3306/teach?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
druid.username=root
druid.password=123456
druid.driverClassName=com.mysql.cj.jdbc.Driver
druid.maxActive=8
druid.maxWait=5000

DBUtils

package com.huawei.util;import com.alibaba.druid.pool.DruidDataSource;import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;/*** Jdbc工具类[加入事务控制+线程+Druid连接池]** @avthor HuangJun* @date 2022/3/30 10:36*/public class DBUtils {static String USER = null;static String USER_PASS = null;static String DB_URL = null;static String DRIVER_CLASS = null;//容器变量      [ThreadLocal用于隔离多线程并发 产生的数据混乱]private static ThreadLocal<Connection> conns = new ThreadLocal<>();private static DataSource dataSource;/*** 静态代码块加载属性配置文件*/static {Properties config = new Properties();try {//找到文件InputStream is = DBUtils.class.getResourceAsStream("/db.properties");//并读取到内存config.load(is);//读取属性数据的keyDRIVER_CLASS = config.getProperty("jdbc.driverClassName");//初始化Durid连接池数据DruidDataSource dds = new DruidDataSource();dds.configFromPropety(config);//加载属性文件到数据源对象dataSource = dds;} catch (IOException e) {e.printStackTrace();}}public static DataSource getDataSource() {return dataSource;}/*** 注册驱动*/static {try {Class.forName(DRIVER_CLASS);} catch (ClassNotFoundException e) {e.printStackTrace();}}public static Connection getConn() {if (conns.get() == null) {// 当前线程是否有连接对象Connection conn = null;try {conn = dataSource.getConnection();conns.set(conn);//放入当前线程对象中} catch (Exception e) {e.printStackTrace();}}return conns.get();}/*** @throws Exception*/public static void beginTransaction() throws Exception {getConn().setAutoCommit(false);}/*** 提交事务*/public static void commit() {try {getConn().commit();} catch (SQLException throwables) {throwables.printStackTrace();}}/*** 回滚*/public static void rollback() {try {getConn().rollback();} catch (SQLException throwables) {throwables.printStackTrace();}}public static Connection getConn(String DB_URL) {Connection conn = null;try {conn = DriverManager.getConnection(DB_URL, USER, USER_PASS);} catch (Exception e) {e.printStackTrace();}return conn;}public static void close(Connection conn, Statement stmt, ResultSet rs) {if (rs != null) {try {rs.close();} catch (Exception e) {e.printStackTrace();}}if (stmt != null) {try {stmt.close();} catch (Exception e) {e.printStackTrace();}}if (conn != null) {try {conn.setAutoCommit(true);conn.close();conns.remove();} catch (Exception e) {e.printStackTrace();}}}/*** 通用的DML sql语句执行方法** @param sql* @param params* @return*/public static int update(String sql, Object... params) throws Exception {int result = 0;Connection conn = getConn();PreparedStatement psmt = conn.prepareStatement(sql);//获取参数化SQL中的? 个数int count = psmt.getParameterMetaData().getParameterCount();if (count != params.length) {return -1;}//遍历参数个数 从动态数组中取出for (int i = 1; i <= count; i++) {psmt.setObject(i, params[i - 1]);}//执行sql语句result = psmt.executeUpdate();close(conn, psmt, null);return result;}/*** 查询方法** @param sql* @param params* @return* @throws Exception*/public static ResultSet query(String sql, Object... params) throws Exception {ResultSet result = null;Connection conn = getConn();PreparedStatement psmt = conn.prepareStatement(sql);//获取参数化SQL中的? 个数int count = psmt.getParameterMetaData().getParameterCount();if (count != params.length) {return null;}//遍历参数个数 从动态数组中取出for (int i = 1; i <= count; i++) {psmt.setObject(i, params[i - 1]);}//执行sql语句result = psmt.executeQuery();return result;}/*** 获取数据库连接池中的连接** @return 如果返回 null,说明获取连接失败<br/>有值就是获取连接成功*/public static Connection getConnection() {Connection conn = conns.get();if (conn == null) {try {conn = dataSource.getConnection();//从数据库连接池中获取连接conns.set(conn); // 保存到 ThreadLocal 对象中, 供后面的jdbc 操作使用conn.setAutoCommit(false); // 设置为手动管理事务} catch (SQLException e) {e.printStackTrace();}}return conn;}/*** * 提交事务, 并关闭释放连接*/public static void commitAndClose() {Connection connection = conns.get();if (connection != null) { // 如果不等于 null, 说明 之前使用过连接, 操作过数据库try {connection.commit(); // 提交 事务} catch (SQLException e) {e.printStackTrace();} finally {try {connection.close(); // 关闭连接, 资源资源} catch (SQLException e) {e.printStackTrace();}}}//一定要执行 remove 操作,否则就会出错。 (因为 Tomcat 服务器底层使用了线程池技术)conns.remove();}/*** 回滚事务,并关闭释放连接*/public static void rollbackAndClose() {Connection connection = conns.get();if (connection != null) { // 如果不等于 null, 说明 之前使用过连接,操作过数据库try {connection.rollback();//回滚事务} catch (SQLException e) {e.printStackTrace();} finally {try {connection.close(); // 关闭连接, 资源资源} catch (SQLException e) {e.printStackTrace();}}}//一定要执行 remove操作,否则就会出错。 (因为 Tomcat服务器底层使用了线程池技术)conns.remove();}/*** 关闭连接, 放回数据库连接池** @param conn*/public static void close(Connection conn) {if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}

transfer.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>转账</title><script type="text/javascript" src="js/axios-v0.27.2.js"></script>
</head>
<body>
<h3>模拟银行转账</h3>
<form action="/transfer.do" method="post"><table width="450px" border="1" cellpadding="0" cellspacing="0"><tr><td width="100px">转账人</td><td><input  name="fromAcc"></td></tr><tr><td>转账金额</td><td><input name="money"></td></tr><tr><td>收款人</td><td><input name="toAcc"></td></tr><tr><td colspan="2"><input type="submit" value="提交"></td></tr></table>
</form>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4fuol3rd-1651747441085)(C:\Users\hj\Desktop\2022KP java全栈-01\博客原件\转账事务控制\03.png)]

" src=“js/axios-v0.27.2.js”>

模拟银行转账

<table width="450px" border="1" cellpadding="0" cellspacing="0"><tr><td width="100px">转账人</td><td><input  name="fromAcc"></td></tr><tr><td>转账金额</td><td><input name="money"></td></tr><tr><td>收款人</td><td><input name="toAcc"></td></tr><tr><td colspan="2"><input type="submit" value="提交"></td></tr>
</table>

```

注意:如果输入负值自己会加钱

java web 转账事务控制相关推荐

  1. java web项目请求控制及简单漏洞防范

    背景:当时项目没用什么框架,过滤器,请求限制等都需要自己手写. 1.请求加时间戳 在后台过滤器中可以加判断,如果请求时间戳与服务器时间相差太大,可以返回异常,具体情况可以具体使用. 请求中加时间戳的示 ...

  2. java map集合 事务控制_对象回收过程?线程池执行过程? map原理?集合类关系?synchronized 和 volatile ? 同一个类的方法事务传播控制还有作用吗?java 锁...

    1.  对象回收过程? 可达性分析算法: 如果一个对象从 GC Roots 不可达时,则证明此对象不可用. 通过一系列称为GC ROOTS的对象作为起点,从这些起点往下搜索,搜索走过的路径 称为引用链 ...

  3. JAVA日记之SpringJdbcTemplate/声明式事务控制 ----喝最烈的酒.

    JdbcTemplate基本使用 01-JdbcTemplate基本使用-概述 JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装.spring框 ...

  4. java 控制jsp_JSP学习之Java Web中的安全控制实例详解

    普通用户界面 修改登录的Servlet,修改后的代码如下: LoginProcess.java代码: package servlet; import javabean.User; import jav ...

  5. java事务代码_关于java中实现JDBC事务控制代码示例

    一.前言 数据库事务是执行业务的每个逻辑单元一系列操作,可由一个或多个SQL语句组成.如执行的SQL都能被正确的执行,则这批SQL提交将被生效,否则都不成功,通过这样的事务控制有效的保障了数据库数据的 ...

  6. 【java学习之路】(java框架)010.声明式事务控制

    声明式事务控制 编程式事务控制相关对象 PlatformTransactionManager* PlatformTransactionManager 接口是 spring 的事务管理器,它里面提供了我 ...

  7. java day60【 Spring 中的 JdbcTemplate[会用] 、Spring 中的事务控制 、Spring5 的新特性[了解] 】...

    第1章 Spring 中的 JdbcTemplate[会用] 1.1JdbcTemplate 概述 1.2JdbcTemplate 对象的创建 1.3spring 中配置数据源 1.3.1 环境搭建 ...

  8. Java中的事务——全局事务与本地事务

    转载自   Java中的事务--全局事务与本地事务 在上一篇文章中说到过,Java事务的类型有三种:JDBC事务.JTA(Java Transaction API)事务.容器事务. 这是从事务的实现角 ...

  9. Java web基础学习笔记

    1.xml概述 1.1xml:xml一种数据存储格式,这种数据存储格式在存储数据内容的同时,还能够保存数据之间的关系 1.2xml保存数据的方法:xml利用标签来保存数据的内容,利用标签之间的嵌套关系 ...

最新文章

  1. 如何查看python安装位置图_怎么查看python安装路径
  2. BZOJ3075[USACO 2013 Mar Gold 3.Necklace]——AC自动机+DP
  3. c语言 #define dpath .exe是什么意思,C语言宏定义#define
  4. laravel 5.1 php版本号,发行版本说明 | 序言 | Laravel 5.1 中文文档
  5. 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则
  6. 10.9 自动注册DSN和创建表
  7. Java序列化机制原理,java面试题,java基础笔试题,BAT
  8. Python打基础一定要吃透这68个内置函数
  9. 【数值计算】计算机中的数值计算
  10. vs2013 update5离线升级包下载地址
  11. 特来电支付中心总体介绍
  12. 王者荣耀在android目录下的名字,王者荣耀手q区有哪些 王者荣耀安卓手Q区名称...
  13. 网站文章采集与伪原创技巧
  14. 浮点数切分 C++
  15. 伍鸣博士受邀出席徐汇区住房租赁市场研讨会
  16. 海康硬盘录像机无法通过rtsp协议连接到EasyNVR的Web页面如何处理?
  17. 阿里云GPU计算型gn6i服务器配置性能好不好用?
  18. linux百度云工具baidu pcs
  19. 【DC010沙龙年度合集】顶尖Hacking技术盛宴(文末福利)
  20. 寻找演讲比赛流程管理系统

热门文章

  1. BUUCTF:[MRCTF2020]天干地支+甲子
  2. 不在书店和荒岛图书馆
  3. 四角号码查询器 第3版 发布
  4. linux如何在文件末尾添加空行,关于eof:Linux – 检查文件末尾是否有空行
  5. 电吹风哪个牌子比较好?
  6. 士兵突击【幕后故事】
  7. myeclipse中的文件内容被覆盖如何恢复
  8. Te Amo,我爱你
  9. js vbs 数组_Javascript与vbscript数据共享
  10. 网易美术干货,《阴阳师》的角色“设计感”是如何诞生的?