一, 引言
通过上一篇 mybatis 的入门学习, 我们已经会使用 mybatis 实现简单的增删改查, 但是我们也发现了用原始 Dao 开发的一些问题:
Dao 方法体存在重复代码: 通过 SqlSessionFactory 创建 SqlSession, 调用 SqlSession 的数据库操作方法
调用 sqlSession 的数据库操作方法需要指定 statement 的 id, 这里存在硬编码, 不得于开发维护.
为了解决这些问题, 我们采用 Mapper 动态代理方法来进行开发: 程序员编写 Mapper 接口 (相当于 Dao 接口), 由 Mybatis 框架根据接口定义创建接口的动态代理对象, 代理对象的方法体同上边 Dao 接口实现类方法.
二, 开发规范
Mapper 接口开发需要遵循以下规范:
1, Mapper.xml 文件中的 namespace 与 mapper 接口的类路径相同.
2, Mapper 接口方法名和 Mapper.xml 中定义的每个 statement 的 id 相同
3, Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同
4,Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同
三, 改造
第一步: Mapper.xml(映射文件)
定义 mapper 映射文件 UserMapper.xml, 将 UserMapper.xml 放在 config 下 mapper 目录下, 效果如下:
文件内容如下:
<?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">
- <!-- namespace: 命名空间, 用于隔离 sql, 还有一个很重要的作用, 后面会讲 -->
- <mapper namespace="com.yuanqinnan.mapper.UserMapper">
- <select id="queryUserById" parameterType="int" resultType="com.yuanqinnan.model.User">
- SELECT * FROM `user`where id=#{id}
- </select>
- <!-- 查询 user 表的所有数据 -->
- <select id="selectUserAll" resultType="com.yuanqinnan.model.User">
- select * from user
- </select>
- <!--
- 1,${value} 里面必须要写 value, 不然会报错
- 2,${} 表示拼接 sql 字符串, 将接收到的参数不加任何修饰拼接在 sql 语句中
- 3, 使用 ${} 会造成 sql 注入
- -->
- <select id="selectLikeUserName" resultType="com.yuanqinnan.model.User" parameterType="String">
- select * from user where username like '%${value}%'
- </select>
- <!--#{} 实现 -->
- <select id="selectLikeUserName2" resultType="com.yuanqinnan.model.User" parameterType="String">
- select * from user where username like #{username}
- </select>
- <!-- 向 user 表插入一条数据 -->
- <insert id="insertUser" parameterType="com.yuanqinnan.model.User">
- insert into user(id,username,sex,birthday,address)
- value(#{id},#{username},#{sex},#{birthday},#{address})
- </insert>
- <!-- 保存用户 -->
- <insert id="saveUser" parameterType="com.yuanqinnan.model.User">
- <!-- selectKey 标签实现主键返回 -->
- <!-- keyColumn: 主键对应的表中的哪一列 -->
- <!-- keyProperty: 主键对应的 pojo 中的哪一个属性 -->
- <!-- order: 设置在执行 insert 语句前执行查询 id 的 sql, 在执行 insert 语句之后执行查询 id 的 sql -->
- <!-- resultType: 设置返回的 id 的类型 -->
- <selectKey keyColumn="id" keyProperty="id" order="AFTER"
- resultType="int">
- SELECT LAST_INSERT_ID()
- </selectKey>
- INSERT INTO `user`
- (username,birthday,sex,address) VALUES
- (#{username},#{birthday},#{sex},#{address})
- </insert>
- <!-- 根据 id 更新 user 表的数据 -->
- <update id="updateUserById" parameterType="com.yuanqinnan.model.User">
- update user set username=#{username} where id=#{id}
- </update>
- <!-- 根据 id 删除 user 表的数据 -->
- <delete id="deleteUserById" parameterType="int">
- delete from user where id=#{id}
- </delete>
- </mapper>
其他地方未有改动, 主要是 namespace="com.yuanqinnan.mapper.UserMapper" 的修改, 现在我们实现这个接口
第二步: UserMapper(接口文件)
新建 mapper 包, 新增接口 UserMapper
内容:
- public interface UserMapper {
- // 查询用户
- User queryUserById(int id);
- // 查询用户列表
- List<User> selectUserAll();
- // 模糊查询
- List<User> selectLikeUserName(String username);
- // 新增
- void saveUser(User user);
- }
第三步: 加载 UserMapper.xml 文件
- <mappers>
- <!-- 映射文件方式 1, 一个一个的配置 -->
- <mapper resource="config/sqlmap/User.xml"/>
- <mapper resource="config/mapper/UserMapper.xml"/>
- </mappers>
测试:
- public class MapperTest {
- private SqlSessionFactory sqlSessionFactory;
- @Before
- public void init() throws Exception {
- // 创建 SqlSessionFactoryBuilder
- SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
- // 加载 SqlMapConfig.xml 配置文件
- InputStream inputStream = Resources.getResourceAsStream("config/SqlMapConfig.xml");
- // 创建 SqlsessionFactory
- this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
- }
- @Test
- public void testQueryUserById() {
- // 获取 sqlSession, 和 spring 整合后由 spring 管理
- SqlSession sqlSession = this.sqlSessionFactory.openSession();
- // 从 sqlSession 中获取 Mapper 接口的代理对象
- UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
- // 执行查询方法
- User user = userMapper.queryUserById(1);
- System.out.println(user);
- // 和 spring 整合后由 spring 管理
- sqlSession.close();
- }
- @Test
- public void testQueryUserByUsername() {
- // 获取 sqlSession, 和 spring 整合后由 spring 管理
- SqlSession sqlSession = this.sqlSessionFactory.openSession();
- // 从 sqlSession 中获取 Mapper 接口的代理对象
- UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
- // 执行查询方法
- List<User> list = userMapper.selectLikeUserName("张");
- for (User user : list) {
- System.out.println(user);
- }
- // 和 spring 整合后由 spring 管理
- sqlSession.close();
- }
- @Test
- public void testSaveUser() {
- // 获取 sqlSession, 和 spring 整合后由 spring 管理
- SqlSession sqlSession = this.sqlSessionFactory.openSession();
- // 从 sqlSession 中获取 Mapper 接口的代理对象
- UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
- // 创建保存对象
- User user = new User();
- user.setUsername("刘备");
- user.setBirthday(new Date());
- user.setSex("1");
- user.setAddress("蜀国");
- // 执行查询方法
- userMapper.saveUser(user);
- System.out.println(user);
- // 和 spring 整合后由 spring 管理
- sqlSession.commit();
- sqlSession.close();
- }
- }
测试结果与上一篇相同
四, 总结
selectOne 和 selectList
动态代理对象调用 sqlSession.selectOne() 和 sqlSession.selectList() 是根据 mapper 接口方法的返回值决定, 如果返回 list 则调用 selectList 方法, 如果返回单个对象则调用 selectOne 方法.
namespace
mybatis 官方推荐使用 mapper 代理方法开发 mapper 接口, 程序员不用编写 mapper 接口实现类, 使用 mapper 代理方法时, 输入参数可以使用 pojo 包装对象或 map 对象, 保证 dao 的通用性.
源码地址: https://github.com/yuanqinnan/javaLearn
来源: https://www.cnblogs.com/yuanqinnan/p/10548717.html