最近在读刘增辉老师所著的《MyBatis 从入门到精通》一书, 很有收获, 于是将自己学习的过程以博客形式输出, 如有错误, 欢迎指正, 如帮助到你, 不胜荣幸!
1. @Select 注解
1.1 使用 Sql 语句设置别名方式
假设现在有个需求: 根据 id 查询角色信息. 使用注解方式该如何实现呢?
首先, 在接口 SysRoleMappper 中添加如下方法:
- @Select({
- "SELECT id,role_name roleName,enabled,create_by createBy,create_time createTime","FROM sys_role","WHERE id = #{id}"
- })
- SysRole selectById(Long id);
上面的代码也可以写成如下格式:
- @Select({
- "SELECT id,role_name roleName,enabled,create_by createBy,create_time createTime FROM sys_role WHERE id = #{id}"
- })
- SysRole selectById(Long id);
以上 2 种方式都是传递字符串数组的形式, 我们还可以用直接传递字符串的形式:
- @Select("SELECT id,role_name roleName,enabled,create_by createBy,create_time createTime FROM sys_role WHERE id = #{id}")
- SysRole selectById(Long id);
使用注解方式同样需要考虑表字段和 Java 属性字段映射的问题, 使用注解方式主要有 3 种方式来实现.
第 1 种方式是通过 Sql 语句设置别名, 上面的代码就用的是这种方式.
1.2 使用 mapUnderscoreToCamelCase 配置方式
打开 src/main/resources 目录下我们之前新建的 mybatis-config.xml 文件, 添加如下配置:
- <settings>
- <!-- 其他配置 -->
- <setting name="mapUnderscoreToCamelCase" value="true"/>
- </settings>
该配置打开后, MyBatis 会按照 "下划线转驼峰" 规则自动映射, 即将数据库列 role_name 自动转换为属性 roleName.
此时, 上面的代码可以修改为:
- @Select("SELECT id,role_name,enabled,create_by,create_time FROM sys_role WHERE id = #{id}")
- SysRole selectById(Long id);
虽然也可以写为如下格式, 但是不推荐这么使用:
- @Select("SELECT * FROM sys_role WHERE id = #{id}")
- SysRole selectById(Long id);
1.3 使用 resultMap 方式
在 xml 中, 我们使用过 resultMap 来配置映射:
- <resultMap id="sysUserMap" type="com.zwwhnly.mybatisaction.model.SysUser">
- <id property="id" column="id"/>
- <result property="userName" column="user_name"/>
- <result property="userPassword" column="user_password"/>
- <result property="userEmail" column="user_email"/>
- <result property="userInfo" column="user_info"/>
- <result property="headImg" column="head_img" jdbcType="BLOB"/>
- <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
- </resultMap>
在注解方式中, 有一个对应的注解 @Results 来配置映射:
- @Results({
- @Result(property = "id", column = "id", id = true),
- @Result(property = "roleName", column = "role_name"),
- @Result(property = "enabled", column = "enabled"),
- @Result(property = "createBy", column = "create_by"),
- @Result(property = "createTime", column = "create_time")
- })
- @Select("SELECT id,role_name,enabled,create_by,create_time FROM sys_role WHERE id = #{id}")
- SysRole selectById2(Long id);
代码简单讲解:
1)@Results 注解对应着 xml 中的 resultMap 标签
2)@Result 对应着 xml 中的 result 标签
3)@Result(property = "id", column = "id", id = true) 对应着 xml 中的 < id property="id" column="id"/>
也许有人会问, 我在 xml 中, 为 resultMap 设置了一个 id, 这样我就能复用该 resultMap 了, 在注解方式中, 支持吗?
带着这个疑问, 让我们来试着修改下代码:
- @Results(id = "roleResultMap", value = {
- @Result(property = "id", column = "id", id = true),
- @Result(property = "roleName", column = "role_name"),
- @Result(property = "enabled", column = "enabled"),
- @Result(property = "createBy", column = "create_by"),
- @Result(property = "createTime", column = "create_time")
- })
- @Select("SELECT id,role_name,enabled,create_by,create_time FROM sys_role WHERE id = #{id}")
- SysRole selectById2(Long id);
结果发现代码编译错误, 找不到 id 属性.
按下 Ctrl+B, 发现 @Results 的源码如下:
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.METHOD})
- public @interface Results {
- Result[] value() default {};
- }
从源码我们可以发现, 这个注解没有 id 属性, 难道我们每个方法上都要加上重复的映射吗?
答案当然是否定的, 不过在 MyBatis 3.3.0 及以前的版本中, 注解定义的 @Results 不能共用, 需要在每一个方法上都写一遍. 但是从 MyBatis 3.3.1 版本开始,@Results 注解增加了一个 id 属性, 设置了 id 属性后, 就可以通过 id 属性引用同一个 @Results 配置了.
看过之前几篇博客的读者可能知道, 我们的 MyBatis 刚好使用的是 3.3.0 版本, 所以刚好不支持设置 id 属性, 哈哈.
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.3.0</version>
- </dependency>
修改 MyBatis 的版本为 3.3.1(如果没有设置自动导入变化的话, 需要手动点下 Import Changes):
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.3.1</version>
- </dependency>
这时会发现, 上面原本编译报错的代码可以编译通过了.
此时 @Results 的源码如下, 相比于之前的代码, 增加了 id 属性:
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.METHOD})
- public @interface Results {
- String id() default "";
- Result[] value() default {};
- }
那如何引用这个 @Results 注解呢? 请看如下代码:
- @ResultMap("roleResultMap")
- @Select("SELECT * FROM sys_role")
- List<SysRole> selectAll();
说明: 当配合 xml 方式使用的时候, 这里引用的 id 值还可以是 xml 中 resultMap 元素的 id 属性值.
为了使篇幅不至于过长, 这里不再贴出这 3 个方法的单元测试代码和输出日志, 相信看过前几篇博客的读者已经可以自己写出单元测试代码了, 也可以参考文末的源码地址下载下源码.
2. @Insert 注解
2.1 不需要返回主键
和 xml 中的使用方式几乎一样, 代码如下:
- @Insert({"INSERT INTO sys_role(id, role_name, enabled, create_by, create_time)",
- "VALUES (#{id},#{roleName},#{enabled},#{createBy},#{createTime,jdbcType=TIMESTAMP})"})
- int insert(SysRole sysRole);
2.2 返回自增主键
如果需要返回数据库的自增主键, 代码如下:
- @Insert({"INSERT INTO sys_role(role_name, enabled, create_by, create_time)",
- "VALUES (#{roleName},#{enabled},#{createBy},#{createTime,jdbcType=TIMESTAMP})"})
- @Options(useGeneratedKeys = true, keyProperty = "id")
- int insertUseGeneratedKeys(SysRole sysRole);
和 xml 中的使用方式差不多,@Options(useGeneratedKeys = true, keyProperty = "id") 等价于 xml 中的 useGeneratedKeys="true" keyProperty="id".
2.3 返回非自增主键
在之前的博客中, 我们知道 selectKey 既支持主键自增的数据库, 比如 MySQL, 也支持主键不自增的数据库, 如 Oracle, 在 xml 中的写法是这样的:
- <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
- SELECT LAST_INSERT_ID()
- </selectKey>
那么使用注解方式该如何实现呢? 代码如下所示:
- @Insert({"INSERT INTO sys_role(role_name, enabled, create_by, create_time)",
- "VALUES (#{roleName},#{enabled},#{createBy},#{createTime,jdbcType=TIMESTAMP})"})
- @SelectKey(statement = "SELECT LAST_INSERT_ID()", keyColumn = "id", keyProperty = "id", resultType = Long.class, before = false)
- int insertUseSelectKey(SysRole sysRole);
before = false 相当于 xml 中的 order="AFTRE", 这是 MySQL 数据库的配置.
before = true 相当于 xml 中的 order="BEFORE", 这是 Oracle 数据库的配置.
注意事项: 不同的数据库 statement 的值会不同, 上面中的值适用于 MySQL 数据库, 使用其他类型的数据库时要注意修改.
3. @Update 注解
和 xml 中的使用方式几乎一样, 代码如下:
- @Update({"UPDATE sys_role", "SET role_name = #{roleName},enabled = #{enabled},create_by=#{createBy},",
- "create_time=#{createTime,jdbcType=TIMESTAMP}", "WHERE id=#{id}"})
- int updateById(SysRole sysRole);
4. @Delete 注解
和 xml 中的使用方式几乎一样, 代码如下:
- @Delete("DELETE FROM sys_role WHERE id = #{id}")
- int deleteById(Long id);
5. Provider 注解
MyBatis 提供了 4 种 Provider 注解, 分别是 @SelectProvider,@InsertProvider,@UpdateProvider 和 @DeleteProvider.
我们以 @SelectProvider 为例了解下 Provider 注解的使用方法.
首先在 com.zwwhnly.mybatisaction.mapper 包下新建如下类:
- package com.zwwhnly.mybatisaction.mapper;
- import org.apache.ibatis.jdbc.SQL;
- public class SysPrivilegeProvider {
- public String selectById(final Long id) {
- return new SQL() {
- {
- SELECT("id,privilege_name,privilege_url");
- FROM("sys_privilege");
- WHERE("id = #{id}");
- }
- }.toString();
- }
- }
以上代码也可以写成如下方式:
- public String selectById(final Long id) {
- return "SELECT id,privilege_name,privilege_url FROM sys_privilege WHERE id = #{id}";
- }
然后在接口 SysPrivilegeProvider 中添加如下方法:
- @SelectProvider(type = SysPrivilegeProvider.class, method = "selectById")
- SysPrivilege selectById(Long id);
最后在 src/test/java 下的 com.zwwhnly.mybatisaction.mapper 包下新建测试类 SysPrivilegeMapperTest:
- package com.zwwhnly.mybatisaction.mapper;
- import com.zwwhnly.mybatisaction.model.SysPrivilege;
- import org.apache.ibatis.session.SqlSession;
- import org.junit.Assert;
- import org.junit.Test;
- public class SysPrivilegeMapperTest extends BaseMapperTest {
- @Test
- public void testSelectById() {
- SqlSession sqlSession = getSqlSession();
- try {
- SysPrivilegeMapper sysPrivilegeMapper = sqlSession.getMapper(SysPrivilegeMapper.class);
- SysPrivilege sysPrivilege = sysPrivilegeMapper.selectById(1L);
- Assert.assertNotNull(sysPrivilege);
- Assert.assertEquals("用户管理", sysPrivilege.getPrivilegeName());
- } finally {
- sqlSession.close();
- }
- }
- }
运行测试代码, 测试通过, 输出日志如下:
- DEBUG [main] - ==> Preparing: SELECT id,privilege_name,privilege_url FROM sys_privilege WHERE (id = ?)
- DEBUG [main] - ==> Parameters: 1(Long)
- TRACE [main] - <== Columns: id, privilege_name, privilege_url
TRACE [main] - <== Row: 1, 用户管理, /users
DEBUG [main] - <== Total: 1
6. 源码
源码地址: https://github.com/zwwhnly/mybatis-action.git , 欢迎下载.
7. 参考
刘增辉《MyBatis 从入门到精通》
来源: https://www.cnblogs.com/zwwhnly/p/11136448.html