0


【MyBatis】| 在WEB中应⽤MyBatis(使⽤MVC架构模式)

一:在WEB中应⽤MyBatis(使⽤MVC架构模式)

目标:

①掌握mybatis在web应⽤中怎么⽤

②mybatis三⼤对象的作⽤域和⽣命周期

③ThreadLocal原理及使⽤

④巩固MVC架构模式

⑤为学习MyBatis的接⼝代理机制做准备

实现功能:银⾏账户转账

使⽤技术: HTML + Servlet + MyBatis

WEB应⽤的名称: bank

1. 前期准备

(1)数据库表准备

设计表结构

插入数据

(2)在Web应用中使用Mybatis搭建环境,创建一个Web应用,并添加本地的Tomcat服务器,然后在进行资源的配置

①在pom.xml文件中引入依赖

<?xml version="1.0" encoding="UTF-8"?>

<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>
  
  <name>mybatis-004-web</name>
  <groupId>com.bjpowernode</groupId>
  <artifactId>mybatis-004-web</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <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>5.1.23</version>
    </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>3.1.0</version>
    </dependency>
  </dependencies>

</project>

②一些配置文件的引入

③编写前端转账页面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>

④使用MVC架构模式创建包

解释:dao是连接数据库、pojo是普通的java类、service是编写业务、utils是工具类、web是servlet

(1)按照三层架构分析:web是表示层、service是业务层、dao是持久化层。
(2)按照MVC架构模式分析:pojo、dao、service属于M、所有的.jsp属于V、web属于C。(3)MVC架构模式和三层的关系:M是包括业务层和持久层,V和C属于表示层。

pojo类,封装账户信息

package com.bjpowernode.bank.pojo;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.pojo
 * @Project:mybatis
 * @name:Account
 * @Date:2023/1/1 17:53
 */
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;
    }
    // setter and getter
    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;
    }
    // 重写toString
    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }
}

工具类,连接数据库的类

package com.bjpowernode.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;

import java.io.IOException;

public class SqlSessionUtils {
    public SqlSessionUtils() {
    }
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession openSession(){
        return sqlSessionFactory.openSession();
    }

}

2. 核心代码实现

细节:在web.xml文件中有一个配置,metadata-complete="true">表示只支持配置文件的形式,不支持注解的形式开发;等于false表示两个都支持!

主要框架形式和所需要的展示页面

①bao包:连接数据库的操作,面向接口编程,接口和对应的额实现类

②exception包:抛出异常,一个是余额不足抛出的异常,一个是转账过程出现的异常

③pojo包:封装数据的,普通的java类

④service包:编写业务逻辑代码的,面向接口编程,接口和对应的额实现类

⑤utils包:连接数据库的代码封装

⑥web包:编写servlet,是司令官,进行调度的

①index.html是前端提交数据的页面,输入转账信息的

②money-not-enough.html是转出余额不足,所展示结果的页面

③success.html是转账成功的页面

④transfer-error.html是转账出现问题的页面

①AccountMapper.xml:专门编写sql语句的

②jdbc.properties:连接数据库所需要的配置信息

③logbaxk.xml:日志配置信息

④mybatis-config.xml:引入日志、读取连接数据库配置文件、连接数据库、关联AccountMapper.xml配置文件等信息的核心配置文件

(1)编写servlet,根据前端发送的请求,编写AccountServlet,这个Servlet相当于司令官C,调度两个秘书M和V

package com.bjpowernode.bank.web;

import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;
import com.bjpowernode.bank.service.AccountService;
import com.bjpowernode.bank.service.impl.AccountServiceImpl;

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;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.web
 * @Project:mybatis
 * @name:AccountServlet
 * @Date:2023/1/1 19:23
 */
