MVC模式分层练习

新建库

新建表

插入点数据

先不用MVC模式写功能,来看下缺点是什么

新建一个空项目

选项项目使用的JDK

自己的IDEA总是要重启下

新建模块

因maven还没教

添加框架支持

添加后项目多了这些

添加些必要依赖  这里注意下,如果导入jar包不对可以重新导入下或者是jar包本身出了问题

添加页面

配置Tomcat

启动

请求地址  因现在没有后端

现在写后端 并测试

解决控制台输出乱码问题

System.out输出乱码

需要用到JDBC连接Mysql数据库

导入Mysql驱动jar包

java web项目  一般会在WEB-INF下有个lib用来放Tomcat内没有,外部引入的依赖

可以创建个lib目录  然后将jar包复制进来

具体代码

package com.bank.web;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;

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.*;
import java.sql.*;
import java.util.Locale;

/**
 * 在不使用MVC架构模式的前提下,完成银行账户转账
 * 分析这个程序存在哪些问题?
 * @author hrui
 * @date 2023/8/31 23:06
 */
@WebServlet("/transfer")
public class AccountTransferServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //获取响应流对象
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        //获取前端传来的参数
        String fromActno = req.getParameter("fromActno");
        String toActno = req.getParameter("toActno");
        double money = Double.parseDouble(req.getParameter("money"));
