【Mybatis-1】MyBatis注解版详解

时间:2022-07-25
本文章向大家介绍【Mybatis-1】MyBatis注解版详解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

MyBatis之注解版 Java 1.5起,随着注解的流行,Mybatis也与时俱进地推出了基于注解的新版本。

1 注解版基本使用

pom依赖和yml配置文件以及相关数据见前文:SpringBoot系列(八):MyBatis之XML 配置版。 注解版与xml配置版的不同在于,注解版不再需要配置xml文件,直接在dao层接口中通过注解书写sql语句即可。

1.1 @Select 注解

@Select 主要在查询的时候使用,具体如下:

@Select("SELECT * FROM users")
List<User> getUserList();

1.2 @Insert 注解

插入数据库时使用:

@Insert("INSERT INTO users(userName,passWord,user_sex) VALUES(‘xiaohong’, ‘123456‘, ‘male’)")
void addUser();

1.3 @Update 注解

所有的更新操作 SQL 都可以使用 @Update:

@Update("UPDATE users SET userName='xiaohong2',password=#{passWord} WHERE id = 1")
void updateUser();

1.4 @Delete 注解

处理数据删除:

@Delete("DELETE FROM users WHERE id =1")
void deleteUser();

2 参数传递

上面的例子演示了基本的增删改查语句,但在实际项目中,肯定不能将参数写成具体的值,这就涉及到如何参数传递的问题了。 如果参数只有一个,直接在方法中使用参数,并在SQL中使用#{sex}来接收同名参数。

@Select("SELECT * FROM users WHERE sex = #{sex}")
List<User> getUserList(String sex);

如果有多个参数时,就需要用@Param标签来进行映射了。

2.1 @Param 注解传参

@Select("SELECT * FROM users WHERE sex = #{sex} AND age > #{age}")
List<User> getUsersBySex(@Param("sex") String sex,@Param("age") int age);

2.2 Map传参

当参数很多时,可以考虑使用Map传参:

@Select("SELECT * FROM users WHERE user_name=#{userName} AND user_sex = #{sex}")
List<User> getUsersByNameAndSex(Map<String, Object> map);

在调用该方法时,将参数依次加入map中:

Map param =  new HashMap();
param.put("userName","xiaohong");
param.put("sex","male");
List<User> users = userMapper.getListByNameAndSex(param);

2.3 对象传参

Insert("INSERT INTO users(userName,passWord,sex) VALUES(#{userName}, #{passWord}, #{sex})")
void addUser(User user);

在执行时,系统会自动读取对象的属性并值赋值到同名的 #{xxx} 中。

2.4 # 符号和$ 符号的区别

@Select("SELECT * FROM user WHERE user_name = #{userName}")
User getUserByName(@Param("userName") String userName);

@Select("SELECT * FROM user WHERE user_name = '${userName}'")
User getUserByName(@Param("userName") String userName);

通过这个例子,可以看出 # 会对SQL进行预处理,使用 $ 时会直接将值拼接到SQL中。使用 $ 有SQL注入的风险,但当库表名需要进行参数化时适合使用 $

3 字段映射

实际项目中,经常出现Mysql命名规范与Java的差异性导致的数据库字段名与Java实体类变量名不一致的情况。这个在前文中,已经讲述了解决方案。那么在注解版如何解决这个问题呢?Mybatis提供了两个注解:@Results 和 @Result 注解,这两个注解配合来使用,主要作用是将数据库中查询到的数值转化为具体的字段,修饰返回的结果集,关联实体类属性和数据库字段一一对应,如果实体类属性和数据库属性名保持一致,就不需要这个属性来修饰。示例如下:

@Select("SELECT * FROM users")
@Results({
    @Result(property = "sex",  column = "sex", javaType = UserSexEnum.class),
    @Result(property = "userName", column = "user_name")
})
List<User> getUserList();

4 动态SQL

MyBatis 可以灵活的支持动态 SQL,在前文xml配置版中已有详细阐述,与之对应的,在注解版中Mybatis提供了两种方式来支持,第一种是使用注解来实现,另一种是提供 SQL 类来支持。

4.1 使用注解实现

用 script 标签包围,然后像 XML 语法一样书写:

@Update("<script>
  update users
    <set>
      <if test="userName != null">user_name=#{userName},</if>
      <if test="sex!= null">sex=#{sex},</if>
    </set>
  where id=#{id}
</script>")
void update(User user);

这种方式就是注解 + XML 的混合使用方式,既有 XML 灵活又有注解的方便,但也有一个缺点需要在 Java 代码中拼接 XML 语法很不方便,因此 MyBatis 又提供了一种更优雅的使用方式来支持动态构建 SQL。

4.2 使用 SQL 构建类

可以看出 UserSql 中有一个方法 getList,使用 StringBuffer 对 SQL 进行拼接,通过 if 判断来动态构建 SQL,最后方法返回需要执行的 SQL 语句。

public class UserSql {
    public String getUserList(User user) {
        StringBuffer sql = new StringBuffer("select id, user_name, password, sex, nick_name as nickName");
        sql.append(" from users where 1=1 ");
        if (userParam != null) {
            if (StringUtils.isNotBlank(user.getUserName())) {
                sql.append(" and user_name = #{userName}");
            }
            if (StringUtils.isNotBlank(user.getSex())) {
                sql.append(" and sex = #{sex}");
            }
        }
        sql.append(" order by id desc");
        sql.append(" limit " + user.getBeginLine() + "," + user.getPageSize());
        log.info("getList sql is :" +sql.toString());
        return sql.toString();
    }
}

接下来只需要在 Mapper 中引入这个类和方法即可。

@SelectProvider(type = UserSql.class, method = "getUserList")
List<UserEntity> getList(User user);

两个参数:

  1. type:动态生成 SQL 的类
  2. method:类中具体的方法名

4.3 结构化 SQL

public String getCount(UserParam userParam) {
   String sql= new SQL(){{
        SELECT("count(1)");
        FROM("users");
        if (StringUtils.isNotBlank(userParam.getUserName())) {
            WHERE("userName = #{userName}");
        }
        if (StringUtils.isNotBlank(userParam.getUserSex())) {
            WHERE("user_sex = #{userSex}");
        }
        //从这个 toString 可以看出,其内部使用高效的 StringBuilder 实现 SQL 拼接
    }}.toString();

    log.info("getCount sql is :" +sql);
    return sql;
}
  1. SELECT 表示要查询的字段,可以写多行,多行的 SELECT 会智能地进行合并而不会重复。
  2. FROM 和 WHERE 跟 SELECT 一样,可以写多个参数,也可以在多行重复使用,最终会智能合并而不会报错。这样语句适用于写很长的 SQL,且能够保证 SQL 结构清楚,便于维护、可读性高。