上一篇文章文章使用的是三层架构模式,因为事务开启需要在service层,所以只能在service层开启事务,为了包管是同一事务,所以要在service层获取到connection对象,然后将这个对象传递到dao层,可是这个有一个问题,就是connection是操作数据库的工具,他不该该写在service层
那么是否可以将开启事务和关闭事务以及回滚事务和获取连接对象封装起来,包管在任何体例中操作的都是同一个connection,这样在dao层就可以直接获取connection了,就没有需要service层去传输connection了,这样service代码中就直接挪用封装好的开启事务,提交事务的体例,而dao层为了查询,或者修改数据库所用到的connection对象,直接挪用封装好的获取connection体例,他们获取的这些封装好的体例中操作的connection是一个
思想是有了,那么如何才能包管在任何体例中操作的都是同一个connection对象呢?这里首先要介绍一个类Threadlocal,这个类的素质是一个map,可是它很特殊,因为它的键我们不消操作,键固定为当前线程的名字,我们只用操作值,这个类可以帮忙我们获取connection对象,然后存入Threadlocal,这就可以包管只要我们始终在一个线程中,那么取出的connction就始终是一个,这样我们在银行转账这个单线程程序中,在任何处所都是操作同一个connction,service不再需要传递connection给dao了,dao只要直接在Threadlocal中获取,就可以获取到和service一样的connection。
mysql数据库事务阐发:实现银行转账功能的优化,附代码+实现过程-1.jpg (17.43 KB, 下载次数: 0)
2018-7-14 22:35 上传
这个ThreadLocal虽然是map可是因为键固定,所以我们只需要操作值,所以我们只需要泛型写值就ok了,还有就是它的基本体例,map中增加删除,都需要指定键这个不需要,这个获取直接t1.get(),删除直接t1.remove()因为键默认为当前线程的名字。
自界说MyDataSource工具类
package com.huanfeng.utils;import java.sql.Connection;import java.sql.SQLException;import com.mchange.v2.c3p0.ComboPooledDataSource;public class MyDataSource {//获得Connection ----- 从连接池中获取private static ComboPooledDataSource dataSource = new ComboPooledDataSource();//建立ThreadLocalprivate static ThreadLocal tl = new ThreadLocal();//开启事务public static void startTransaction() throws SQLException{Connection conn = getCurrentConnection();conn.setAutoCommit(false);}//获适当前线程上绑定的connpublic static Connection getCurrentConnection() throws SQLException{//从ThreadLocal寻找 当前线程是否有对应ConnectionConnection conn = tl.get();if(conn==null){//获得新的connectionconn = getConnection();//将conn资源绑定到ThreadLocal(map)上tl.set(conn);}return conn;}public static Connection getConnection() throws SQLException{return dataSource.getConnection();}//回滚事务public static void rollback() throws SQLException {getCurrentConnection().rollback();}//提交事务public static void commit() throws SQLException {Connection conn = getCurrentConnection();conn.commit();//将Connection从ThreadLocal中移除tl.remove();conn.close();}}
transfer.jsp
Insert title here转出账户:转入账户:
转账金额:
TransferServlet
package com.huanfeng.cn;import java.io.IOException;import java.net.URLEncoder;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class TransferServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//接受转账的参数request.setCharacterEncoding("UTF-8");String out = request.getParameter("out");String in = request.getParameter("in");String moneyStr = request.getParameter("money");double money = Double.parseDouble(moneyStr);//挪用业务层的转账体例TransferService service = new TransferService();boolean isTransferSuccess = service.transfer(out,in,money);response.setContentType("text/html;charset=UTF-8");if(isTransferSuccess){response.getWriter().write("转账成功!!!");}else{response.getWriter().write("转账失败!!!");}}protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
TransferService
package com.huanfeng.cn;import java.sql.Connection;import java.sql.SQLException;import com.huanfeng.utils.MyDataSource;public class TransferService {public boolean transfer(String out, String in, double money) {TransferDao dao = new TransferDao();boolean isTranferSuccess = true;try {MyDataSource.startTransaction();dao.out(out,money);dao.in(in,money);} catch (Exception e) {isTranferSuccess = false;//回滚事务try {MyDataSource.rollback();} catch (SQLException e1) {e1.printStackTrace();}e.printStackTrace();} finally{try {MyDataSource.commit();} catch (SQLException e) {e.printStackTrace();}}return isTranferSuccess;}}
TransferDao
package com.huanfeng.cn;import java.sql.Connection;import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;import org.junit.Test;import com.huanfeng.utils.MyDataSource;public class TransferDao {public void out(String out, double money) throws SQLException {QueryRunner runner = new QueryRunner();Connection conn = MyDataSource.getCurrentConnection();String sql = "update account set money=money-? where name=?";int b=runner.update(conn, sql, money,out);System.out.println(b+"aa");}public void in(String in, double money) throws SQLException {QueryRunner runner = new QueryRunner();Connection conn = MyDataSource.getCurrentConnection();String sql = "update account set money=money+? where name=?";runner.update(conn, sql, money,in);}}
数据库
mysql数据库事务阐发:实现银行转账功能的优化,附代码+实现过程-2.jpg (10.33 KB, 下载次数: 0)
2018-7-14 22:35 上传
至此程序就ok了可是这个程序还有一个问题,就是我们判断是否转账成功是根据是都有异常产生的,如果有异常产生就暗示转账不成功的,
mysql数据库事务阐发:实现银行转账功能的优化,附代码+实现过程-3.jpg (32.22 KB, 下载次数: 0)
2018-7-14 22:35 上传
可是这个程序转账不成功也就是update执行失败不会产生异常,只会返回0,也就是说如果我们表单中输入的name数据库中没有,他也不会产生异常,不会产生异常那么service就认为数据库操作执行成功,所以这是不对的,应该判断返回值,如果的返回值为0,就暗示数据库操作失败
更多内容回复查看:
游客,如果您要查看本帖隐藏内容请回复