@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"));
        // AccountService accountService = new AccountServiceImpl(); // 面向接口编程
        try {
            // 调用service的转账方法完成转账(调度业务层-M)
            accountService.transfer(fromActno,toActno,money);
            // 调用View完成展示结果
            // 转账成功,跳转页面
            response.sendRedirect(request.getContextPath()+"/success.html");
        } catch (MoenyNotEnoughException e) {
            // 钱不够,跳转页面
            response.sendRedirect(request.getContextPath()+"/money-not-enough.html");
        } catch (TransferException e) {
            // 转账失败,跳转页面
            response.sendRedirect(request.getContextPath()+"/transfer-error.html");
        }

    }
}

余额不足money-not-enough.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>余额不足</title>
</head>
<body>
    <h1>余额不足</h1>
</body>
</html>

转账成功success.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转账成功</title>
</head>
<body>
    <h1>转账成功</h1>
</body>
</html>

转账失败transfer-error.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>转账失败</title>
</head>
<body>
    <h1>转账失败</h1>
</body>
</html>

(2)上面逻辑发现是司令官Servlet调用业务逻辑代码(M)完成转账操作,所以需要编写AccountService接口和AccountServiceImpl实现类

AccountService接口

package com.bjpowernode.bank.service;

import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;

public interface AccountService {
    /**
     * 账户转账
     * @param fromActno 转账账号
     * @param toActno 转入账号
     * @param money 转账金额
     */
    void transfer(String fromActno,String toActno,double money) throws MoenyNotEnoughException, TransferException;
}

AccountServiceImpl实现类

package com.bjpowernode.bank.service.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.bao.impl.AccountDaoImpl;
import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.service.AccountService;

/** 编写业务逻辑代码
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.service.impl
 * @Project:mybatis
 * @name:AccountServiceImpl
 * @Date:2023/1/1 19:40
 */
public class AccountServiceImpl implements AccountService {---
   // 修改数据的类
   private AccountDao accountDao = new AccountDaoImpl();
    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoenyNotEnoughException, TransferException {
        // 判断转出账户的余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            // 如果转出账户余额不足,抛出异常提示用户
            throw new MoenyNotEnoughException("对不起,余额不足");
        }
        // 如果余额充足,更新转出和转入账户余额
        Account toAct = accountDao.selectByActno(toActno);
        // 修改内存中的余额
        fromAct.setBalance(fromAct.getBalance()-money);
        toAct.setBalance(toAct.getBalance()+money);
        // 修改数据库当中余额
        int count = accountDao.updateByActno(fromAct);
        count += accountDao.updateByActno(toAct);
        if (count != 2) {
            // 转账异常
            throw new TransferException("转账异常");
        }
    }
}

余额不足抛出异常MoenyNotEnoughException

package com.bjpowernode.bank.exception;

public class MoenyNotEnoughException extends Exception{
    // 两个构造方法
    public MoenyNotEnoughException() {
    }
    public MoenyNotEnoughException(String message) {
        super(message);
    }
}

转账失败抛出异常TransferException

package com.bjpowernode.bank.exception;

public class TransferException extends Exception{
    public TransferException() {
    }
    public TransferException(String message) {
        super(message);
    }
}

(3)在编写业务逻辑发现又需要数据库的操作,这就需要一个类专门连接数据库,专门处理数据的操作;面向接口编程,编写AccountDao接口和AccountDaoImpl类

AccountDao接口

package com.bjpowernode.bank.bao;

import com.bjpowernode.bank.pojo.Account;

/**
 * 负责对表中数据进行CRUD
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.bao
 * @Project:mybatis
 * @name:AccountDao
 * @Date:2023/1/1 19:48
 */
public interface AccountDao {
    /**
     * 根据账号查询账户信息
     * @param actno
     * @return 返回的是账户信息
     */
   Account selectByActno(String actno);

    /**
     * 更新账户信息
     * @param act
     * @return 1表示更新成功
     */
   int updateByActno(Account act);
}

AccountDaoImpl类

package com.bjpowernode.bank.bao.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.bao.impl
 * @Project:mybatis
 * @name:AccountDaoImpl
 * @Date:2023/1/1 19:57
 */
