MyBatis②相关API & DAO层实现

1、相关 API

运用了工厂模式建造者模式

  • SqlSessionFactoryBuilder
  • SqlSessionFactory
  • SqlSession

1.1、API 介绍

SqlSessionFactoryBuilder

  • 作用:以输入流的形式加载核心配置文件,构建 sqlSessionFactory 工厂对象。

  • Resources APIorg.apache.ibatis.io 提供,可通过输入流、文件、URL 等形式加载核心配置文件。

    String resource = "mybatis-config.xml";
    InputStream is = Resources.getResourceAsStream(resource);
    
    SQL_SESSION_FACTORY = new SqlSessionFactoryBuilder().build(is);
    

SqlSessionFactory

作用:创建 sqlSession 实例。

  • openSession():开启事务,默认不自动提交事务。
  • openSession(boolean autoCommit):参数表示是否自动提交事务。

SqlSession

作用:执行 SQL、管理事务。

  • 执行 SQL
    • insert()
    • delete()
    • update()
    • selectOne()、selectList()
  • 事务管理
    • commit()
    • rollback()

1.2、作用域

不同作用域,在多线程下需要考虑线程安全问题。

SqlSessionFactoryBuilder SqlSessionFactory SqlSession
作用 构建 SqlSessionFactory 创建 SqlSession 执行 SQL、事务管理
说明 构建 SqlSessionFactory 后不再需要 被创建之后,在应用运行期间一直存在
(相当于数据库连接池)
非线程安全,每次使用完就关闭
最佳作用域 方法作用域
(即局部变量)
应用作用域
(可通过单例模式实现)
请求或方法作用域

示例

  • 在 Web 应用中,将 SqlSession 放在一个和 HTTP 请求相似的作用域中。

  • 每次收到 HTTP 请求,开启一个 SqlSession,返回响应后就关闭。

  • 关闭操作应在 finally 块中进行。

    image-20210725183052852

2、DAO 实现

MyBatis 的 DAO 层有 2 种实现方式。

  • 传统方式:手动创建 DAO 接口实现类,在实现类中编写 MyBatis 代码。
  • 动态代理方式:MyBatis 自动生成代理实现类。

2.1、传统方式

参考 概述 - 2.3 - CRUD

  • 搭建环境
  • 映射文件:Mapper.xml
  • 工具类:提供 SqlSession 实例。
  • DAO 层
    • DAO 接口
    • DAO 接口实现类
      1. 获取 sqlSession 对象(从工具类中获取)。
      2. 执行 SQL,获得返回结果。
  • Service 层
    1. 实例化 DAO 实现类。
    2. 调用 DAO 层方法。
    3. 事务管理:提交 / 回滚
    4. 释放资源。

2.2.1、Mapper 接口

在 MyBatis 中,dao 层通常称为 mapper

public interface UserMapper {
    int insertUser(User user);
    int deleteUserByUserId(String userId);
    int updateUser(User user);
    List<User> listUsers();
}

2.2.2、Mapper 接口实现类

DAO 层只负责与数据库交互,事务管理由 Service 层完成

本例为简化代码,将事务管理放在 DAO 层。

  • 获取 sqlSession 对象。

  • 执行 SQL,获得返回结果。

  • * 提交事务

    public class UserMapperImpl implements UserMapper {
        @Override
        public int insertUser(User user) {
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            int row = sqlSession.insert("userMapper.insertUser", user);
    
            sqlSession.commit();
            sqlSession.close();
    
            return row;
        }
    
        @Override
        public int deleteUserByUserId(String userId) {
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            int row = sqlSession.delete("userMapper.deleteUserByUserId", userId);
    
            sqlSession.commit();
            sqlSession.close();
    
            return row;
        }
    
        @Override
        public int updateUser(User user) {
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            int row = sqlSession.update("userMapper.updateUser", user);
    
            sqlSession.commit();
            sqlSession.close();
    
            return row;
        }
    
        @Override
        public List<User> listUsers() {
            SqlSession sqlSession = MyBatisUtils.getSqlSession();
    
            List<User> userList = sqlSession.selectList("userMapper.listUsers");
            sqlSession.close();
    
            return userList;
        }
    }
    

