MyBatis多参数传递的四种方式

MyBatis多参数传递的四种方式

2015年12月06日 16:06:47

阅读数:8253

一、多参数传递之注解方式示例

若映射器中的方法只有一个参数,则在对应的SQL语句中,可以采用#{参数名}的方式来引用此参数,以前的例子多属于此类。但这种方法却不适用于需要传递多个参数的情况,今天就来介绍如何使用注解传递多个参数。

1、使用注解实现多参数传递
      首先应引入“org.apache.ibatis.annotations.Param”,我们在接口TeacherMapper中引入,并增加一个教师分页查询的方法findTeacherByPage的声明。如下所示:

 
  1. package com.abc.mapper;

  2. import com.abc.domain.Teacher;

  3. import org.springframework.stereotype.Component;

  4. import java.util.List;

  5. //使用@Param注解需要先引入Param

  6. import org.apache.ibatis.annotations.Param;

  7. //@Component指定映射器名称为myTeacherMapper

  8. //相关内容,可参考笔者博客:

  9. //http://legend2011.blog.51cto.com/3018495/980150

  10. @Component("myTeacherMapper")

  11. public interface TeacherMapper {

  12. public Teacher getById(int id);

  13. //分页查询教师信息

  14. public List<Teacher> findTeacherByPage(

  15. //使用@Param("sort")注解,即可在SQL语句中

  16. //以“#{sort}”的方式引用此方法的sort参数值。

  17. //当然也可以在@Param中使用其他名称,

  18. //如@Param("mysort")

  19. @Param("sort") String sort,//排序字段

  20. //以下三个注解同理

  21. @Param("dir") String dir, //排序方向

  22. @Param("start") int start, //起始记录

  23. @Param("limit") int limit //记录条数

  24. );

  25. }


对应的映射文件TeacherMapper.xml的内容如下:

 
  1. <?xmlversion="1.0"encoding="utf8"?>

  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

  4. <!--与以前一样,namespace的值是对应的映射器接口的完整名称-->

  5. <mapper namespace="com.abc.mapper.TeacherMapper">

  6. <!--教师实体映射-->

  7. <resultMap id="supervisorResultMap"type="Teacher">

  8. <id property="id"/>

  9. <result property="name"/>

  10. <result property="gender"/>

  11. <result property="researchArea"column="research_area"/>

  12. <result property="title"/>

  13. <!--collection元素映射教师的指导学生集合的属性。这里采用了

  14. “命名空间名.select语句id”的形式来引用StudentMapper.xml中的

  15. select语句getStudents。

  16. -->

  17. <collection property="supStudents" column="id" ofType="Student"

  18. select="com.abc.mapper.StudentMapper.getStudents"/>

  19. </resultMap>

  20. <select id="findTeacherByPage" resultMap="supervisorResultMap">

  21. select * from teacher

  22. order by ${sort} ${dir} limit #{start},#{limit}

  23. </select>

  24. </mapper>

运行主程序如下:

 
  1. package com.demo;

  2. import org.springframework.context.ApplicationContext;

  3. import com.abc.mapper.StudentMapper;

  4. import com.abc.mapper.TeacherMapper;

  5. import com.abc.domain.Teacher;

  6. import com.abc.domain.Student;

  7. import org.springframework.context.support.ClassPathXmlApplicationContext;

  8. import java.util.List;

  9. public class CollectionDemo

  10. {

  11. private static ApplicationContext ctx;

  12. static

  13. {

  14. //在类路径下寻找resources/beans.xml文件

  15. ctx = new ClassPathXmlApplicationContext("resources/beans.xml");

  16. }

  17. public static void main(String[] args)

  18. {

  19. //从Spring容器中请求映射器

  20. TeacherMapper mapper =

  21. (TeacherMapper)ctx.getBean("myTeacherMapper");

  22. Teacher teacher = null;

  23. //查询教师分页信息

  24. List<Teacher> teachers =

  25. //以name字段升序排序,从第0条记录开始查询。

  26. //查询2条记录

  27. mapper.findTeacherByPage("name","asc",0, 2);

  28. if(teachers == null)

  29. {

  30. System.out.println("未找到相关教师信息。");

  31. }

  32. else

  33. {

  34. Object[] t = teachers.toArray();

  35. System.out.println("**********************************************");

  36. for(int i = 0; i < t.length; i++)

  37. {

  38. teacher = (Teacher)t[i];

  39. System.out.println("教师姓名:" + " " + teacher.getName());

  40. System.out.println("教师职称:" + " " + teacher.getTitle());

  41. System.out.println("指导学生信息:");

  42. //遍历指导的学生

  43. for(Student s : teacher.getSupStudents())

  44. {

  45. System.out.println( s.getName() + " " + s.getGender()

  46. + " " + s.getGrade()

  47. + " " + s.getMajor());

  48. }

  49. System.out.println("**********************************************");

  50. }

  51. }

  52. }

  53. }