//        System.out.println("转出账户:"+fromActno);
//        System.out.println("转入账户:"+fromActno);
//        System.out.println("转账金额:"+fromActno);


        //编写转账的业务逻辑代码,连接数据库,进行转账操作
        //1.转账之前要判断转出账户的余额是否充足

        Connection conn=null;
        PreparedStatement ps=null;
        //PreparedStatement ps2=null;
        ResultSet rs=null;

        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //获取连接
            conn = DriverManager.getConnection("xxx", "xxx", "xxx");
            conn.setAutoCommit(false);
            //获取执行对象
            String sql="select balance from t_act where actno=?";
            ps = conn.prepareStatement(sql);

            ps.setString(1, fromActno);
            //执行sql,返回结果集
            rs = ps.executeQuery();
            //获取结果集
            if(rs.next()){
                double balance = rs.getDouble("balance");
                if(balance<money){
                    //余额不足(使用异常处理机制)
                    throw new MoneyNotEnoughException("余额不足");
                }
                //程序能到这里,说明余额重组  不需要else
                //开始转账
                sql="update t_act set balance=balance-? where actno=?";
                ps = conn.prepareStatement(sql);
                ps.setDouble(1, money);
                ps.setString(2, fromActno);
                int count = ps.executeUpdate();

                //模拟异常
                String str=null;
                str.toString();

                sql="update t_act set balance=balance+? where actno=?";
                ps=conn.prepareStatement(sql);
                ps.setDouble(1, money);
                ps.setString(2, toActno);
                //累计
                count += ps.executeUpdate();
                if(count!=2){
                    throw new AppException("app异常,请联系管理员");
                }
            }
            conn.commit();
            writer.print("转账成功");
        } catch (ClassNotFoundException | SQLException | MoneyNotEnoughException | AppException e) {
            try {
                if(conn!=null) {
                    conn.rollback();
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
            writer.print(e.getMessage());
        }finally {
            //释放资源,根据JDBC规范 从小到大
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(ps!=null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

1>负责了数据接收

2>负责了核心业务处理

3>负责了数据库表中的CRUD操作(Create(增) Retrieve(查) Update(改) Delete(删))

4>负责了数据的页面展示

引起的缺点:

代码复用性差  比如查余额,可以抽取出来,单独放到一个方法

代码复用性差的原因,没有职能分工,独立组件的概念,代码之间耦合度高,扩展力差

操作数据库代码和业务逻辑混杂在一起,容易出错,无法专注于业务逻辑书写

下面以MVC的模式对上面代码改进

1.系统为什么要分层?

        希望专人干专事.各司其职.分工明确.这样可以降低耦合,扩展增强.复用增强

2.软件架构中,有一个非常著名的架构模式:MVC模式

M(Model:数据/业务)       V(View:视图/展示)       C(Controller:控制器/核心)

首先是对JDBC的封装

JDBC工具类

package com.bank.utils;

import java.sql.*;
import java.util.ResourceBundle;

/**
 * @author hrui
 * @date 2023/9/1 10:24
 */
public 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 username=bundle.getString("username");

    private static String password=bundle.getString("password");

    //不让创建对象,原因工具类方法一般都静态的,无需外部创建对象
    //为防止外部创建对象,构造私有化
    private DBUtil(){

    }

    //DBUtil类加载时注册驱动
    static{
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //没有使用连接池,直接创建的连接对象
    public static Connection getConnection() throws SQLException {
        Connection conn= DriverManager.getConnection(url,username,password);
        return conn;
    }

    public static void close(Connection conn, Statement statement, ResultSet rs){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

测试连接

封装实体类

package com.bank.mvc;

import java.util.Objects;

/**
 * 账户实体类,用于封装账户信息
 * POJO对象
 * 有的人也会把这种专门封装数据的对象,称为bean对象(javabean:咖啡豆)
 * 有的人也会把这种专门分装数据的对象,称为领域模型对象.domain对象.
 * pojo,bean,domain
 * @author hrui
 * @date 2023/9/1 15:34
 */
public class Account {

    private Long id;
    private String actno;
    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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Account acount = (Account) o;
        return id.equals(acount.id) && actno.equals(acount.actno) && balance.equals(acount.balance);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, actno, balance);
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }
}

编写DAO层

package com.bank.mvc;

import com.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;

/**
 * 负责Acount数据的增删改查
 * 1.什么是DAO
 *      Data Access Object(数据访问对象)
 * 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)
 * 3.DAO只负责数据库CRUD,没有任何业务逻辑
 * 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象
 * @author hrui
 * @date 2023/9/1 12:39
 */
public class AccountDao {

    public int insert(Account act){
        Connection conn=null;
        PreparedStatement ps=null;
        int count=0;
        try {
            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) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }
        return count;
    }

    public int deleteByActno(Long id){
       Connection conn=null;
       PreparedStatement ps=null;
       int count=0;
        try {
            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) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }
        return count;
    }

    public int update(Account act){
        Connection conn=null;
        PreparedStatement ps=null;
        int count=0;
        try {
            conn=DBUtil.getConnection();
            String sql="update t_act set balance=? where id=?";
            ps=conn.prepareStatement(sql);
            ps.setDouble(1, act.getBalance());
            ps.setLong(2, act.getId());
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }
        return count;
    }

    public Account selectBtActNo(String actno){
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Account account=new Account();
        try {
            conn=DBUtil.getConnection();
            String sql="select id,actno,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");
                String actno1=rs.getString("actno");
                Double balance=rs.getDouble("balance");
                account.setId(id);
                account.setActno(actno1);
                account.setBalance(balance);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }

        return account;
    }

    public List<Account> selectAll(){
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        List<Account> list=new ArrayList<>();
        try {
            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);
                list.add(account);
            }
        } catch (SQLException e) {

            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }
        return list;
    }
}

原先在Servlet里

1>负责了数据接收

2>负责了狠心业务处理

3>负责了数据库表中数据CRUD操作

4>负责了页面数据展示

现在已经一层层分离了

两个异常类

用AccountSAervice来做业务处理

具体业务处理代码

package com.bank.mvc;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;

/**
 * Service:业务
 * 专门处理Account的业务处理类
 * 该类只专注业务处理
 * 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以
 * @author hrui
 * @date 2023/9/2 0:49
 */
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 {
        //查询余额是否充足
        Account fromAccount = accountDao.selectBtActNo(fromActno);
        if(fromAccount.getBalance()<money){
            throw new MoneyNotEnoughException("余额不足");
        }
        //程序到这里说明余额够
        Account toAct=accountDao.selectBtActNo(toActno);

        //修改余额
        fromAccount.setBalance(fromAccount.getBalance()-money);
        toAct.setBalance(toAct.getBalance()+money);

        //更新数据库
        int count=accountDao.update(fromAccount);

        count += accountDao.update(toAct);
        //count++;
        if(count!=2){
            throw new AppException("转账异常");
        }

    }


}