2.2.3、测试

JUnit 模拟 Service 层

  1. 实例化 DAO 实现类。

  2. 调用 DAO 层方法。

  3. 释放资源(此处省略)

    @Test
    public void testInsertUser() {
        User user = new User("uu_demo", "demo", "123456");
    
        UserMapper mapper = new UserMapperImpl();
        mapper.insertUser(user);
    }
    
    @Test
    public void testDeleteUserByUserId() {
        String userId = "uu_demo";
        UserMapper mapper = new UserMapperImpl();
        mapper.deleteUserByUserId(userId);
    }
    
    @Test
    public void testUpdateUser() {
        User user = new User("uu_demo", "demo112", "1234112356");
        UserMapper mapper = new UserMapperImpl();
        mapper.updateUser(user);
    }
    
    @Test
    public void testListUsers() {
        UserMapper mapper = new UserMapperImpl();
        List<User> userList = mapper.listUsers();
        System.out.println(userList);
    }
    

2.2、动态代理方式(❗)

底层原理:动态代理

  • 只需编写 Mapper 接口,MyBatis 自动创建代理实现类。

  • 命名规范:以下的命名对应相等。

    Mapper.xml Mapper 接口
    namespace 全限类名
    statement 的 ID 方法名
    parameterType 方法参数类型
    resultType 方法返回值类型

2.2.1、Mapper 接口

与传统方式相同。

public interface UserMapper {
    int insertUser(User user);
    int deleteUserByUserId(String userId);
    int updateUser(User user);
    List<User> listUsers();
}

2.2.2、Mapper.xml

  • namespace:对应 Mapper 接口的全限类名

  • statement 的 ID:对应 Mapper 接口的方法名

  • parameterType:对应 Mapper 接口的方法参数类型

  • resultType:对应 Mapper 接口的方法返回值类型

    <?xml version="2.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="indi.jaywee.mapper.UserMapper">
    
        <insert id="insertUser" parameterType="user">
        	...
        </insert>
    
        <delete id="deleteUserByUserId" parameterType="string">
            ...
        </delete>
    
        <update id="updateUser" parameterType="user">
            ...
        </update>
    
        <select id="listUsers" resultType="user">
            ...
        </select>
    </mapper>
    

2.2.3、测试(❗)

通过 JUnit 测试模拟 Service 层对 DAO 层的调用。

  1. 通过 sqlSession 获取 Mapper

  2. 调用方法(DQL 需提交事务)

  3. 关闭资源。

    @Test
    public void testInsertUser() {
        User user = new User("uu_demo123", "demo123", "123456");
    
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        mapper.insertUser(user);
    
        sqlSession.commit();
        sqlSession.close();
    }
    
    @Test
    public void testDeleteUserByUserId() {
        String userId = "uu_demo";
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        mapper.deleteUserByUserId(userId);
    
        sqlSession.commit();
        sqlSession.close();
    }
    
    @Test
    public void testUpdateUser() {
        User user = new User("uu_demo123", "demo112", "1234112356");
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        mapper.updateUser(user);
    
        sqlSession.commit();
        sqlSession.close();
    }
    
    @Test
    public void testListUsers() {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        List<User> userList = mapper.listUsers();
        System.out.println(userList);
    
        sqlSession.close();
    }
    

2.3、说明

2.3.1、SQL 执行方式

  • 传统方式:通过 sqlSeesion 执行 SQL。
  • 代理方式:通过 sqlSeesion 获取 Mapper,由 Mapper 执行 SQL

2.3.2、事务管理

  • MyBatis 默认不自动提交事务,DML 需要手动提交事务
  • 在 Service 层进行事务管理,而不是 DAO 层。
posted @ 2021-07-23 15:19  Jaywee  阅读(150)  评论(0编辑  收藏  举报

👇