当前位置: 首页 > 图灵资讯 > 技术篇> 解决事务问题和分包

解决事务问题和分包

来源:图灵教育
时间:2023-05-22 09:21:57

1.代码73-74com中的代码.powernode.bank.webAccountservice

package com.powernode.bank.web;import com.powernode.bank.exceptions.MoneyNotEnoughException;import com.powernode.bank.service.AccountService;import jakarta.servlet.ServletException;import jakarta.servlet.annotation.WebServlet;import jakarta.servlet.http.HttpServlet;import jakarta.servlet.http.HttpServletRequest;import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;///账户servlet小程序  67和70//AccountServlet是指挥官。他负责调度其他组件完成任务。@WebServlet("/transfer")public class AccountServlet extends HttpServlet {///将Accountservlet视为Controler    ////调用业务方法处理业务(调度Model处理业务)  70    private AccountService accountService = new AccountService();    @Override    protected void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        //接收数据  70        String fromActno = request.getParameter("fromActno");        String toActno = request.getParameter("toActno");        double money = Double.parseDouble(request.getParameter("money"));        ////调用业务方法处理业务(调度Model处理业务)        try {            accountService.transfer(fromActno,toActno,money);            ///程序执行在这里表示成功            //显示数据(调度view左业务显示)            //重定向            response.sendRedirect(request.getContextPath()+"/success.jsp");        } catch (MoneyNotEnoughException e){            ///执行到这里转账失败,余额不足            //显示数据(调度view左业务显示)            //重定向            response.sendRedirect(request.getContextPath()+"/moneynotenough.jsp");        }catch (Exception e) {            ///执行到这里转账失败            //显示数据(调度view左业务显示)            //重定向            response.sendRedirect(request.getContextPath()+"/error.jsp");        }    }}

com.powernode.bank.serviceAccountservicer

package com.powernode.bank.service;////这一类负责处理account业务  69import com.powernode.bank.exceptions.AppException;import com.powernode.bank.exceptions.MoneyNotEnoughException;import com.powernode.bank.dao.AccountDao;import com.powernode.bank.pojo.Account;import com.powernode.bank.utils.DBUtil;import java.sql.Connection;import java.sql.SQLException;/** * service翻译为:业务。 * AccountService:专门处理Account业务的类别。 * AccountService:专门处理Account业务的类别。 * 纯业务代码应在此类中编写。(只关注业务。不写别的。不与其他代码混合。) * 只希望专注于业务,能完美实现业务,少量bug。 * * 一般来说,业务名称:XxxService、XxxBiz... */public class AccountService {    // 为何在这里定义?因为数据库可以连接到每个业务方法中。    private AccountDao accountDao = new AccountDao();    // 这里的方法命名必须反映你想处理什么业务。    // 我们需要提供一种可以实现转账的业务方法(一种业务对应一种方法)。)    /**     * 完成转账的业务逻辑     * @param fromActno 转出账号     * @param toActno 转入账号     * @param money 转账金额     */    public void transfer(String fromActno,String toActno,double money)            throws MoneyNotEnoughException, AppException {        ///service层控制事务  71        try (Connection connection = DBUtil.getConnection();){            ///开启事务(Conection对象需要使用)71            connection.setAutoCommit(false);            //查询余额是否充足(根据账户将查询对象封装成account账户返回)            //fromact是account账户对象            Account fromAct = accountDao.selectByActno(fromActno);            ///余额不足            if(fromAct.getBalance()                throw new MoneyNotEnoughException(对不起,余额不足”);            }            ///到这里说余额充足            我们继续检查另一个账户的余额            ///toact是account账户对象            Account toAct = accountDao.selectByActno(toActno);            ///修改余额(只修改内存中java对象的余额)            fromAct.setBalance(fromAct.getBalance()-money);            toAct.setBalance(toAct.getBalance()+money);            ////更新数据库中的余额            int count = accountDao.update(fromAct);            ////模拟异常///            String s = null;//            s.toString();            count += accountDao.update(toAct);            if(count != 2){                throw new AppException(”账户转账异常!= 2){                throw new AppException(“账户转帐异常!!");            }            ///提交事务            connection.commit();        } catch (SQLException e) {            throw new AppException(”账户转账异常!!!");            ///回滚事务(不屑也没关系)        }    }}

com.powernode.bank.daoCRUDAcountDao操作