servlet里做的就是调度

package com.bank.mvc;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;

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;

/**
 * 让AcountServlet做为Controller  调度员
 * 负责调度其他组件
 * @author hrui
 * @date 2023/9/1 12:27
 */
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //获取前端传来的参数
        String fromActno = req.getParameter("fromActno");
        String toActno = req.getParameter("toActno");
        double money = Double.parseDouble(req.getParameter("money"));

        //调用业务方法处理业务(调度Model处理业务)
        AccountService accountService=new AccountService();
        try {
            accountService.transfer(fromActno,toActno,money);
            resp.sendRedirect(req.getContextPath()+"/success.jsp");
        } catch (MoneyNotEnoughException e) {
            e.printStackTrace();
            resp.sendRedirect(req.getContextPath()+"/moneynoenough.jsp");
        } catch (AppException e) {
            e.printStackTrace();
            resp.sendRedirect(req.getContextPath()+"/error.jsp");
        }

    }
}

三个页面显示

 

上面代码缺少事务控制,一般事务都在service进行控制

一般来说是在service层去开启事务  提交事务

这里事务管理,做的low的方式就是在业务层获取数据库连接对象,然后传进去,当然这样做的话,在DAO层就不要在finally中关闭事务了.传个null就行,在Service中开启事务,并在Service中提交事务,在Service中的finally中关闭连接

上代码

DAO

package com.bank.mvc;

import com.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;

/**
 * 负责Acount数据的增删改查
 * 1.什么是DAO
 *      Data Access Object(数据访问对象)
 * 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)
 * 3.DAO只负责数据库CRUD,没有任何业务逻辑
 * 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象
 * @author hrui
 * @date 2023/9/1 12:39
 */
public class AccountDao {

    public int insert(Account act,Connection conn){

        PreparedStatement ps=null;
        int count=0;
        try {

            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) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public int deleteByActno(Long id,Connection conn){

       PreparedStatement ps=null;
       int count=0;
        try {

            String sql="delete from t_act where id=?";
            ps=conn.prepareStatement(sql);
            ps.setLong(1, id);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public int update(Account act,Connection conn){

        PreparedStatement ps=null;
        int count=0;
        try {

            String sql="update t_act set balance=? where id=?";
            ps=conn.prepareStatement(sql);
            ps.setDouble(1, act.getBalance());
            ps.setLong(2, act.getId());
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public Account selectBtActNo(String actno,Connection conn){

        PreparedStatement ps=null;
        ResultSet rs=null;
        Account account=new Account();
        try {

            String sql="select id,actno,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");
                String actno1=rs.getString("actno");
                Double balance=rs.getDouble("balance");
                account.setId(id);
                account.setActno(actno1);
                account.setBalance(balance);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }

        return account;
    }

    public List<Account> selectAll(Connection conn){
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        List<Account> list=new ArrayList<>();
        try {

            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);
                list.add(account);
            }
        } catch (SQLException e) {

            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return list;
    }
}

Service

package com.bank.mvc;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;
import com.bank.utils.DBUtil;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * Service:业务
 * 专门处理Account的业务处理类
 * 该类只专注业务处理
 * 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以
 * @author hrui
 * @date 2023/9/2 0:49
 */
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层控制事务
        //开启事务(需要用到Connection对象)
        Connection conn=null;
        try {
           conn = DBUtil.getConnection();
           conn.setAutoCommit(false);
            //查询余额是否充足
            Account fromAccount = accountDao.selectBtActNo(fromActno,conn);
            if(fromAccount.getBalance()<money){
                throw new MoneyNotEnoughException("余额不足");
            }
            //程序到这里说明余额够
            Account toAct=accountDao.selectBtActNo(toActno,conn);

            //修改余额
            fromAccount.setBalance(fromAccount.getBalance()-money);
            toAct.setBalance(toAct.getBalance()+money);

            //更新数据库
            int count=accountDao.update(fromAccount,conn);

            count += accountDao.update(toAct,conn);
//        String str=null;
//        str.toString();
            //或者
            //count++;  会向用户提示转账失败  但是转账确已经完成   或者1账户减款而2账户没有加的情况
            if(count!=2){
                throw new AppException("转账异常");
            }
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,null,null);
        }


    }


}

 

