Follow Lao Du to learn MyBatis + Day 5 + apply MyBatis in WEB (using MVC architecture mode)

6. Apply MyBatis in WEB (using MVC architecture mode)

Target:

  • Master how to use mybatis in web applications
  • The scope and life cycle of the three mybatis objects
  • Principle and use of ThreadLocal
  • Consolidate the MVC architectural pattern
  • Prepare for learning the interface proxy mechanism of MyBatis

Realize the function:

  • bank account transfer

Technology used:

  • HTML + Servlet + MyBatis

The name of the web application:

  • bank

6.1 Requirements description

img

6.2 Database table design and data preparation

img

img

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 80016
 Source Host           : localhost:3306
 Source Schema         : powernode

 Target Server Type    : MySQL
 Target Server Version : 80016
 File Encoding         : 65001

 Date: 29/10/2022 17:06:33
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_act
-- ----------------------------
DROP TABLE IF EXISTS `t_act`;
CREATE TABLE `t_act`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `actno` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `balance` decimal(10, 2) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_act
-- ----------------------------
INSERT INTO `t_act` VALUES (1, 'act001', 50000.00);

SET FOREIGN_KEY_CHECKS = 1;

6.3 Implementation steps

The first step: environment construction

  • Create Maven WEB application in IDEA ( mybatis-004-web )

img

  • IDEA configures Tomcat, where Tomcat uses version 10+. And deploy the application to tomcat.

img

img

  • The maven web application created by default has no java and resources directories, including two solutions

    • The first one: add it manually.

img

    • The second: modify the configuration file in maven-archetype-webapp-1.4.jar

img

img

img

  • The version of the web.xml file is relatively low, you can copy it from the sample file of tomcat10, and then modify it
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="false">
    <!-- <servlet> -->
    <!--     <servlet-name>test</servlet-name> -->
    <!--     <servlet-class>cn.yangbocsu.bank.web.AccountServlet</servlet-class> -->
    <!-- </servlet> -->

    <!-- <servlet-mapping> -->
    <!--     <servlet-name>test</servlet-name> -->
    <!--     <url-pattern>/transfer</url-pattern> -->
    <!-- </servlet-mapping> -->
</web-app>
  • Delete the index.jsp file, because we don't use JSP for this project. Just use html.

  • Make sure that the packaging method in the pom.xml file is a war package.

  • Introduce related dependencies

    • Compiler version changed to 17
    • The introduced dependencies include: mybatis, mysql driver, junit, logback, servlet.
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>cn.yangbocsu</groupId>
  <artifactId>mybatis_004_web</artifactId>
  <packaging>war</packaging>
  <version>1.0</version>

  <!-- <name>mybatis_004_web maven</name> -->
  <name>mybatis_004_web</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.10</version>
    </dependency>
    <!--mysql驱动依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.30</version>
    </dependency>

    <!--junit依赖-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>

    <!--logback依赖-->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.11</version>
    </dependency>

    <!--servlet依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>

  </dependencies>

  <build>
    <finalName>mybatis_004_web</finalName>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

  • Introduce relevant configuration files and put them in the resources directory (all in the root path of the class)

    • mybatis-config.xml
    • AccountMapper.xml
    • logback.xml
    • jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/powernode
jdbc.username=root
jdbc.password=root
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <properties resource="jdbc.properties"/>

    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--一定要注意这里的路径哦!!!-->
        <mapper resource="AccountMapper.xml"/>
    </mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="account">

</mapper>

Step 2: front-end page index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>银行转账</title>
</head>
<body>
    <form action="/bank/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>

Step 3: Create pojo package, service package, dao package, web package, utils package

  • com.powernode.bank.pojo
  • com.powernode.bank.service
  • com.powernode.bank.service.impl
  • com.powernode.bank.dao
  • com.powernode.bank.dao.impl
  • com.powernode.bank.web.controller
  • com.powernode.bank.exception
  • com.powernode.bank.utils: Copy the previously written SqlSessionUtil tool class to this package.

Step 4: Define the pojo class: Account

package com.powernode.bank.pojo;

/**
 * 银行账户类
 * @author 老杜
 * @version 1.0
 * @since 1.0
 */
public class Account {
    
    
    private Long id;
    private String actno;
    private Double balance;

    @Override
    public String toString() {
    
    
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + 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;
    }
}

