映射文件详解
参数处理(#和$的区别)
- #{}:可以获取map中的值或者实体对象属性的值;
- ${}:可以获取map中的值或者实体对象属性的值;
select * from person where id=${id} and name=#{name}
# 控制台输出:select * from person where id=2 and last_name=?
区别
- #{}:是以预编译的形式,将参数设置到SQL语句中,相当于JDBC中的 PreparedStatement;可以防止SQL注入;
- ${}:取出的值直接拼接在SQL语句中;会有安全问题;
大多情况下,我们取参数的值都应该去使用 #{} ;
原生 JDBC 不支持占位符的地方我们就可以使用 ${} 进行取值
比如分表、排序等;
# 按照年份分表拆分
select * from ${year}_income where xxx;
#{}更丰富的用法
规定参数的一些规则:
javaType、 jdbcType、 mode(存储过程)、 numericScale、
resultMap、 typeHandler、 jdbcTypeName
jdbcType通常需要在某种特定的条件下被设置:
在我们数据为null的时候,有些数据库可能不能识别 MyBatis 对 NULL 的默认处理。比如Oracle(报错,JdbcType OTHER:无效的类型);
因为 MyBatis 对所有的 NULL 都映射的是原生 JDBC 的 OTHER 类型,Oracle 不能正确处理;
由于全局配置中:jdbcTypeForNull=OTHER;而Oracle不支持OTHER类型;
两种解决办法:
1、给#{}中加上javaType,如:
<insert id="addPer" databaseId="oracle">
<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
select PERSON_SEQ.nextval from dual
</selectKey>
insert into person(id,name,age,email)
values(#{id},#{name},#{age},#{email,jdbcType=NULL})
</insert>
2、在配置文件的settings标签中设置 jdbcTypeForNull=NULL,如:
<settings>
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
parameterType参数类型
parameterType为输入参数,即负责配置的时候传入的参数类型。
parameterType有基本数据类型和复杂的数据类型配置。
基本数据类型
基本数据类型:int,String,long,Date等;
这是在我之前的博客中讲的最多的了
<select id="findByType" parameterType="String" resultType="com.domain.User">
select * from product where product_type like #{product_type}
</select>
复杂数据类型
复杂数据类型:Java实体类和Map
博主暂时只遇到Java实体类的情况,所以就先讲实体类的情况先
传入类型为实体类
这种使用方式广泛应用于实际开发中,由多个对象组成一个查询条件来实现数据的查询。
<select id="findUserByVo" parameterType="com.domain.QueryVo" resultType="com.domain.User">
select * from product where product_type like #{user.product_type}
</select>
QueryVo是我们新建的一个类,如下:
package com.domain;
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
我们可以看到,该类中的参数为User类型的,所以xml中的写法变为"#{user.product_type}"
测试类如下:
/**
* 测试QueryVo作为查询条件
*/
@Test
public void testfindByVo(){
QueryVo vo = new QueryVo();
User user = new User();
user.setProduct_type("%用品%");
vo.setUser(user);
List<User>userList = userDao.findUserByVo(vo);
for (User user1:userList){
System.out.println(user1);
}
}
resultMap结果映射
resultMap标签一般用于对实体类的封装,即将实体类中的字段与数据库表中的字段进行关联映射。
用法:
<resultMap id="自定义ID名" type="实体类" >
<!--主键字段的对应如下-->
<id property="实体类属性" column="数据库主键字段名"/>
<!--非主键字段的对应如下-->
<result property="实体类属性" column="数据库字段名" jdbcType="数据库字段类型(可不写)"/>
</resultMap>
如:
1.当实体类中的字段与数据库表中的字段不相同时,在resultMap标签中将实体类字段与数据库字段进行关联映射
<resultMap id="userMap" type="com.domain.User">
<result property="name" column="product_name"/>
<result property="type" column="product_type"/>
<result property="price" column="product_price"/>
<result property="date" column="regist_date"/>
</resultMap>
2.多表操作中的一对一关联查询
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"/> <!--此处的aid为表中id的别名-->
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<association property="user" javaType="user">
<id property="id" column="id"/>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
注:这里association标签的作用是将account和user两张表关联起来再映射到实体类上。
3.多表操作中的一对多操作
<!-- 定义User的resultMap-->
<!--一对多查询-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account"> <!--ofType指的是集合accounts的类型-->
<id column="aid" property="id"/> <!--aid为列别名,起别名是因为主子表都有该字段-->
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap>
上面嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则。
association关联
- association 可以指定联合的 javaBean 对象
property=“user”:指定哪个属性是联合的对象
javaType:指定这个属性对象的类型(不能省略)
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"/> <!--此处的aid为表中id的别名-->
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<association property="user" javaType="user">
<id property="id" column="id"/>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
- association 定义关联对象的封装规则
select:表明当前属性是调用 select 指定的方法查出的结果
column:指定将哪一列的值传给这个方法
<resultMap type="com.domain.User" id="MyPerByStep">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="age" property="sex"/>
<!-- association定义关联对象的封装规则
select:表明当前属性是调用select指定的方法查出的结果
column:指定将哪一列的值传给这个方法
流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
-->
<association property="comp"
select="com.dao.CompanyMapper.getCompById"
column="id">
</association>
</resultMap>
流程:使用select指定的方法(传入 column 指定的这列参数的值)查出对象,并封装给 property 指定的属性
discriminator鉴别器
MyBatis可以使用 discriminator 判断某列的值,然后根据某列的值改变封装行为
有时候,一个数据库查询可能会返回多个不同的结果集(但总体上还是有一定的联系的)。
鉴别器(discriminator)标签就是被设计来应对这种情况的,另外也能处理其它情况,例如类的继承层次结构。 鉴别器的概念很好理解——它很像 Java 中的 switch 语句
一个鉴别器的定义需要指定 column 和 javaType 属性。column 指定了 MyBatis 查询被比较值的地方。 而 javaType 用来确保使用正确的相等测试(虽然很多情况下字符串的相等测试都可以工作)。
例如:
封装Person
如果查出的是女生:就把公司信息查询出来,否则不查询;
如果是男生,把 name 这一列的值赋值给 email;
<resultMap type="com.domain.User" id="MyEmpDis">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="sex" property="sex"/>
<!--
column:指定判定的列名
javaType:列值对应的java类型
-->
<discriminator javaType="string" column="sex">
<!--女生 resultType:指定封装的结果类型;不能缺少。/resultMap-->
<case value="0" resultType="com.domain.User">
<association property="comp"
select="com.dao.CompanyMapper.getCompById"
column="id">
</association>
</case>
<!--男生 如果是男生,把name这一列的值赋值给email; -->
<case value="1" resultType="com.domain.User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="name" property="email"/>
<result column="sex" property="sex"/>
</case>
</discriminator>
</resultMap>
在这个示例中,MyBatis 会从结果集中得到每条记录,然后比较它的 sex 的值。 如果它匹配任意一个鉴别器的 case,就会使用这个 case 指定的结果映射。 这个过程是互斥的,也就是说,剩余的结果映射将被忽略。 如果不能匹配任何一个 case,MyBatis 就只会使用鉴别器块外定义的结果映射。