但上面代码有点low

如何解决Connection传参问题

用ThreadLocal

改造代码

DBUtil

package com.bank.utils;

import java.sql.*;
import java.util.ResourceBundle;

/**
 * @author hrui
 * @date 2023/9/1 10:24
 */
public 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 username=bundle.getString("username");

    private static String password=bundle.getString("password");

    //不让创建对象,原因工具类方法一般都静态的,无需外部创建对象
    //为防止外部创建对象,构造私有化
    private DBUtil(){

    }

    //DBUtil类加载时注册驱动
    static{
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    private static ThreadLocal<Connection> local=new ThreadLocal<>();

    //没有使用连接池,直接创建的连接对象
    public static Connection getConnection() throws SQLException {
        Connection conn=local.get();
        if(conn==null) {
            conn = DriverManager.getConnection(url, username, password);
            local.set(conn);
        }
        return conn;
    }



    public static void close(Connection conn, Statement statement, ResultSet rs){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
                //注意:关闭连接时候移除  Tomcat是支持线程池的,不从当前线程里移除 有可能下次别人拿到了,但是conn已经关闭
                local.remove();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

将AccountDao恢复原状,还是从DBUtil里取Connection,但是不需要再传参数,注意finally里面Connection照样传null,原因:还是需要在Service层进行事务控制

package com.bank.mvc;

import com.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;

/**
 * 负责Acount数据的增删改查
 * 1.什么是DAO
 *      Data Access Object(数据访问对象)
 * 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)
 * 3.DAO只负责数据库CRUD,没有任何业务逻辑
 * 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象
 * @author hrui
 * @date 2023/9/1 12:39
 */
public class AccountDao {

    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) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public int deleteByActno(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) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public int update(Account act){
        PreparedStatement ps=null;
        int count=0;
        try {
           Connection conn=DBUtil.getConnection();
            String sql="update t_act set balance=? where id=?";
            ps=conn.prepareStatement(sql);
            ps.setDouble(1, act.getBalance());
            ps.setLong(2, act.getId());
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public Account selectBtActNo(String actno){
        PreparedStatement ps=null;
        ResultSet rs=null;
        Account account=new Account();
        try {
           Connection conn=DBUtil.getConnection();
            String sql="select id,actno,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");
                String actno1=rs.getString("actno");
                Double balance=rs.getDouble("balance");
                account.setId(id);
                account.setActno(actno1);
                account.setBalance(balance);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }

        return account;
    }

    public List<Account> selectAll(){
        PreparedStatement ps=null;
        ResultSet rs=null;
        List<Account> 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);
                list.add(account);
            }
        } catch (SQLException e) {

            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return list;
    }
}

业务层

package com.bank.mvc;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;
import com.bank.utils.DBUtil;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * Service:业务
 * 专门处理Account的业务处理类
 * 该类只专注业务处理
 * 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以
 * @author hrui
 * @date 2023/9/2 0:49
 */
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 {
        try(Connection conn= DBUtil.getConnection()){
            conn.setAutoCommit(false);
            //查询余额是否充足
            Account fromAccount = accountDao.selectBtActNo(fromActno);
            if(fromAccount.getBalance()<money){
                throw new MoneyNotEnoughException("余额不足");
            }
            //程序到这里说明余额够
            Account toAct=accountDao.selectBtActNo(toActno);

            //修改余额
            fromAccount.setBalance(fromAccount.getBalance()-money);
            toAct.setBalance(toAct.getBalance()+money);

            //更新数据库
            int count=accountDao.update(fromAccount);

            count += accountDao.update(toAct);
//        String str=null;
//        str.toString();
            //或者
            //count++;  会向用户提示转账失败  但是转账确已经完成   或者1账户减款而2账户没有加的情况
            if(count!=2){
                throw new AppException("转账异常");
            }
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new AppException("转账异常");
        }


    }


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/101145.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中东 Shopify 如何使用 Bytebase 构建一站式数据库开发工作流

