pom依赖和yml配置文件以及相关数据见前文:SpringBoot系列(八):MyBatis之XML 配置版。
注解版与xml配置版的不同在于,注解版不再需要配置xml文件,直接在dao层接口中通过注解书写sql语句即可。
@Select 主要在查询的时候使用,具体如下:
@Select("SELECT * FROM users")
List<User> getUserList();
插入数据库时使用:
@Insert("INSERT INTO users(userName,passWord,user_sex) VALUES(‘xiaohong’, ‘123456‘, ‘male’)")
void addUser();
所有的更新操作 SQL 都可以使用 @Update:
@Update("UPDATE users SET userName='xiaohong2',password=#{passWord} WHERE id = 1")
void updateUser();
处理数据删除:
@Delete("DELETE FROM users WHERE id =1")
void deleteUser();
上面的例子演示了基本的增删改查语句,但在实际项目中,肯定不能将参数写成具体的值,这就涉及到如何参数传递的问题了。
如果参数只有一个,直接在方法中使用参数,并在SQL中使用#{sex}来接收同名参数。
@Select("SELECT * FROM users WHERE sex = #{sex}")
List<User> getUserList(String sex);
如果有多个参数时,就需要用@Param标签来进行映射了。
@Select("SELECT * FROM users WHERE sex = #{sex} AND age > #{age}")
List<User> getUsersBySex(@Param("sex") String sex,@Param("age") int age);
当参数很多时,可以考虑使用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);
Insert("INSERT INTO users(userName,passWord,sex) VALUES(#{userName}, #{passWord}, #{sex})")
void addUser(User user);
在执行时,系统会自动读取对象的属性并值赋值到同名的 #{xxx} 中。
@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注入的风险,但当库表名需要进行参数化时适合使用 $。
实际项目中,经常出现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();
MyBatis 可以灵活的支持动态 SQL,在前文xml配置版中已有详细阐述,与之对应的,在注解版中Mybatis提供了两种方式来支持,第一种是使用注解来实现,另一种是提供 SQL 类来支持。
用 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。
可以看出 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);
两个参数:
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;
}