SpringBoot从入门到精通(十九)使用注解实现动态Sql、参数传递

简介: 前面介绍了Spring Boot 整合mybatis 使用注解的方式实现数据库操作,介绍了如何自动生成注解版的mapper 和pojo类。 接下来介绍使用mybatis 常用注解以及如何传参数等数据库操作中的常用操作。其实,mybatis 注解方式 和 XML配置方式两者的使用基本上相同,只有在构建 SQL 脚本有所区别,所以这里重点介绍两者之间的差异,以及增删改查,参数传递等注解的常用操作。

前面介绍了Spring Boot 整合mybatis 使用注解的方式实现数据库操作,介绍了如何自动生成注解版的mapper 和pojo类。 接下来介绍使用mybatis 常用注解以及如何传参数等数据库操作中的常用操作。

其实,mybatis 注解方式 和 XML配置方式两者的使用基本上相同,只有在构建 SQL 脚本有所区别,所以这里重点介绍两者之间的差异,以及增删改查,参数传递等注解的常用操作。

Spring Boot 整合mybatis 使用xml配置版之前已经介绍过了,不清楚的朋友可以看看之前的文章。

 

一、注解介绍

mybatis 注解方式的最大特点就是取消了 Mapper XML 配置,具体的 SQL 脚本直接写在 Mapper 类或是 SQLProvider 中的方法动态生成
mybatis 提供的常用注解有: @Insert 、@Update 、@Select、 @Delete 等标签,这些注解其实就是 MyBatis 提供的来取代其 XML配置文件的。

1、@Select 注解

@Select,主要在查询的时候使用,查询类的注解,一般简单的查询可以使用这个注解。

@Select({
    "select",
    "id, company_id, username, password, nickname, age, sex, job, face_image, province, ",
    "city, district, address, auth_salt, last_login_ip, last_login_time, is_delete, ",
    "regist_time",
    "from sys_user",
    "where id = #{id,jdbcType=VARCHAR}"
})
@Results({
    @Result(column="id", property="id", jdbcType=JdbcType.VARCHAR, id=true),
    @Result(column="company_id", property="companyId", jdbcType=JdbcType.VARCHAR),
    @Result(column="face_image", property="faceImage", jdbcType=JdbcType.VARCHAR),
    @Result(column="auth_salt", property="authSalt", jdbcType=JdbcType.VARCHAR),
    @Result(column="last_login_ip", property="lastLoginIp", jdbcType=JdbcType.VARCHAR),
    @Result(column="last_login_time", property="lastLoginTime", jdbcType=JdbcType.TIMESTAMP),
    @Result(column="is_delete", property="isDelete", jdbcType=JdbcType.INTEGER),
    @Result(column="regist_time", property="registTime", jdbcType=JdbcType.TIMESTAMP)
})
User selectByPrimaryKey(String id);

注意:如果是多个参数,需要将 #后面的参数和传入的变量名保持一致。

 

2、@Insert 注解

@Insert,插入数据时使用,直接传入数据实体类,mybatis 会属性自动解析到对应的参数。所以需要将 #后面的参数和实体类属性保持一致。

@Insert({
        "insert into sys_user (id, company_id, ",
        "username, password, ",
        "nickname, age, sex, ",
        "job, face_image, ",
        "province, city, ",
        "district, address, ",
        "auth_salt, last_login_ip, ",
        "last_login_time, is_delete, ",
        "regist_time)",
        "values (#{id,jdbcType=VARCHAR}, #{companyId,jdbcType=VARCHAR}, ",
        "#{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, ",
        "#{nickname,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}, #{sex,jdbcType=INTEGER}, ",
        "#{job,jdbcType=INTEGER}, #{faceImage,jdbcType=VARCHAR}, ",
        "#{province,jdbcType=VARCHAR}, #{city,jdbcType=VARCHAR}, ",
        "#{district,jdbcType=VARCHAR}, #{address,jdbcType=VARCHAR}, ",
        "#{authSalt,jdbcType=VARCHAR}, #{lastLoginIp,jdbcType=VARCHAR}, ",
        "#{lastLoginTime,jdbcType=TIMESTAMP}, #{isDelete,jdbcType=INTEGER}, ",
        "#{registTime,jdbcType=TIMESTAMP})"
    })
    int insert(User record);

注意:需要将 #后面的参数和实体类属性保持一致。

 

3、@Update 注解