公司简介 Salla 是一家 2016 年成立&#xff0c;位于沙特麦加的自建站电商平台。 作为中东 Shopify&#xff0c;其最大的特点是支持阿拉伯语建站&#xff0c;并且提供更多适应中东地区特点的本地化服务。截止目前&#xff0c;已有 47,000 家店铺入驻 Salla&#xff0c;商品销售…

已解决‘jupyter‘ 不是内部或外部命令,也不是可运行的程序或批处理文件报错

本文摘要&#xff1a;本文已解决‘jupyter‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件的相关报错问题&#xff0c;并系统性地总结提出了几种可用解决方案。同时结合人工智能GPT排除可能得隐患及错误。 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲…

C++--动态规划其他问题

1.一和零 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#xff0…

ubuntu学习(六)----文件编程实现cp指令

1 思路 Linux要想复制一份文件通常指令为&#xff1a; cp src.c des.c 其中src.c为源文件&#xff0c;des.c为目标文件。 要想通过文件编程实现cp效果&#xff0c;思路如下 1 首先打开源文件 src.c 2 读src到buf 3 创建des.c 4 将buf写入到des.c 5 close两个文件 2 实现 vi …

容器技术Linux Namespaces和Cgroups

对操作系统了解多少&#xff0c;仅仅敲个命令吗 操作系统虚拟化&#xff08;容器技术&#xff09;的发展历程 1979 年&#xff0c;UNIX 的第 7 个版本引入了 Chroot 特性。Chroot 现在被认为是第一个操作系统虚拟化&#xff08;Operating system level virtualization&#x…

如何在 Vue TypeScript 项目使用 emits 事件

Vue是构建出色的Web应用程序的最灵活、灵活和强大的JavaScript框架之一。Vue中最重要的概念和关键特性之一是能够促进应用程序组件之间的通信。让我们深入探讨一下Vue中的“emits”概念&#xff0c;并了解它们如何以流畅和无缝的方式实现父子组件之间的通信。 Vue中的emits是什…

工控上位机程序为什么只能用C语言?

工控上位机程序并不只能用C#开发&#xff0c;实际上在工业自动化领域中&#xff0c;常见的上位机开发语言包括但不限于以下几种&#xff1a;C#: C#是一种常用的编程语言&#xff0c;在工控领域中被广泛使用。它具有良好的面向对象特性和丰富的类库支持&#xff0c;可以实现高性…

艾昆纬携手亚马逊云科技赋能生物医药企业,加速武田数字化转型

IQVIA艾昆纬是全球以及中国医疗健康服务领域的领导者&#xff0c;利用其数据及分析&#xff0c;前沿数字化技术和医疗领域的专业知识&#xff0c;智能连接医疗生态的各个环节。过去几年&#xff0c;IQVIA艾昆纬所服务的生物医药行业客户武田中国也迎来了数字化转型的高潮。 武田…

习题练习 C语言(暑期第三弹)

自我小提升&#xff01; 前言一、存储地址二、逗号表达式三、除自身以外数组的乘积四、字节与二进制五、符号计算六、不用加减乘除做加法七、unsigned判断八、移位计算九、sizeof宏十、移位计算十一、移位计算十二、优先级判断十三、单词倒排总结 前言 重要的事说三遍&#xf…

工厂方法模式的概述和使用

目录 一、工厂方法模式概述1. 定义2. 使用动机 二、工厂方法模式结构1. 模式结构2. 时序图 三、工厂方法模式的使用实例四、工厂方法模式的优缺点五、工厂方法模式在Java中应用 原文链接 一、工厂方法模式概述 1. 定义 工厂方法模式(Factory Method Pattern)又称为工厂模式&…