2、可能会遇到的错误
      关于order by
      一般而言,我们会使用#{参数名}的形式来引用方法中的参数,但这种方式对于order by子句无效或报错。例如,当TeacherMapper.xml的select语句findTeacherByPage中的order by子句以#{sort}的形式引用方法中的sort参数的值时,是无效的(读者可自行验证);以#{dir}的形式引用方法中的dir参数的值时,会报MySQLSyntaxErrorException。因此,在这里使用了${参数名}的形式引用了相应的参数值。

二、多参数传递之默认命名方式示例

       对于映射器中的方法,MyBatis默认从左到右给方法的参数命名为param1、param2…,依次类推。我们可以无需借助注解,直接在SQL语句中使用这些默认名称。首先去掉@Param注解的TeacherMapper.java如下所示:

 
  1. package com.abc.mapper;

  2. import com.abc.domain.Teacher;

  3. import org.springframework.stereotype.Component;

  4. import java.util.List;

  5. //@Component指定映射器名称为myTeacherMapper

  6. //相关内容,可参考笔者博客:

  7. //http://legend2011.blog.51cto.com/3018495/980150

  8. @Component("myTeacherMapper")

  9. public interface TeacherMapper {

  10. public Teacher getById(int id);

  11. //分页查询教师信息

  12. public List<Teacher> findTeacherByPage(

  13. String sort,//排序字段

  14. String dir, //排序方向

  15. int start, //起始记录

  16. int limit //记录条数

  17. );

  18. }