Step 5: Write AccountDao interface and AccountDaoImpl implementation class

At least several methods must be provided in the analysis dao to complete the transfer:

  • Need to check whether the balance is sufficient before transfer: selectByActno
  • To update the account when transferring money: update
package com.powernode.bank.dao;

import com.powernode.bank.pojo.Account;

/**
 * 账户数据访问对象
 * @author 老杜
 * @version 1.0
 * @since 1.0
 */
public interface AccountDao {
    
    

    /**
     * 根据账号获取账户信息
     * @param actno 账号
     * @return 账户信息
     */
    Account selectByActno(String actno);

    /**
     * 更新账户信息
     * @param act 账户信息
     * @return 1表示更新成功,其他值表示失败
     */
    int update(Account act);
}
package com.powernode.bank.dao.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;

public class AccountDaoImpl implements AccountDao {
    
    
    @Override
    public Account selectByActno(String actno) {
    
    
        SqlSession sqlSession = SqlSessionUtil.openSession();
        Account act = (Account)sqlSession.selectOne("selectByActno", actno);
        sqlSession.close();
        return act;
    }

    @Override
    public int update(Account act) {
    
    
        SqlSession sqlSession = SqlSessionUtil.openSession();
        int count = sqlSession.update("update", act);
        sqlSession.commit();
        sqlSession.close();
        return count;
    }
}

Step 6: The mybatis code is written in AccountDaoImpl, and the SQL mapping file needs to be written

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="account">
    <select id="selectByActno" resultType="com.powernode.bank.pojo.Account">
        select * from t_act where actno = #{actno}
    </select>
    <update id="update">
        update t_act set balance = #{balance} where actno = #{actno}
    </update>
</mapper>

Step 7: Write the AccountService interface and AccountServiceImpl

package com.powernode.bank.exception;

/**
 * 余额不足异常
 * @author 老杜
 * @version 1.0
 * @since 1.0
 */
public class MoneyNotEnoughException extends Exception{
    
    
    public MoneyNotEnoughException(){
    
    }
    public MoneyNotEnoughException(String msg){
    
     super(msg); }
}
package com.powernode.bank.exception;

/**
 * 应用异常
 * @author 老杜
 * @version 1.0
 * @since 1.0
 */
public class AppException extends Exception{
    
    
    public AppException(){
    
    }
    public AppException(String msg){
    
     super(msg); }
}
package com.powernode.bank.service;

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

/**
 * 账户业务类。
 * @author 老杜
 * @version 1.0
 * @since 1.0
 */
public interface AccountService {
    
    

    /**
     * 银行账户转正
     * @param fromActno 转出账户
     * @param toActno 转入账户
     * @param money 转账金额
     * @throws MoneyNotEnoughException 余额不足异常
     * @throws AppException App发生异常
     */
    void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException;
}
package com.powernode.bank.service.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.dao.impl.AccountDaoImpl;
import com.powernode.bank.exception.AppException;
import com.powernode.bank.exception.MoneyNotEnoughException;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.service.AccountService;

public class AccountServiceImpl implements AccountService {
    
    

    private AccountDao accountDao = new AccountDaoImpl();

    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {
    
    
        // 查询转出账户的余额
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
    
    
            throw new MoneyNotEnoughException("对不起,您的余额不足。");
        }
        try {
    
    
            // 程序如果执行到这里说明余额充足
            // 修改账户余额
            Account toAct = accountDao.selectByActno(toActno);
            fromAct.setBalance(fromAct.getBalance() - money);
            toAct.setBalance(toAct.getBalance() + money);
            // 更新数据库
            accountDao.update(fromAct);
            accountDao.update(toAct);
        } catch (Exception e) {
    
    
            throw new AppException("转账失败,未知原因!");
        }
    }
}

Step 8: Write AccountController

package com.powernode.bank.web.controller;