package com.powernode.bank.dao;///这类负责Account的数据操作(增删改查)  67import com.powernode.bank.pojo.Account;import com.powernode.bank.utils.DBUtil;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;/** * AccountDao负责Account数据的增删改查。 * 1. DAO是什么? * 1. DAO是什么? *      Data Access Object(数据访问对象) * 2. DAO实际上是JavaEE的设计模式之一。(不是23种设计模式。) * 3. DAO只负责数据库表的CRUD,没有任何业务逻辑。 * 4. 没有任何业务逻辑,只负责表中数据的添加、删除和检查对象,有一个特殊的标题:DAO对象。 * 5. 为什么叫AccountDao? *      这是因为这个DAO是专门处理t_act表的。 *      如果处理t_user表,可以称为:UserDao *      如果处理t_student表,可以称为:StudentDao * 6. 一般情况下:一个表会对应一个DAO对象。 * 7. DAO中的方法名非常固定,一般都是: *      insert *      deleteByXxx *      update *      selectByXxx *      selectAll */public class AccountDao{    ///负责将账户信息插入数据库  67    ///之所以是int,是因为插入操作返回受影响的行数    public int insert(Account act){        PreparedStatement ps = null;        int count = 0;        try {            Connection conn = DBUtil.getConnection();            String sql = "insert into t_act(actno,balance) values(?,?)";            //获取预编译对象            ps = conn.prepareStatement(sql);            ps.setString(1,act.getActno());            ps.setDouble(2,act.getBalance());            //执行            count = ps.executeUpdate();        } catch (SQLException e) {            throw new RuntimeException();        }finally {            ///关闭资源            DBUtil.close(null,ps,null);        }        return count;    }    ///删除数据(根据id删除)  67    public int deleteById(Long id){        PreparedStatement ps = null;        int count = 0;        try {            Connection conn = DBUtil.getConnection();            String sql = "delete from t_act where id = ?";            ps = conn.prepareStatement(sql);            ps.setLong(1,id);            count = ps.executeUpdate();        } catch (SQLException e) {            throw new RuntimeException(e);        }finally {            DBUtil.close(null,ps,null);        }        return 0;    }    ///更新数据  67    public int update(Account act){        PreparedStatement ps = null;        int count = 0;        try {            Connection conn = DBUtil.getConnection();            String sql = "update t_act set balance = ? , actno = ? , actno = ? where id = ?";            ps = conn.prepareStatement(sql);            ps.setDouble(1, act.getBalance());            ps.setString(2, act.getActno());            ps.setLong(3, act.getId());            count = ps.executeUpdate();        } catch (SQLException e) {            throw new RuntimeException(e);        } finally {            DBUtil.close(null, ps, null);        }        return count;    }    ////根据账号查找数据  67    public Account selectByActno(String actno){        PreparedStatement ps = null;        ResultSet rs = null;        Account act = null;        try {            Connection conn = DBUtil.getConnection();            String sql = "select id,balance from t_act where actno = ?";            ps = conn.prepareStatement(sql);            ps.setString(1,actno);            rs = ps.executeQuery();            if(rs.next()){                Long id = rs.getLong("id");                Double balance = rs.getDouble("balance");                ///将结果集成一个java对象                act = new Account();                act.setId(id);                act.setActno(actno);                act.setBalance(balance);            }        } catch (SQLException e) {            throw new RuntimeException(e);        } finally {            DBUtil.close(null, ps, rs);        }        return act;    }    //获取所有账户  67    public List selectAll(){        PreparedStatement ps = null;        ResultSet rs = null;        List list = new ArrayList<>();        try {            Connection conn = DBUtil.getConnection();            String sql = "select id,actno,balance from t_act";            ps = conn.prepareStatement(sql);            rs = ps.executeQuery();            while(rs.next()){                ///取出数据                Long id = rs.getLong("id");                String actno = rs.getString("actno");                Double balance = rs.getDouble("balance");                ///包装对象                ///这是一个个封装               /* Account account = new Account();                account.setId(id);                account.setActno(actno);                account.setBalance(balance);*/                ///用结构方法封装                Account account = new Account(id, actno, balance);                //添加到list集合中                list.add(account);            }        } catch (SQLException e) {            throw new RuntimeException(e);        } finally {            DBUtil.close(null, ps, rs);        }        return list;    }}

com.powernode.bank.pojojavabean类Account

