MyBatis学习笔记】10:#和$,sql元素,resultMap的结构/构造器,存储结果集
在MyBatis的SQL中使用#{}
和${}
都会被视为特殊字符串来处理。前者是设置了参数,MyBatis会将参数设置到语句中(默认是PreparedStatement)。后者是传递特殊字符串所对应的变量值,而不是传递参数。
修改上篇中@Param
传递多参数的例子。
为映射器接口中的方法添加一个参数:
List<Person> findPersonByAnnotation(@Param("columns") String columns,@Param("surname") String surname, @Param("sexType") SexType sexType);
- 1
修改相应的映射配置,将使用${}
将这个参数变成直出的变量:
<!--使用注解传递参数,这时是不涉及单独一个类型的,所以去掉parameterType属性-->
<!--必备的属性解析(如sex_type需要解析成整数下标)需要指明,因为参数不再全是String-->
<select id="findPersonByAnnotation" resultMap="personMap">
SELECT ${columns}
FROM person
WHERE name LIKE CONCAT(#{surname}, '%')
AND sex_type = #{sexType,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}
</select>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
在主类中使用查询:
List<Person> personList = personMapper.findPersonByAnnotation("id,name","刘",SexType.MALE);
- 1
查询结果:
只查询了这两列,所以其它属性是空。
映射配置中的sql元素
基本使用
映射配置中的sql
元素用于定义一串SQL语句的组成部分,其它的语句可以通过引用来使用它。
如要实现和前面一样的功能,可以不从参数传入${}
,而是配置到sql
元素中解耦:
<sql id="columns">
id,name
</sql>
<select id="findPersonByAnnotation" resultMap="personMap">
SELECT <include refid="columns"/>
FROM person
WHERE name LIKE CONCAT(#{surname}, '%')
AND sex_type = #{sexType,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}
</select>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
这里<include refid="sql元素的id"/>
即是将这部分SQL代码原封不动的引用到了相应位置上。
向sql元素中传参
可以在include
元素内配置property
子元素,向sql
元素中传递参数,再将转化${参数名}
为相应参数值后的SQL引入该位置。
还是相同的功能,若将表名作为参数传入:
<sql id="columns">
${prefix}.id, ${prefix}.name
</sql>
<select id="findPersonByAnnotation" resultMap="personMap">
SELECT
<include refid="columns">
<!--设置sql元素中的${prefix}的参数值为person(表名)-->
<property name="prefix" value="person"/>
</include>
FROM person
WHERE name LIKE CONCAT(#{surname}, '%')
AND sex_type = #{sexType,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}
</select>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
resultMap元素结构
<!--结果集映射-->
<resultMap id="" type="">
<!--配置构造方法-->
<constructor>
<idArg column="" javaType=""/>
<arg column="" javaType=""/>
</constructor>
<!--主属性-->
<id property="" column=""/>
<!--非主属性-->
<result property="" column=""/>
<!--一对一关系-->
<association property="" column="" select=""/>
<!--一对多关系-->
<collection property="" column="" select=""/>
<!--鉴别器-->
<discriminator javaType="" column="">
<case value="" resultMap=""/>
</discriminator>
</resultMap>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
constructor子元素
使用resultMap
的constructor
子元素来配置一个POJO的构造器,因为POJO类不见得会有无参构造方法。可以认为后面的id
和result
子元素对应的是setter方法传参,而这个子元素则是用构造方法来传参构造POJO对象的。
使用constructor
元素时,里面的idArg
子元素表示主属性,arg
子元素则是非主属性,使用方法和id
与result
元素类似。
存储结果集
使用POJO存储结果集
前面学习的一直是这种方式,只要select
元素配置了resultMap
属性指向一个结果映射,或者使用resultType
属性指向一个POJO类或其别名,那么Mapper接口的相应方法就应当设计成返回一个POJO对象的形式。
使用Map存储结果集
就像使用Map可以做多参数传递一样,结果集也是多个参数的集合,可以全部存在Map里面。使用resultType="map"
,那么Mapper接口的相应方法就应当设计成返回一个Map接口的实现类对象的形式。
映射文件中添加:
<!--使用Map存储结果集,所以resultType="map"-->
<select id="findToMap" resultType="map">
SELECT *
FROM person
WHERE name LIKE CONCAT(#{surname}, '%')
AND sex_type = #{sexType,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}
</select>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
映射器接口中添加相应的方法:
List<HashMap<String,String>> findToMap(@Param("surname") String surname, @Param("sexType") SexType sexType);
- 1
主类中使用,获取到一个存Map实现类的List,然后遍历,以数据库中的列名(而不是POJO属性名)为key获取结果集各个列的值:
//调用工具类的静态方法开启并获取一个SqlSession实例
sqlSession = SqlSessionFactoryUtil.openSqlSession();
//获取映射器代理类对象
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
//传给这个查询方法,用于查询
List<HashMap<String,String>> mapList = personMapper.findToMap("刘",SexType.MALE);
//输出,注意以数据库中的列名(而不是POJO属性名)为key
for (HashMap p:mapList) {
System.out.println(p.get("id")+","+p.get("name")+","+p.get("sex_type")+","+p.get("id_card"));
}
//善后处理...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
运行结果:
从第三列是1可以看出,这种方式的一大特点即在于,数据库中存的是什么,查出来的就是什么样的字符串。在多数时候,这样可能会失去语义(如1本来应代表枚举MALE),而且使用这种方式会让可读性下降。