zoukankan      html  css  js  c++  java
  • MyBatis系列(五):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,欢迎下载。

    刘增辉《MyBatis从入门到精通》

  • 相关阅读:
    学而201205期先导班信息系统项目管理师招生简章
    201205期蘑菇班信息系统项目管理师招生简章
    用常识驳倒方舟子之一 :韩寒的女儿与常识
    学而201211期蘑菇班信息系统项目管理师招生简章
    工作量与工作历时计算
    git设置中英文
    楼层跳转scrollintoview坑
    一则浏览器兼容性解决案例(搜狗)
    C语言未初始化变量输出的是随即数
    远程关机,在MM面前显摆一次的机会,别错过 To Phper
  • 原文地址:https://www.cnblogs.com/zwwhnly/p/11136448.html
Copyright © 2011-2022 走看看