Mybatis mapper层的传参问题


Mybatis对mapper层中,参数的绑定

参考链接:

在写项目的过程中用到mybatis层中,有关于@Param的使用和参数的绑定一直是个坑,这里记录一下

mapper层的格式

public interface MessageInfoMapping {
	@Select("select a.id, a.message_name, a.message_url, a.message_pwd, a.message_author, a.created, a.updated, "
			+ "b.type_name from `message_info` as a inner join `message_type` as b "
			+ "on a.message_typeId = b.id")
	List<MessageInfoEntity> getMessageAll();
  
	@Insert("insert into `message_info` (`message_name`, `message_url`, `message_typeId`,`message_pwd`, `message_author`) "
			+ "values(#{messageName}, #{messageUrl}, #{messageTypeId}, #{messagePwd}, #{messageAuthor})")
	void addMessage(MessageInfoEntity message);
  
	@Select("select * from `message_info` where message_url = #{messageUrl}")
	MessageInfoEntity getMessageByUrl(String messageUrl);
  
	@Delete("delete from `message_info` where message_url = #{messageUrl}")
	void deleteMessageByUrl(String messageUrl);
  
	@Update("update `message_info` SET message_name = #{message.messageName}, message_url = #{message.messageUrl}, "+ "message_typeId=#{message.messageTypeId}, message_pwd=#{message.messagePwd}, message_author=#{message.messageAuthor} "+ "where message_url=#{oldUrl}")
	void updateMessage(@Param("message")MessageInfoEntity message, @Param("oldUrl") String oldUrl);
}

​ 引入mybatis依赖后,先创建实体类entity,再写mapper层的接口。mapper层可以不用加任何springboot注解哦~,可以统一在启动类加上扫包@MapperScan(...)

​ 接口里面就是SQL常见的crud操作了。下面主要说明和记录一下方法传参数的时候坑。

由参数问题引发的bug

​ 有时候可能会觉得莫名其妙,有的时候一个参数明明不用添加 @Param 注解,有的时候,却需要添加,不添加会报错。

常见需要使用@Param的场景

首先,如下几个需要添加 @Param 注解的场景,相信大家都已经有共识了:

  • 第一种:方法有多个参数,需要 @Param 注解

例如下面这样:

@Mapper
public interface UserMapper {
    Integer insert(@Param("username") String username, @Param("address") String address);
}

对应的 XML 文件如下:

<insert id="insert" parameterType="org.javaboy.helloboot.bean.User">
    insert into user (username,address) values (#{username},#{address});
</insert>

这是最常见的需要添加 @Param 注解的场景。

  • 第二种:方法参数要取别名,需要 @Param 注解

当需要给参数取一个别名的时候,我们也需要 @Param 注解,例如方法定义如下:

@Mapper
public interface UserMapper {
    User getUserByUsername(@Param("name") String username);
}

对应的 XML 定义如下:

<select id="getUserByUsername" parameterType="org.javaboy.helloboot.bean.User">
    select * from user where username=#{name};
</select>

老实说,这种需求不多,费事。

  • 第三种:XML 中的 SQL 使用了 $ ,那么参数中也需要 @Param 注解

$ 会有注入漏洞的问题,但是有的时候你不得不使用 $ 符号,例如要传入列名或者表名的时候,这个时候必须要添加 @Param 注解,例如:

@Mapper
public interface UserMapper {
    List<User> getAllUsers(@Param("order_by")String order_by);
}

对应的 XML 定义如下:

<select id="getAllUsers" resultType="org.javaboy.helloboot.bean.User">
    select * from user
    <if test="order_by!=null and order_by!=''">
        order by ${order_by} desc
    </if>
</select>

前面这三种,都很容易懂,相信很多小伙伴也都懂,除了这三种常见的场景之外,还有一个特殊的场景,经常被人忽略。

  • 第四种,那就是动态 SQL ,如果在动态 SQL 中使用了参数作为变量,那么也需要 @Param 注解,即使你只有一个参数。

如果我们在动态 SQL 中用到了 参数作为判断条件,那么也是一定要加 @Param 注解的,例如如下方法:

@Mapper
public interface UserMapper {
    List<User> getUserById(@Param("id")Integer id);
}

定义出来的 SQL 如下:

<select id="getUserById" resultType="org.javaboy.helloboot.bean.User">
    select * from user
    <if test="id!=null">
        where id=#{id}
    </if>
</select>

这种情况,即使只有一个参数,也需要添加 @Param 注解,而这种情况却经常被人忽略!

mapper层的SQL语句传入List

  • 首先,我遇到过的错误:
Parameter array not found. Available parameters are [collection, list]

报错原因主要是,当我们要查询一些的信息时,可能会采用list集合或者数组作为参数传入方法中。

<select id="findSomeUsers" resultType="user3" parameterType="list">
  select * from user where id in
  <foreach collection="noList" index="index" item="no" open="(" separator="," close=")">
 	#{no}
  </foreach>
</select>

这时报错是因为,传递一个 List 实例或者数组作为参数对象传给 MyBatis,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list” 作为键,而数组实例将会以“array”作为键。解决这个异常的两种方式是:
1.在方法参数前面加上你遍历的集合的名称,比如你在foreach的collection中写的是noList,那么你就在传入的list参数前面加上一个注解@Param(“noList”)。
2.将foreach的collection中的值改成list即可。

  • 在实际开发中,上述报错,下面代码为一项目中使用的正确代码:
@Select({ "<script>", "select * from `product_category` where category_type in ",
"<foreach collection='categoryTpyeList' item='item' index='index' open='(' separator=',' close=')'>",
"#{item}", "</foreach>", "</script>" })
public List<ProductCategoryEntity> findByCategoryTpye(
  @Param("categoryTpyeList") List<Integer> categoryTpyeList
);

​ - collection: 指定要遍历的集合(三种情况 list,array,map) !!!!在这种使用注解sql的情况下,这里请填写mapper方法中集合的名称

​ - item:将当前遍历出的元素赋值给指定的变量 (相当于for循环中的i)

​ - separator:每个元素之间的分隔符

​ - index:索引。遍历list的时候是index就是索引,item就是当前值

​ - #{变量名}就能取出变量的值也就是当前遍历出的元素


文章作者: 小小千千
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小小千千 !
评论
  目录