import com.powernode.bank.exception.AppException;
import com.powernode.bank.exception.MoneyNotEnoughException;
import com.powernode.bank.service.AccountService;
import com.powernode.bank.service.impl.AccountServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 账户控制器
 * @author 老杜
 * @version 1.0
 * @since 1.0
 */
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {
    
    

    //为了让这个对象在其他方法中也可以用。声明为实例变量。
    private AccountService accountService = new AccountServiceImpl();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        // 获取表单数据
        String fromActno = request.getParameter("fromActno");
        String toActno = request.getParameter("toActno");
        double money = Double.parseDouble(request.getParameter("money"));

        // 调用 service 的转账方法完成转账 (调业务层)
        // 层和层之间要用接口去衔接,目的是降低层与层之间的耦合度
        try {
    
    
            accountService.transfer(fromActno,toActno,money);
            //程序能够走到这里,表示转账-定成功了。
            //调用 View 完成展示结果。
            response.sendRedirect(request.getContextPath() + "/success.html");
        } catch (MoneyNotEnoughException e) {
    
    
            response.sendRedirect(request.getContextPath() + "/error1.html");
        } catch (TransferException e) {
    
    
            response.sendRedirect(request.getContextPath() + "/error2.html");
        }catch (Exception e) {
    
    
            response.sendRedirect(request.getContextPath() + "/error2.html");
        }
        // 调用视图层 完成展示结果
    }
}

Start the server, open the browser, enter the address: http://localhost:8080/bank, test:

img

img

img

6.4 MyBatis object scope and transaction issues

The scope of MyBatis core objects

SqlSessionFactoryBuilder

This class can be instantiated, used and discarded, once the SqlSessionFactory is created, it is no longer needed. So the best scope for an instance of SqlSessionFactoryBuilder is method scope (that is, local method variables). You can reuse SqlSessionFactoryBuilder to create multiple SqlSessionFactory instances, but it's best not to keep it around all the time to ensure that all XML parsing resources can be released for more important things.

SqlSessionFactory

Once created, the SqlSessionFactory should exist for the duration of the application, there is no reason to discard it or create another instance. The best practice for using SqlSessionFactory is not to create multiple times during the running of the application. Rebuilding SqlSessionFactory multiple times is considered a code "bad habit". So the best scope for SqlSessionFactory is application scope. There are many ways to do it, the easiest is to use the singleton pattern or the static singleton pattern.

SqlSession

Each thread should have its own instance of SqlSession. Instances of SqlSession are not thread-safe and therefore cannot be shared, so its best scope is request or method scope. You should never place a reference to an instance of SqlSession in a static field of a class, not even an instance variable of a class. You must also never place references to SqlSession instances in any type of managed scope, such as HttpSession in the Servlet framework. If you're using a web framework today, consider putting the SqlSession in a scope similar to HTTP requests. In other words, every time an HTTP request is received, a SqlSession can be opened, and after a response is returned, it can be closed. This closing operation is very important. In order to ensure that the closing operation can be performed every time, you should put this closing operation in the finally block. The following example is a standard pattern to ensure that the SqlSession is closed:

try (SqlSession session = sqlSessionFactory.openSession()) {
    
    
  // 你的应用逻辑代码
}

business problem

In the previous transfer business, two accounts were updated. We need to ensure that they succeed or fail at the same time. At this time, we need to use the transaction mechanism to start the transaction when the transfer method starts to execute until both updates are successful. To commit the transaction, we try to modify the transfer method as follows:

package com.powernode.bank.service.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.dao.impl.AccountDaoImpl;
import com.powernode.bank.exception.AppException;
import com.powernode.bank.exception.MoneyNotEnoughException;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.service.AccountService;
import com.powernode.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;

public class AccountServiceImpl implements AccountService {
    
    

    private AccountDao accountDao = new AccountDaoImpl();

    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {
    
    
        // 查询转出账户的余额
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
    
    
            throw new MoneyNotEnoughException("对不起,您的余额不足。");
        }
        try {
    
    
            // 程序如果执行到这里说明余额充足
            // 修改账户余额
            Account toAct = accountDao.selectByActno(toActno);
            fromAct.setBalance(fromAct.getBalance() - money);
            toAct.setBalance(toAct.getBalance() + money);
            // 更新数据库(添加事务)
            SqlSession sqlSession = SqlSessionUtil.openSession();
            accountDao.update(fromAct);
            // 模拟异常
            String s = null;
            s.toString();
            
            accountDao.update(toAct);
            sqlSession.commit();
            sqlSession.close();
        } catch (Exception e) {
    
    
            throw new AppException("转账失败,未知原因!");
        }
    }
}

Pay attention to the current data in the database table before running:

img

execute program:

img

img

View the data in the database table again:

img

Dumbfounded now! ! ! There was a problem with the transaction, the transfer failed, and the money was still missing by 10,000. What is the reason? The main reason is that the SqlSession objects used in service and dao are not the same.