@Update,一般数据更新操作可以使用 @Update注解实现。

@Update({
        "update sys_user",
        "set company_id = #{companyId,jdbcType=VARCHAR},",
          "username = #{username,jdbcType=VARCHAR},",
          "password = #{password,jdbcType=VARCHAR},",
          "nickname = #{nickname,jdbcType=VARCHAR},",
          "age = #{age,jdbcType=INTEGER},",
          "sex = #{sex,jdbcType=INTEGER},",
          "job = #{job,jdbcType=INTEGER},",
          "face_image = #{faceImage,jdbcType=VARCHAR},",
          "province = #{province,jdbcType=VARCHAR},",
          "city = #{city,jdbcType=VARCHAR},",
          "district = #{district,jdbcType=VARCHAR},",
          "address = #{address,jdbcType=VARCHAR},",
          "auth_salt = #{authSalt,jdbcType=VARCHAR},",
          "last_login_ip = #{lastLoginIp,jdbcType=VARCHAR},",
          "last_login_time = #{lastLoginTime,jdbcType=TIMESTAMP},",
          "is_delete = #{isDelete,jdbcType=INTEGER},",
          "regist_time = #{registTime,jdbcType=TIMESTAMP}",
        "where id = #{id,jdbcType=VARCHAR}"
    })
    int updateByPrimaryKey(User record);

4、@Delete 注解
@Delete 数据删除的注解

@Delete({
        "delete from sys_user",
        "where id = #{id,jdbcType=VARCHAR}"
    })
    int deleteByPrimaryKey(String id);

 

5、@Results @Result 注解

@Results 和 @Result 主要作用是,当有一些特殊的场景需要处理,查询的返回结果与期望的数据格式不一致时,可以将将数据库中查询到的数值自动转化为具体的属性或类型,,修饰返回的结果集。比如查询的对象返回值属性名和字段名不一致,或者对象的属性中使用了枚举等。如果实体类属性和数据库属性名保持一致,就不需要这个属性来修饰。

@Select({
    "select",
    "id, company_id, username, password, nickname, age, sex, job, face_image, province, ",
    "city, district, address, auth_salt, last_login_ip, last_login_time, is_delete, ",
    "regist_time",
    "from sys_user",
    "where id = #{id,jdbcType=VARCHAR}"
})
@Results({
    @Result(column="id", property="id", jdbcType=JdbcType.VARCHAR, id=true),
    @Result(column="company_id", property="companyId", jdbcType=JdbcType.VARCHAR),
    @Result(column="face_image", property="faceImage", jdbcType=JdbcType.VARCHAR),
    @Result(column="auth_salt", property="authSalt", jdbcType=JdbcType.VARCHAR),
    @Result(column="last_login_ip", property="lastLoginIp", jdbcType=JdbcType.VARCHAR),
    @Result(column="last_login_time", property="lastLoginTime", jdbcType=JdbcType.TIMESTAMP),
    @Result(column="is_delete", property="isDelete", jdbcType=JdbcType.INTEGER),
    @Result(column="regist_time", property="registTime", jdbcType=JdbcType.TIMESTAMP)
})
User selectByPrimaryKey(String id);


上面的例子可以看到,数据库中的company_id 字段和实体类中定义的 companyId 属性的名称不一致,需要Result 转换。

 

以上就是项目中常用的增、删、改、查的操作, 其实这些在基本的方法不需要手动写,用前面讲过的mybatis generator 自动生成即可。讲这些主要是熟悉这些常用的注解。

二、传参方式

上面介绍了mybatis 常用的注解,如何实现增删改查的操作,相信很多人会有疑问了: mybatis 是如何将参数传递到 SQL 中的呢,都有哪几种传参方式呢? 下面就来一一介绍mybatis 注解版的传参方式。

1、直接传参

对于单个参数的方法,可直接使用 #{id} 的方式接收同名的变量参数。

@Delete("delete from sys_user where id = #{id,jdbcType=VARCHAR}")
int deleteByPrimaryKey(String id);

 

2、使用 @Param 注解

@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中 。如果你的方法有多个参数,@Param 注解 会在方法的参数上就能为它们取自定义名字,参数则先以 "param" 作前缀,再加上它们的参数位置作为参数别名。例如, #{param1}、 #{param2},这个是默认值。如果注解是 @Param("person"),那么参数就会被命名为 #{person}。

