MyBatis②相关API & DAO层实现
1、相关 API
运用了工厂模式、建造者模式。
- SqlSessionFactoryBuilder
- SqlSessionFactory
- SqlSession
1.1、API 介绍
SqlSessionFactoryBuilder
-
作用:以输入流的形式加载核心配置文件,构建
sqlSessionFactory
工厂对象。 -
Resources API:
org.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 块中进行。
2、DAO 实现
MyBatis 的 DAO 层有 2 种实现方式。
- 传统方式:手动创建 DAO 接口实现类,在实现类中编写 MyBatis 代码。
- 动态代理方式:MyBatis 自动生成代理实现类。
2.1、传统方式
- 搭建环境
- 映射文件:Mapper.xml
- 工具类:提供
SqlSession
实例。 - DAO 层
- DAO 接口
- DAO 接口实现类
- 获取
sqlSession
对象(从工具类中获取)。 - 执行 SQL,获得返回结果。
- 获取
- Service 层
- 实例化 DAO 实现类。
- 调用 DAO 层方法。
- 事务管理:提交 / 回滚
- 释放资源。
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 层
-
实例化 DAO 实现类。
-
调用 DAO 层方法。
-
释放资源(此处省略)
@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 层的调用。
-
通过 sqlSession 获取 Mapper。
-
调用方法(DQL 需提交事务)
-
关闭资源。
@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 层。