一 介绍
映射文件指导着MyBatis如何进行数据库增删改查,有着非常重要的意义;
-
cache
–命名空间的二级缓存配置 -
cache-ref
– 其他命名空间缓存配置的引用。 -
resultMap
– 自定义结果集映射 -
parameterMap
– 已废弃
!老式风格的参数映射 -
sql
–抽取可重用语句块。 -
insert
– 映射插入语句 -
update
– 映射更新语句 -
delete
– 映射删除语句 -
select
– 映射查询语句
二 主键生成方式
- 若数据库
支持
自动生成主键的字段(比如 MySQL和 SQL Server),则可以设置useGeneratedKeys=”true”
,然后再把keyProperty
设置到目标属性上。
<insert id="insertUser" parameterType="com.zyc.entity.User" useGeneratedKeys="true" keyProperty="id">
insert into t_user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
还可以
将insert插入的数据的主键返回
到User对象中
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id()
</selectKey>
mysql的uuid()
,实现非自增主键的返回
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
select uuid()
</selectKey>
insert into t_user (id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address})
- 而对于
不支持
自增型主键的数据库(例如Oracle),则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会`被设置·,然后插入语句会被调用
<insert id="addEmployee" databaseId="oracle">
<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
select EMPLOYEE_SEQ.nextval from dual
</selectKey>
<!-- 插入的主键是从序列中获取的 -->
insert into employee(id,last_name,age,email)
values(#{id},#{lastName},#{age},#{email})
</insert>
三 参数传递
单个参数
mybatis不会做特殊处理,#{参数名/任意名}
:取出参数值(测试得:真的任意名都可以
)
多个参数
mybatis会做特殊处理,多个参数会被封装成 一个map
key:param1...paramN
,或者arg0...argN-1
<select id="findUserById" parameterType="int" resultType="com.zyc.entity.User">
select username,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex,address from t_user where id=#{id}
</select>
命名参数
明确指定封装参数时map的key;@Param("id")
public User findUserByIdAndName(@Param("id")int id, @Param("name")String name);
映射文件
<select id="findUserByIdAndName" resultType="com.zyc.entity.User">
select username,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex,address from t_user where id=#{id} and username = #{name}
</select>
POJO
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;
#{属性名}
:取出传入的pojo的属性值
<select id="findUserByUser" parameterType="com.zyc.entity.User" resultType="com.zyc.entity.User">
select username,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex,address from t_user where id=#{id}
</select>
Map
这个是我们自己传得map,不是上面多参数是mybatis帮我们处理得。所以可以直接通过key
来获取
<select id="findUserByMap" resultType="com.zyc.entity.User">
select username,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex,address from t_user where id=#{id}
</select>
集合类型参数
#{list[0]}
,数组就是#{array[0]}
<select id="findUserByList" resultType="com.zyc.entity.User">
select username,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex,address from t_user where id=#{list[1]}
</select>
四 #和$
#{key}
:获取参数的值,预编译到SQL中(因为预编译
,最好用在where
里面,测试发现:在编译之后加了引号)。安全。
${key}
:获取参数的值,拼接到SQL中。有SQL注入问题。
五 resultType
简单类型
<select id="getEmpNameById" resultType="string">
POJO
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以
映射成功。如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个
一致,就会创建pojo对象。(验证通过
)
<select id="findUserByMap" resultType="com.zyc.entity.User">
List类型
没什么区别
Mapper
public List<User> findUserByName(String username);
映射文件
<select id="findUserByList" resultType="com.zyc.entity.User">
Map类型
查询一条记录
将查询的数据以{表字段名, 对应的值}
方式存入到Map中。
Mapper
Map<String, Object> getEmpAsMapById(Integer id);
映射文件
<select id="getEmpAsMapById" resultType="map">
select * from t_employee where id = #{id}
</select>
查询多条记录
可以把查询的数据以{表中某一字段名, JavaBean}
方式来封装成Map。
mapper
// 查询所有员工的信息,把数据库中的 'id' 字段作为 key,对应的 value 封装成 Employee 对象
// @MapKey 中的值表示用数据库中的哪个字段名作 key
@MapKey("id")
Map<Integer, Employee> getAllEmpsAsMap();
映射文件
<!--
注意 resultType 返回值类型,不再是 'map',而是 Map 的 value 对应的 JavaBean 类型
-->
<select id="getAllEmpsAsMap" resultType="employee">
select * from t_employee
</select>
自动映射
全局setting设置
-
autoMappingBehavior
默认是PARTIAL
,开启自动映射的功能。唯一的要求是列名和javaBean属性名一致
- 如果autoMappingBehavior设置为
null
则会取消自动映射 - 数据库字段命名规范,POJO属性符合
驼峰命名法
,如A_COLUMNaColumn,我们可以开启自动驼峰命名规则映射功能,mapUnderscoreToCamelCase=true
。
六 自定义resultMap
可以实现高级结果集映射
范例
<!--自定义某个javaBean的封装规则
type:自定义规则的Java类型
id:唯一id方便引用
-->
<resultMap type="com.zyc.entity.User" id="rm1">
<!--指定主键列的封装规则
id定义主键会底层有优化;
column:指定哪一列
property:指定对应的javaBean属性
-->
<id column="id" property="id"/>
<!-- 定义普通列封装规则 -->
<result column="username" property="username"/>
<!-- 其他不指定的列会自动封装:我们只要写resultMap就把全部的映射规则都写上。 -->
</resultMap>
<!-- resultMap:自定义结果集映射规则; -->
<!-- public Employee getEmpById(Integer id); -->
<select id="findUserByRm1" resultMap="rm1">
select id,username ,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex ,address from t_user where id=#{id}
</select>
"一对一"
查询Employee的同时查询员工对应的部门
,就像hibernate中得一对一
sql语句
<select id="getEmpAndDept" resultMap="MyDifEmp">
SELECT
e.id,
e.lastname,
e.gender,
d.id did,
d.dept_name
FROM
tbl_employee e,
tbl_dept d
WHERE
e.d_id = d.id
AND e.id = #{id}
</select>
级联属性
<!--
联合查询:级联属性封装结果集
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="gender" property="gender"/>
<result column="did" property="dept.id"/>
<result column="dept_name" property="dept.departmentName"/>
</resultMap>
使用association
<!--
使用association定义关联的单个对象的封装规则;
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="gender" property="gender"/>
<!-- association可以指定联合的javaBean对象
property="dept":指定哪个属性是联合的对象
javaType:指定这个属性对象的类型[不能省略]
-->
<association property="dept" javaType="com.atguigu.mybatis.bean.Department">
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
</association>
</resultMap>
association分步查询
- 先按照员工id查询员工信息
- 根据查询员工信息中的d_id值去部门表查出部门信息
- 部门设置到员工中;
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!-- association定义关联对象的封装规则
select:表明当前属性是调用select指定的方法查出的结果
column:指定将哪一列的值传给这个方法
流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
-->
<association property="dept"
select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
column="d_id">
</association>
</resultMap>
延迟加载(懒加载)
主配置文件
<!-- 可以使用延迟加载(懒加载);(按需加载)
Employee==>Dept:
我们每次查询Employee对象的时候,都将一起查询出来。
部门信息在我们使用的时候再去查询;
分段查询的基础之上加上两个配置:
-->
<settings>
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
<setting name="jdbcTypeForNull" value="NULL"/>
<!--显示的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
"一对多"
例如:查询部门的时候将部门对应的所有员工信息也查询出来
sql语句
<select id="getEmpsByDeptId" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where d_id=#{deptId}
</select>
一次查询
<!--嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则 -->
<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDept">
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
<!--
collection定义关联集合类型的属性的封装规则
ofType:指定集合里面元素的类型
-->
<collection property="emps" ofType="com.atguigu.mybatis.bean.Employee">
<!-- 定义这个集合中元素的封装规则 -->
<id column="eid" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
<!-- public Department getDeptByIdPlus(Integer id); -->
<select id="getDeptByIdPlus" resultMap="MyDept">
SELECT d.id did,d.dept_name dept_name,
e.id eid,e.last_name last_name,e.email email,e.gender gender
FROM tbl_dept d
LEFT JOIN tbl_employee e
ON d.id=e.d_id
WHERE d.id=#{id}
</select>
分步查询
<!-- collection:分段查询 -->
<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDeptStep">
<id column="id" property="id"/>
<id column="dept_name" property="departmentName"/>
<collection property="emps"
select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
column="{deptId=id}" fetchType="lazy"></collection>
</resultMap>
<!-- public Department getDeptByIdStep(Integer id); -->
<select id="getDeptByIdStep" resultMap="MyDeptStep">
select id,dept_name from tbl_dept where id=#{id}
</select>
扩展:传递多列得值
- 分步查询的时候通过column指定,将对应的列的数据传递过去,我们有时需要传递
多列数据
。使用{key1=column1,key2=column2…}
的形式 -
association
或者collection
标签的fetchType=eager/lazy
可以覆盖全局
的延迟加载策略,指定立即加载(eager)或者延迟加载(lazy)
鉴别器
discriminator
<!-- <discriminator javaType=""></discriminator>
鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为
封装Employee:
如果查出的是女生:就把部门信息查询出来,否则不查询;
如果是男生,把last_name这一列的值赋值给email;
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!--
column:指定判定的列名
javaType:列值对应的java类型 -->
<discriminator javaType="string" column="gender">
<!--女生 resultType:指定封装的结果类型;不能缺少。/resultMap-->
<case value="0" resultType="com.atguigu.mybatis.bean.Employee">
<association property="dept"
select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
column="d_id">
</association>
</case>
<!--男生 ;如果是男生,把last_name这一列的值赋值给email; -->
<case value="1" resultType="com.atguigu.mybatis.bean.Employee">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="last_name" property="email"/>
<result column="gender" property="gender"/>
</case>
</discriminator>
</resultMap>