python3+requests:接口自动化测试(二)

前言&#xff1a;上篇文章python3requestsunittest&#xff1a;接口自动化测试&#xff08;一&#xff09;&#xff1a;已经介绍了基于unittest框架的实现接口自动化&#xff0c;但是也存在一些问题&#xff0c;比如最明显的测试数据和业务没有区分开&#xff0c;接口用例不便于…

禅道项目管理系统 - 操作使用 (2023版)

1. 部门-用户-权限 新增部门 新增用户 设置权限 2. 项目集创建 项目集 - 添加项目集 3. 产品线创建 产品 - 产品线 4. 产品创建 产品 - 产品列表 - 添加产品 5. 产品计划创建 产品 - xx产品 - 计划 - 创建计划 我这里创建3个计划 (一期, 二期, 三期) 6. 研发需求 - 创建模块…

设计模式-中介者模式

文章目录 一、前言二、中介者模式1、定义2、未使用/使用中介者模式对比2.1、未使用中介者模式&#xff1a;2.2、使用中介者模式&#xff1a; 3、角色分析3.1、中介者&#xff08;Mediator&#xff09;&#xff1a;3.2、同事&#xff08;Colleague&#xff09;&#xff1a;3.3、…

Springboot2.0 上传图片 jar包导出启动(第二章)

目录 一&#xff0c;目录文件结构讲解二&#xff0c;文件上传实战三&#xff0c;jar包方式运行web项目的文件上传和访问处理&#xff08;核心知识&#xff09;最后 一&#xff0c;目录文件结构讲解 简介&#xff1a;讲解SpringBoot目录文件结构和官方推荐的目录规范 1、目录讲解…

SAP_ABAP_接口技术_RFC远程函数实践总结

SAP ABAP顾问能力模型梳理_企业数字化建设者的博客-CSDN博客SAP Abap顾问能力模型&#xff0c;ALV/REPORT|SMARTFROM|SCREEN|OLE|BAPI|BDC|PI|IDOC|RFC|API|WEBSERVICE|Enhancement|UserExits|Badi|Debughttps://blog.csdn.net/java_zhong1990/article/details/132469977 SAP接…

RabbitMQ-常用命令

RabbitMQ常用命令 3.1 启动停止rabbitMQ命令 # 前台启动Erlang VM 和 RabbitMQ 当窗口关闭或者ctrlc时&#xff0c;使退出了。 rabbitmq-server# 使用系统命令启动 systemctl start rabbitmq-server# 后台启动 rabbitmq-server -detached# 停止rabbitMQ和Erlang VM rabbitmq-…

【Python基础教程】快速找到多个字典中的公共键(key)的方法

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 方法一&#xff1a;for in循环 from random import randint, samplea1 {k: randint(1, 4) for k in abcdefg} a2 {k: randint(1, 4) for k in abc123456…

【OpenCV入门】第七部分——图像的几何变换

文章结构 缩放dsize参数实现缩放fx参数和fy参数实现缩放 翻转仿射变换平移旋转倾斜 透视cmath模块 缩放 通过resize()方法可以随意更改图像的大小比例&#xff1a; dst cv2.resize(src, dsize, fx, fy, interpolation)src&#xff1a; 原始图像dsize&#xff1a; 输出图像的…

代码随想录—力扣算法题:19删除链表的倒数第N个节点.Java版(示例代码与导图详解)

19.删除链表的倒数第N个节点 力扣题目链接 更多内容可点击此处跳转到代码随想录&#xff0c;看原版文件 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 进阶&#xff1a;你能尝试使用一趟扫描实现吗&#xff1f; 示例 1&#xff1…

六、vim编辑器的使用

1、编辑器 (1)编辑器就是一款软件。 (2)作用就是用来编辑文件&#xff0c;譬如编辑文字、编写代码。 (3)Windows中常用的编辑器&#xff0c;有自带的有记事本(notepad)&#xff0c;比较好用的notepad、VSCode等。 (4)Linux中常用的编辑器&#xff0c;自带的最古老的vi&…