正如我们所知在mapper文件中用注解的方式写一些普通的查询,删除sql语句格式都相对简单,而且一般我们如果有动态sql需要的话,可以采用把sql写在xml文件,然后根据Mapper内方法id进行匹配,实现我们复杂的查询或者循环添加等操作。

但是如果不写xml文件而用@Mapper注解方式的话,那如何写动态SQL?
首先如果注解写动态sql的话会用到 <script> </scrpit>标签.

实战例子1:

1. 多条件查询以及分页低配版(返回List集合)

@Select({"<script> SELECT * FROM user WHERE " +
"<if  test= "mobile != null and mobile != ''"> mobile = #{mobile} </if>" +
"<if  test= "star != null and star != ''">  AND star=#{star} </if>" +
"<if test ='startTime != null '>  AND UNIX_TIMESTAMP(update_time) >= #{startTime} </if>" +
"<if test ='endTime != null '>   AND UNIX_TIMESTAMP(update_time) &lt;= #{endTime} </if>" +
"<if test="count > 0">  LIMIT #{offset}, #{count} </if> </script>"})
//参数是对象,携带多参数进行模糊分页查询
List<User> getUserList(Request request);

2. 多条件查询以及分页升级版(返回List集合)

//把条件语句单独提出来,方便其他语句使用,比如查询数据集合信息,查询数据条数的sql语句
String QUERY_CODE_SQL = "<if  test= \"mobile != null and mobile != ''\">  mobile = #{mobile} </if> " +
            "<if  test= \"star != null and star != ''\">  AND star=#{star} </if>" +
            "<if test ='startTime != null '>  AND UNIX_TIMESTAMP(update_time) >= #{startTime} </if>" +
            "<if test ='endTime != null '>   AND UNIX_TIMESTAMP(update_time) &lt;= #{endTime} </if>" +
            "<if test=\"count > 0\">  LIMIT #{offset}, #{count} </if>";

@Select({"<script> SELECT * FROM user WHERE" + QUERY_CODE_SQL + " </script>"})
//参数是对象,携带多参数进行模糊分页查询集合信息
List<User> getUserList(Request request);

3. 根据某条件循环查询相关信息(返回List集合)

 @Select({"<script> ",
            "SELECT * FROM user ",
            "WHERE id IN ",
            "<foreach collection = 'userIds' separator = ',' open = '(' close = ')' item = 'id'>  ",
            "#{id} ",
            "</foreach> ",
            "</script>"})
List<User> getUserListByUserIds(@Param("userIds") Set<Long> userIdSet);

上面例子说明如下:

/**
 * 参数为Set集合,集合内携带条件(多个用户的id==userIds)
 *     collection :collection属性的值有三个分别是List、Array、Map三种,分别对应的参数类型为:List、数组、map集合,我在上面传的参数为Set集合(set内没有重复数据,比List集合实用,避免反复查询),所以值为别名userIds,参数没有别名的话此处用collection;
 *    item : 表示在迭代过程中每一个元素的别名
 *    #{参数} 中的参数名和item别名相对应    #{id} <==> item = 'id'
 *    open :前缀
 *    close :后缀
 */

4 根据某条件循环查询相关信息(返回Map集合)

@Select("<script>" +
        "SELECT  * FROM user_info WHERE" + 
        " fellow_id=#{fellow_id} " + 
        " AND user_id IN " + 
        "<foreach collection = 'user_ids' separator = ',' open = '(' close = ')' item = 'user_id'>" + 
        " #{user_id}" + 
        "</foreach>" +
        "</script>")
@MapKey("userId")
Map<String, CalendarTask> getCalendarTaskMap(
        @Param("fellow_id") Long fellowId,
        @Param("user_ids") List<Long> userIds);

 

上面例子说明如下:

/**
 * 参数1是fellowId;参数2是List集合,集合内携带条件(多个用户的user_id==userIds);
 *    @MapKey()注解,我理解的是规定Map集合的key,本map的key就是每一个userId,所以参数是该sql语句查询结果(*查询出的数据有userId字段)的每条数据中的字段值==>userId;
 */

如果XML元素嵌入在<script>XML元素中,则可以在注释值中为动态SQL使用XML元素:

@Select("<script>SELECT ...</script>")

但是使用<include>元素会触发SQL Mapper配置解析异常,由以下原因引起:

org.apache.ibatis.builder.BuilderException: Unknown element in SQL statement. at org.apache.ibatis.scripting.xmltags.XMLScriptBuilder.parseDynamicTags

如果nodeHandlers在课堂中检查方法org.apache.ibatis.builder.BuilderException,将注意到支持的元素有:

  • trim
  • where
  • set
  • foreach
  • if
  • choose
  • when
  • otherwise
  • bind

然而,包括基于注释的查询中的片段是不可能的。

5  在@mapper注释中,动态写SQL的例子

//bulk insert
    @Insert({"<script> ",
            "insert into CompletedDeviceData (`gatewayID`,`orderId`,`deviceTypeId`,`dataSampledDate`,`data`,`error`)",
            " VALUES ",
            " <foreach collection='dataRecordList' separator=',' index= 'index' item='dataRecord'>",
            "( #{dataRecord.gatewayID},#{dataRecord.orderId},#{dataRecord.deviceTypeId},",
            "#{dataRecord.dataSampledDate},#{dataRecord.data},#{dataRecord.error} )",
            "</foreach> ",
            "</script>"})
    @Options(keyColumn = "recordID", useGeneratedKeys = true)
    int batchInsertRecords(@Param("dataRecordList") List<CompletedDeviceDataEntity> dataRecordList);


 //bulk update or  insert operation
    @Insert({"<script> ",
            "insert into CompletedDeviceData(`gatewayID`,`orderId`,`deviceTypeId`,`dataSampledDate`,`data`,`error`)",
            "VALUES ",
            " <foreach collection='dataRecordList' separator = ',' index='index' item='dataRecord'>",
            " (#{dataRecord.gatewayID},#{dataRecord.orderId},#{dataRecord.deviceTypeId},",
            " #{dataRecord.dataSampledDate},#{dataRecord.data},#{dataRecord.error})",
            "</foreach> ",
            "ON DUPLICATE KEY UPDATE data=VALUES(data), error=VALUES(error)",
            "</script>"})
    @Options(keyColumn = "recordID", useGeneratedKeys = true)
    int batchUpdateOrInsertRecords(@Param("dataRecordList") List<CompletedDeviceDataEntity> dataRecordList);

注: VALUES 里面的参数 要用数据库字段来实现对数据的更新,而不是传入的参数字段!

参考文档:

1. https://www.cnblogs.com/zjdxr-up/p/8319982.html

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