按照上述的默认命名方式,MyBatis对findTeacherByPage方法的参数从左到右的默认命名依次是:sort为param1,dir为param2,start为param3,limit为param4。然后,就可以在映射文件TeacherMapper.xml里的、与此方法相对应的SQL语句中以#{参数名}的方式来使用这些名称了。如下第25行所示:

 
  1. <?xml version="1.0" encoding="utf8"?>

  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

  4. <!--与以前一样,namespace的值是对应的映射器接口的完整名称-->

  5. <mapper namespace="com.abc.mapper.TeacherMapper">

  6. <!--教师实体映射-->

  7. <resultMap id="supervisorResultMap" type="Teacher">

  8. <id property="id"/>

  9. <result property="name"/>

  10. <result property="gender"/>

  11. <result property="researchArea"column="research_area"/>

  12. <result property="title"/>

  13. <collection property="supStudents" column="id" ofType="Student"

  14. select="com.abc.mapper.StudentMapper.getStudents"/>

  15. </resultMap>

  16. <!--param1、param2等是MyBatis对映射器方法参数的默认命名-->

  17. <select id="findTeacherByPage" resultMap="supervisorResultMap">

  18. select * from teacher

  19. order by ${param1} ${param2} limit #{param3},#{param4}

  20. </select>

  21. </mapper>


      #{…}与${…}差异小议
      MyBatis官方文档(http://code.google.com/p/mybatis/wiki/faq)对两者的描述是:#{…}是一个参数标记,而${…}只是简单的字符串替换。一般而言,为避免SQL注入攻击,传递参数应使用#{…}方式,因为这样MyBatis会处理好特殊字符转义的问题;但在SQL语句的某些地方,又不能使用#{…}方式。上述文档举出的例子是不能用这种方式指定表名,而根据我们的经验,在order by子句中也不能用这种方式。从中我们可以总结出:对于诸如表名、字段名(如order by子句后的排序字段)这些表本身或其字段的名字,和SQL关键字(如order by子句后的asc关键字),是不能使用#{…}方式的,而只能使用字符串替换的${…}方式。

三、MyBatis多参数传递之Map方式示例

首先修改映射器接口TeacherMapper中的findTeacherByPage方法如下:

 
  1. //分页查询教师信息

  2. public List<Teacher> findTeacherByPage(Map<String, Object> map);

相应地,这里用到了Map接口,就应该引入此接口:import java.util.Map。
在执行类CollectionDemo中,调用findTeacherByPage方法的相关代码如下:

 
  1. Map<String, Object> params = new HashMap<String, Object>();

  2. //以name字段升序排序,

  3. params.put("sort", "name");

  4. params.put("dir", "asc");

  5. //查询结果从第0条开始,查询2条记录

  6. params.put("start", 0);

  7. params.put("limit", 2);

  8. //查询职称为教授或副教授的教师

  9. params.put("title", "%教授");

  10. //分页查询教师信息

  11. List<Teacher> teachers = mapper.findTeacherByPage(params);


可以看出,我们先把参数放在了一个Map中,这样我们就可以在相应的SQL语句中以#{…}的形式引用这些参数了。如下所示:

 
  1. <select id="findTeacherByPage" resultMap="supervisorResultMap"

  2. parameterType="java.util.Map">

  3. select * from teacher where title like #{title}

  4. order by ${sort} ${dir} limit #{start},#{limit}

  5. </select>


与以前一样,在order by子句中应使用${…}的方式。实际上,这里的parameterType="java.util.Map"可以不要。

四、MyBatis多参数传递之混合方式

在默认命名方式(MyBatis多参数传递之默认命名方式示例)一文中,介绍了MyBatis对参数的默认命名,这种命名在这种情况下依然有效。我们需要做的,就是如何根据这个命名读出Map中的参数值。这里就采用这种方式来实现教师分页查询。先修改映射器接口(TeacherMapper.java)中的教师分页查询方法的声明如下。

 
  1. //分页查询教师信息

  2. public List<Teacher> findTeacherByPage(

  3. Map params, //查询条件

  4. int start, //起始记录

  5. int limit //记录条数

  6. );


那么MyBatis将会对此方法的三个参数依次命名为param1、param2和param3,其中第一个参数为Map类型,后两个参数为int类型。

 执行类(CollectionDemo.java)中的查询代码片段如下: 

 
  1. Map<String, Object> params =

  2. new HashMap<String, Object>();

  3. //以name字段升序排序,

  4. params.put("sort", "name");

  5. params.put("dir", "asc");

  6. //查询职称为教授或副教授的教师

  7. params.put("title", "%教授");

  8. //查询教师分页信息

  9. List<Teacher> teachers =

  10. //以name字段升序排序,从第0条记录开始查询。

  11. //查询2条记录

  12. mapper.findTeacherByPage(params,0, 2);


相应的映射配置(TeacherMapper.xml)文件片段如下: 

 
  1. <selectid="findTeacherByPage"resultMap="supervisorResultMap">

  2. select * from teacher where teacher.title like

  3. #{param1.title} order by ${param1.sort} ${param1.dir} limit #{param2},#{param3}

  4. </select>


在以上的映射文件中,使用#{param1.title}的形式就能访问Map中title属性的值。当然,在order by子句中应使用${param1.sort}的形式,在本例中使用“#”也是可以的,由此我们可以总结出,我们使用#{参数默认命名.属性名}的形式,就可以在映射文件访问Map参数的属性值。

猜你喜欢

转载自blog.csdn.net/f45056231p/article/details/81631376