public class AccountDaoImpl implements AccountDao {
    @Override
    public Account selectByActno(String actno) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        Account account = (Account) sqlSession.selectOne("account.selectByActno", actno);
        sqlSession.close();
        return account;
    }

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

编写sql语句的AccountMapper.xml

<?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.bjpowernode.bank.pojo.Account">
        select * from t_act where actno=#{actno}
    </select>

    <update id="updateByActno">
        update t_act set balance = #{balance} where actno = #{actno};
    </update>
</mapper>

连接数据库的配置文件jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123

核心配置文件mybatis-config.xml

<?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" />
    <!--引入日志-->
    <settings>
        <setting name="logImpl" value="SLF4J"/>
    </settings>
    <environments default="mybatisDB">
        <!--连接的是mybatis数据库-->
        <environment id="mybatisDB">
            <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>
        <!--关联AccountMapper.xml配置文件-->
        <mapper resource="AccountMapper.xml"/>
    </mappers>

</configuration>

3. 事务控制

注:当前的代码没有事务控制,如果在第一条更新语句之后,第二条更新语句之前增加一个空指针异常,那么就会出现钱丢失的情况,这就需要事务的控制!

(1)实际上事务的控制不应该放在Dao层,不能更新一条就提交一次;应该发到Service层,所有逻辑走完了,在提交。

(2)我们在Service层直接增加控制事务的代码,也是不行的;因为在这里获得的sqlSession对象和执行update语句获得的sqlSession对象不是同一个sqlSession对象。

package com.bjpowernode.bank.service.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.bao.impl.AccountDaoImpl;
import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.service.AccountService;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.service.impl
 * @Project:mybatis
 * @name:AccountServiceImpl
 * @Date:2023/1/1 19:40
 */
public class AccountServiceImpl implements AccountService {
   private AccountDao accountDao = new AccountDaoImpl();
    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoenyNotEnoughException, TransferException {

        // 添加事务控制代码
        SqlSession sqlSession = SqlSessionUtils.openSession();

        // 判断转出账户的余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            // 如果转出账户余额不足,抛出异常提示用户
            throw new MoenyNotEnoughException("对不起,余额不足");
        }
        // 如果余额充足,更新转出和转入账户余额
        Account toAct = accountDao.selectByActno(toActno);
        // 修改内存中的余额
        fromAct.setBalance(fromAct.getBalance()-money);
        toAct.setBalance(toAct.getBalance()+money);
        // 修改数据库当中余额
        int count = accountDao.updateByActno(fromAct);
        count += accountDao.updateByActno(toAct);
        if (count != 2) {
            // 转账异常
            throw new TransferException("转账异常");
        }

        // 提交事务
        sqlSession.commit();
        sqlSession.close();
    }
}

(3)使用ThreadLocal控制,本质上是一个Map集合,它的key存储的是线程对象,value存储的是sqlSession对象;我们把sqlSession对象存到这个Map集合里面,对于同一个线程,以后取出来的都是同一个sqlSession对象。

在工具类SqlSessionUtils中引入ThreadLocal

package com.bjpowernode.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;

import java.io.IOException;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.mybatis.utils
 * @Project:mybatis
 * @name:SqlSessionUtils
 * @Date:2022/12/29 14:11
 */

public class SqlSessionUtils {
    public SqlSessionUtils() {
    }
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 全局的,服务器级别的,一个服务器当中定义一个
    private static ThreadLocal<SqlSession> local = new ThreadLocal<>();

    // 获取会话对象
    public static SqlSession openSession(){
        // 先从ThreadLocal当中获取
        SqlSession sqlSession = local.get();
        // 第一次获取肯定是空的
        if (sqlSession == null) {
            // 是空的,在去工厂中获取
            sqlSession = sqlSessionFactory.openSession();
            // 将sqlSession对象绑定到当前线程上
            local.set(sqlSession);
        }
        return sqlSession;
    }