@Select("SELECT * FROM sys_user WHERE username = #{username} and password = #{password}")
List<User> getListByUserSex(@Param("username") String userName, @Param("password") String password);
// 不自定义param 时,默认使用 param + 参数序号 或者 0,1,值就是参数的值。
@Select("SELECT * FROM sys_user WHERE username = #{param1} and password = #{param2}")
List<User> getListByUserSex(String userName, String password);

 

3、Map 传值
需要传送多个参数时,也可以考虑使用 Map的形式。

@Select("SELECT * FROM sys_user WHERE username=#{username} AND password = #{password}")
List<User> getListByNameAndSex(Map<String, Object> map);

调用时将参数依次加入到 Map 中即可。

Map param= new HashMap();
param.put("username","admin");
param.put("password","123456");
List<User> users = userMapper.getListByNameAndSex(param)

 

4、使用pojo对象
使用pojo对象传参是比较常用的传参方式。像上面的insert、update 等方法。都是直接传入user对象。

@Update({
    "update sys_user",
    "set company_id = #{companyId,jdbcType=VARCHAR},",
      "username = #{username,jdbcType=VARCHAR},",
      "password = #{password,jdbcType=VARCHAR},",
      "nickname = #{nickname,jdbcType=VARCHAR},",
      "age = #{age,jdbcType=INTEGER},",
      "sex = #{sex,jdbcType=INTEGER},",
      "job = #{job,jdbcType=INTEGER},",
      "face_image = #{faceImage,jdbcType=VARCHAR},",
      "province = #{province,jdbcType=VARCHAR},",
      "city = #{city,jdbcType=VARCHAR},",
      "district = #{district,jdbcType=VARCHAR},",
      "address = #{address,jdbcType=VARCHAR},",
      "auth_salt = #{authSalt,jdbcType=VARCHAR},",
      "last_login_ip = #{lastLoginIp,jdbcType=VARCHAR},",
      "last_login_time = #{lastLoginTime,jdbcType=TIMESTAMP},",
      "is_delete = #{isDelete,jdbcType=INTEGER},",
      "regist_time = #{registTime,jdbcType=TIMESTAMP}",
    "where id = #{id,jdbcType=VARCHAR}"
})
int updateByPrimaryKey(User record);


以上,就是Mybatis 传参的四种方式。根据方法的参数选择合适的传值方式。

 

三、动态 SQL

实际项目中,除了使用一些常用的增删改查的方法之外,有些复杂的需求,可能还需要执行一些自定义的动态sql。mybatis 除了提供了@Insert、@Delete 这些常用的注解,还提供了多个注解如:@InsertProvider,@UpdateProvider,@DeleteProvider和@SelectProvider,用来建立动态sql 和让 mybatis 执行这些sql 的注解。下面就来实现按字段更新的功能。

1、首先在 UserSqlProvider 中创建 拼接sql的方法。

public String updateByPrimaryKeySelective(User record) {
        BEGIN();
        UPDATE("sys_user");
        if (record.getCompanyId() != null) {
            SET("company_id = #{companyId,jdbcType=VARCHAR}");
        }
        if (record.getUsername() != null) {
            SET("username = #{username,jdbcType=VARCHAR}");
        }
        if (record.getPassword() != null) {
            SET("password = #{password,jdbcType=VARCHAR}");
        }
        if (record.getNickname() != null) {
            SET("nickname = #{nickname,jdbcType=VARCHAR}");
        }
        if (record.getAge() != null) {
            SET("age = #{age,jdbcType=INTEGER}");
        }
        if (record.getSex() != null) {
            SET("sex = #{sex,jdbcType=INTEGER}");
        }
        if (record.getJob() != null) {
            SET("job = #{job,jdbcType=INTEGER}");
        }
        if (record.getFaceImage() != null) {
            SET("face_image = #{faceImage,jdbcType=VARCHAR}");
        }
        if (record.getProvince() != null) {
            SET("province = #{province,jdbcType=VARCHAR}");
        }
        if (record.getCity() != null) {
            SET("city = #{city,jdbcType=VARCHAR}");
        }
        if (record.getDistrict() != null) {
            SET("district = #{district,jdbcType=VARCHAR}");
        }
        if (record.getAddress() != null) {
            SET("address = #{address,jdbcType=VARCHAR}");
        }
        if (record.getAuthSalt() != null) {
            SET("auth_salt = #{authSalt,jdbcType=VARCHAR}");
        }
        if (record.getLastLoginIp() != null) {
            SET("last_login_ip = #{lastLoginIp,jdbcType=VARCHAR}");
        }
        if (record.getLastLoginTime() != null) {
            SET("last_login_time = #{lastLoginTime,jdbcType=TIMESTAMP}");
        }
        if (record.getIsDelete() != null) {
            SET("is_delete = #{isDelete,jdbcType=INTEGER}");
        }
        if (record.getRegistTime() != null) {
            SET("regist_time = #{registTime,jdbcType=TIMESTAMP}");
        }
        WHERE("id = #{id,jdbcType=VARCHAR}");
        return SQL();
    }

 