what to do? In order to ensure that the SqlSession object used in service and dao is the same, you can store the SqlSession object in ThreadLocal. Modify the SqlSessionUtil tool class:

package com.powernode.bank.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * MyBatis工具类
 *
 * @author 老杜
 * @version 1.0
 * @since 1.0
 */
public class SqlSessionUtil {
    
    
    private static SqlSessionFactory sqlSessionFactory;

    /**
     * 类加载时初始化sqlSessionFactory对象
     */
    static {
    
    
        try {
    
    
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    private static ThreadLocal<SqlSession> local = new ThreadLocal<>();   // 新增加的

    /**
     * 每调用一次openSession()可获取一个新的会话,该会话支持自动提交。
     *
     * @return 新的会话对象
     */
    public static SqlSession openSession() {
    
    
        SqlSession sqlSession = local.get();
        if (sqlSession == null) {
    
    
            sqlSession = sqlSessionFactory.openSession();
            local.set(sqlSession);
        }
        return sqlSession;
    }

    /**
     * 关闭SqlSession对象
     * @param sqlSession
     */
    public static void close(SqlSession sqlSession){
    
    
        if (sqlSession != null) {
    
    
            sqlSession.close();
        }
        local.remove();
    }
}

Modify the method in dao: all the commit and close codes in all methods in AccountDaoImpl are deleted.

package com.powernode.bank.dao.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;

public class AccountDaoImpl implements AccountDao {
    
    
    @Override
    public Account selectByActno(String actno) {
    
    
        SqlSession sqlSession = SqlSessionUtil.openSession();
        Account act = (Account)sqlSession.selectOne("account.selectByActno", actno);
        return act;
    }

    @Override
    public int update(Account act) {
    
    
        SqlSession sqlSession = SqlSessionUtil.openSession();
        int count = sqlSession.update("account.update", act);
        return count;
    }
}

Modify the method in service:

package com.powernode.bank.service.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.dao.impl.AccountDaoImpl;
import com.powernode.bank.exception.AppException;
import com.powernode.bank.exception.MoneyNotEnoughException;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.service.AccountService;
import com.powernode.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;

public class AccountServiceImpl implements AccountService {
    
    

    private AccountDao accountDao = new AccountDaoImpl();

    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {
    
    
        // 查询转出账户的余额
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
    
    
            throw new MoneyNotEnoughException("对不起,您的余额不足。");
        }
        try {
    
    
            // 程序如果执行到这里说明余额充足
            // 修改账户余额
            Account toAct = accountDao.selectByActno(toActno);
            fromAct.setBalance(fromAct.getBalance() - money);
            toAct.setBalance(toAct.getBalance() + money);
            // 更新数据库(添加事务)
            SqlSession sqlSession = SqlSessionUtil.openSession();
            accountDao.update(fromAct);
            // 模拟异常
            String s = null;
            s.toString();
            accountDao.update(toAct);
            sqlSession.commit();
            SqlSessionUtil.close(sqlSession);  // 只修改了这一行代码。
        } catch (Exception e) {
    
    
            throw new AppException("转账失败,未知原因!");
        }
    }
}

Data in the current database table:

img

Run the program again:

img

img

Looking at the database tables: no problem.

img

Retest the transfer is successful:

img

img

img

If the balance is insufficient:

img

img

The balance of the account is still normal:

img

6.5 Analyze the problems existing in the current program

Let's take a look at the code of DaoImpl

package com.powernode.bank.dao.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;

public class AccountDaoImpl implements AccountDao {
    
    
    @Override
    public Account selectByActno(String actno) {
    
    
        SqlSession sqlSession = SqlSessionUtil.openSession();
        Account act = (Account)sqlSession.selectOne("account.selectByActno", actno);
        return act;
    }

    @Override
    public int update(Account act) {
    
    
        SqlSession sqlSession = SqlSessionUtil.openSession();
        int count = sqlSession.update("account.update", act);
        return count;
    }
}

It is not difficult to find that the method code in this dao implementation class is very fixed. It is basically a line of code. Methods such as insert, delete, update, and select are called through the SqlSession object. The methods in this class do not have any business logic. Since this is the case, Can we dynamically generate this class , and can we not write this class in the future? Answer: Yes.

Guess you like

Origin blog.csdn.net/qq_38689263/article/details/127618955