    // 关闭sqlSession对象
    public static void close(SqlSession sqlSession){
        if (sqlSession != null) {
            sqlSession.close();
            // 移除sqlSession对象与当前线程的绑定关系
            // 因为Tomcat服务器是支持多线程的,被当前用户用到的t1线程,有可能继续被其他用户使用
            local.remove();
        }
    }
}

修改数据库AccountDaoImpl类,不应该在这里面commit和close

package com.bjpowernode.bank.bao.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.bao.impl
 * @Project:mybatis
 * @name:AccountDaoImpl
 * @Date:2023/1/1 19:57
 */
public class AccountDaoImpl implements AccountDao {
    @Override
    public Account selectByActno(String actno) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        Account account = (Account) sqlSession.selectOne("account.selectByActno", actno);
        return account;
    }

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

在Service层AccountServiceImpl类中增加事务的控制

package com.bjpowernode.bank.service.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.bao.impl.AccountDaoImpl;
import com.bjpowernode.bank.exception.MoenyNotEnoughException;
import com.bjpowernode.bank.exception.TransferException;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.service.AccountService;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.service.impl
 * @Project:mybatis
 * @name:AccountServiceImpl
 * @Date:2023/1/1 19:40
 */
public class AccountServiceImpl implements AccountService {
   private AccountDao accountDao = new AccountDaoImpl();
    @Override
    public void transfer(String fromActno, String toActno, double money) throws MoenyNotEnoughException, TransferException {

        // 添加事务控制代码
        SqlSession sqlSession = SqlSessionUtils.openSession();

        // 判断转出账户的余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            // 如果转出账户余额不足,抛出异常提示用户
            throw new MoenyNotEnoughException("对不起,余额不足");
        }
        // 如果余额充足,更新转出和转入账户余额
        Account toAct = accountDao.selectByActno(toActno);
        // 修改内存中的余额
        fromAct.setBalance(fromAct.getBalance()-money);
        toAct.setBalance(toAct.getBalance()+money);
        // 修改数据库当中余额
        int count = accountDao.updateByActno(fromAct);
        count += accountDao.updateByActno(toAct);
        if (count != 2) {
            // 转账异常
            throw new TransferException("转账异常");
        }

        // 提交事务
        sqlSession.commit();
        // 调用方法关闭
        SqlSessionUtils.close(sqlSession);
    }
}

4. 三大对象的作用域

(1)SqlSessionFactoryBuilder:这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

(2)SqlSessionFactory:SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例,除非连接另一个数据库,一个数据库就对应一个SqlSessionFactory对象。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,所以封装的时候是放到静态代码块里。因此 SqlSessionFactory 的最佳作用域是应用作用域。

(3)SqlSession:每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域(一次请求)。 一个线程对应一个SqlSession对象。

补充:我们发现Dao实现类AccountDaoImp的每个方法代码就两行,而且还有一行是重复的;那么这个类能不能不写了,在内存中生成这个接口的实现类?使用javassist技术,可以只给接口,根据这个接口在内存中自动生成这个实现类,这就是接下来要学的技术!

package com.bjpowernode.bank.bao.impl;

import com.bjpowernode.bank.bao.AccountDao;
import com.bjpowernode.bank.pojo.Account;
import com.bjpowernode.bank.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.bank.bao.impl
 * @Project:mybatis
 * @name:AccountDaoImpl
 * @Date:2023/1/1 19:57
 */
public class AccountDaoImpl implements AccountDao {
    @Override
    public Account selectByActno(String actno) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        Account account = (Account) sqlSession.selectOne("account.selectByActno", actno);
        return account;
    }

    @Override
    public int updateByActno(Account act) {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        int count = sqlSession.update("account.updateByActno", act);
        return count;
    }
}
标签: mybatis mvc 架构

本文转载自: https://blog.csdn.net/m0_61933976/article/details/128511127
版权归原作者 @每天都要敲代码 所有, 如有侵权,请联系我们删除。

“【MyBatis】| 在WEB中应⽤MyBatis(使⽤MVC架构模式)”的评论:

还没有评论