package com.powernode.bank.pojo;///这是Accountjavabean,负责包装数据库中的对象  67/** * 账户实体类:包装账户信息。 * 一般是一张表一张。 * pojo对象。 * 有些人也称这种专门包装数据的对象为bean对象。(javabean:咖啡豆) * 有些人也称这种专门包装数据的对象为领域模型对象。domain对象。 * 不同的程序员有不同的习惯。 * * pojo、bean、domain... */public class Account {  // 这种普通而简单的对象被称为pojo对象。    // 一般来说,不建议将该属性设计为基本数据类型,建议使用包装类型。防止null带来的问题。    //private long id;    private Long id;  //主键    private String actno;//账号    //private double balance;    private Double balance;//余额    public Account() {    }    public Account(Long id, String actno, Double balance) {        this.id = id;        this.actno = actno;        this.balance = balance;    }    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getActno() {        return actno;    }    public void setActno(String actno) {        this.actno = actno;    }    public Double getBalance() {        return balance;    }    public void setBalance(Double balance) {        this.balance = balance;    }    @Override    public String toString() {        return "Account{" +                "id=" + id +                ", actno='" + actno + '\'' +                ", balance=" + balance +                '}';    }}

com.powernode.bank.utils工具类DBUtil

package com.powernode.bank.utils;import java.sql.*;import java.util.ResourceBundle;//工具类  66public class DBUtil {    ////分配文件的属性    private static ResourceBundle bundle = ResourceBundle.getBundle("resources/jdbc");    private static String driver = bundle.getString("driver");    private static String url = bundle.getString("url");    private static String user = bundle.getString("user");    private static String password = bundle.getString("password");    ///之所以设置为私有privatete 因为不允许创建对象,因为工具类的方法是静态的,不需要创建对象    private DBUtil(){};    ///加载DBUTil类时注册驱动器    static {        try {            Class.forName(driver);        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }    //获得Threadlocal对象   73    ///这个对象实际上在服务器中只有一个  73    private static ThreadLocal local = new ThreadLocal<>();    //获取连接对象    ///这里没有数据库连接池,直接创建连接对象。    //返回连接对象    public static Connection getConnection() throws SQLException {        Connection conn = local.get();        if(conn==null){///判断不是空的(因为第一次访问conn肯定是空的)            ///为空获得一个新的conn            conn = DriverManager.getConnection(url, user, password);            ///放入conn            local.set(conn);        }        return conn;    }    ///关闭资源    /**     * 关闭资源     * @param conn 连接对象     * @param stmt 数据库操作对象     * @param rs 结果集对象     */    public static void close(Connection conn, Statement stmt, ResultSet rs){        if(rs !=null){            try {                rs.close();            } catch (SQLException e) {                throw new RuntimeException(e);            }        }        if(stmt !=null){            try {                stmt.close();            } catch (SQLException e) {                throw new RuntimeException(e);            }        }        if(conn !=null){            try {                conn.close();                // 想一想:为什么conn关闭后要从大Map中删除?=null){            try {                conn.close();                // 想一想:为什么conn关闭后要从大Map中删除?                // 根本原因是Tomcat服务器支持线程池。也就是说,一个人用过t1线程                // ,其他用户也可以使用t1线程。                local.remove();            } catch (SQLException e) {                throw new RuntimeException(e);            }        }    }}

异常类com.powernode.bank.exceptionsAppException

package com.powernode.bank.exceptions;//app异常类别  69public class AppException extends Exception{    public AppException() {    }    public AppException(String msg) {        super(msg);    }}

MoneyNotEnoughException

package com.powernode.bank.exceptions;///钱不足异常类  69public class MoneyNotEnoughException extends Exception{    //以下是两个结构器    ///无参构造器    public MoneyNotEnoughException() {    }    //有参构造器    public MoneyNotEnoughException(String msg) {        super(msg);    }}

resourcese配置文件jdbc.properties

driver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://localhost:3306/mvcuser=rootpassword=lzl

index.jsp

<%--银行转账页面   63--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html>  <head>    <title>转账页面</title>    <base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">  </head>  <body>  <form action="transfer" method="post">    转出账户:<input type="text" name="fromActno"><br>    转入账户:<input type="text" name="toActno"><br>    转账金额:<input type="text" name="money"><br>    <input type="submit" value="转账"/>  </form>  </body></html>

error.jsp

<%--转账失败页面 70--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>转账失败</title></head><body><h1>转账失败</h1></body></html>

moneynotenough.jsp

<%--页面余额不足  70--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>转账失败</title></head><body><h1>余额不足</h1></body></html>

success.jsp

<%--页面转移成功  70--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>转账成功</title></head><body><h1>转账成功</h1></body></html>