2、接下来在Mapper 中引入 updateByPrimaryKeySelective 方法

 

@UpdateProvider(type=UserSqlProvider.class, method="updateByPrimaryKeySelective")
int updateByPrimaryKeySelective(User record);

说明:

  type:动态生成 SQL 的类。

  method:类中具体的方法名。

以上,就是使用sqlprovider 动态创建sql,除了示例中的 @UpdateProvider ,,还有 @InsertProvider、 @SelectProvider @DeleteProvider 提供给插入、查询、删除的时使用。

 

最后

上面,介绍了使用mybatis 常用注解实现增、删、改、查。以及mybatis 常用的四种参数传递方式。

这个系列课程的完整源码,也会提供给大家。大家关注我的微信公众号(架构师精进),回复:springboot源码。获取这个系列课程的完整源码。




推荐阅读:

SpringBoot从入门到精通(十八)Mybatis系列之——使用注解的方式实现后台管理功能

SpringBoot从入门到精通(十七)MyBatis系列之——创建自定义mapper 实现多表关联查询!

SpringBoot从小白到精通(十六)使用pagehelper实现分页查询功能

SpringBoot从小白到精通(十五)实现开发环境热部署

SpringBoot从小白到精通(十四)使用JdbcTemplate操作数据库,配置多数据源!

SpringBoot从小白到精通(十三)如何实现事务保存

SpringBoot从小白到精通(十二)logback日志配置

SpringBoot从小白到精通(十一)统一异常处理

SpringBoot从小白到精通(十)使用Interceptor拦截器,一学就会!

SpringBoot从小白到精通(九)使用@Async实现异步执行任务

SpringBoot从小白到精通(八)熟悉@EnableScheduling,一秒搞定定时任务

SpringBoot从小白到精通(七)使用Redis实现高速缓存架构

SpringBoot从小白到精通(六)使用Mybatis实现增删改查【附详细步骤】

SpringBoot从小白到精通(五)Thymeleaf的语法及常用标签

SpringBoot从小白到精通(四)Thymeleaf页面模板引擎

SpringBoot从小白到精通(三)系统配置及自定义配置

SpringBoot从小白到精通(二)如何返回统一的数据格式

SpringBoot从小白到精通(一)如何快速创建SpringBoot项目

相关文章
|
1月前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
49 0
|
2月前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
121 3
|
19天前
|
前端开发 Java Spring
Spring MVC核心:深入理解@RequestMapping注解
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的核心,它将HTTP请求映射到控制器的处理方法上。本文将深入探讨`@RequestMapping`注解的各个方面,包括其注解的使用方法、如何与Spring MVC的其他组件协同工作,以及在实际开发中的应用案例。
35 4
|
1月前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
60 4
SpringBoot必须掌握的常用注解!
|
19天前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
58 2
|
19天前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
40 2
|
22天前
|
消息中间件 Java 数据库
解密Spring Boot:深入理解条件装配与条件注解
Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
26 2
|
23天前
|
JSON Java 数据格式
springboot常用注解
@RestController :修饰类,该控制器会返回Json数据 @RequestMapping(“/path”) :修饰类,该控制器的请求路径 @Autowired : 修饰属性,按照类型进行依赖注入 @PathVariable : 修饰参数,将路径值映射到参数上 @ResponseBody :修饰方法,该方法会返回Json数据 @RequestBody(需要使用Post提交方式) :修饰参数,将Json数据封装到对应参数中 @Controller@Service@Compont: 将类注册到ioc容器
|
23天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
36 2
|
19天前
|
前端开发 Java 开发者
Spring MVC中的控制器:@Controller注解全解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序控制层的核心。它不仅简化了控制器的定义,还提供了灵活的请求映射和处理机制。本文将深入探讨`@Controller`注解的用法、特点以及在实际开发中的应用。
51 0