我所知的Mybatis03————mapper.xml的属性配置研究
xml约束:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.asjy.dao.UserMapper">
</mapper>
全部写在<mapper>中
<!-- namespace:名称空间,对statement进行分类管理,类似于包名,在Mapper代理时,namespace有特殊且重要的作用 -->
========================================================================================================================================
1.Mapper代理开发方式
要实现mapper代理的开发方式,需要遵循一些开发规范
|----需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中
|----mapper接口的全限定类名要和mapper映射文件的namespace的值相同。
|----mapper接口的方法入参只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
接口: xml:
|----mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致;
接口: xml:
|----mapper接口的方法名要和mapper映射文件中的id保持一致;
========================================================================================================================================
2.mapper.xml属性
根据用户ID查询用户信息
例:
<select id="findUserById" parameterType="int" resultType="com.aishang.domain.User">
select * from user where uid = #{id}
</select>
1、#{}:表示一个占位符,如果入参是简单类型,那么#{}里面的入参名可以任意起名;
2、parameterType:入参对应的java类型;
3、resultType:输出结果所映射的java类型(对于单表查询的话用resultType是最合适的,多表联合用resultMap);
根据用户名称来模糊查询用户信息列表
例:
<select id="findUserByName1" parameterType="java.lang.String" resultType="com.aishang.domain.User">
select * from user where username like '%${value}%'
</select>
添加用户
例:
<insert id="insertUser1" parameterType="com.aishang.domain.User">
insert into user(username,password,name,email,phone,addr,state)
values(#{username},#{password},#{name},#{email},#{phone},#{addr},#{state})
</insert>
1、占位符#{}里面写的名字和数据库字段名字一样
添加用户后返回主键 ------ 之主键自增
我用过的地方是,当我添加完一个订单,需要同时添加订单项,这时就需要刚添加完的订单主键ID,添加完再查出ID,再保存,再调用,很麻烦,mybatis中提供了一个便捷方法
例:
<insert id="insertUser2" parameterType="com.aishang.domain.User">
<selectKey keyProperty="uid" resultType="int" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,password,name,email,phone,addr,state)
values(#{username},#{password},#{name},#{email},#{phone},#{addr},#{state})
</insert>
1、selectKey:查询主键,在标签内需要输入查询主键的sql;
2、keyProperty:查询出来的主键值怎么返回?"User"类中"uid"列用来容纳查询出来的生成的主键的值,此配置指明在实体类中用来容纳查询出的主键的属性名;
3、order:指定查询主键的sql和insert语句的执行顺序
| ---- BEFORE: 如果是oracle数据库的话,不是主键自增机制,而是序列机制,
需要先生成一个序列,拿到序列后再执行插入,因此采用的是order="BEFORE"
如果是UUID,也需要先生成一个UUID,再执行插入,也采用order="BEFORE"
| ---- AFTER:mysql中,采用自增主键策略 在insert的时候产生主键,所以在执行完insert之后,再来获取生成的主键,因而在这里配置,order="AFTER"
4、LAST_INSERT_ID():该函数是mysql函数,针对自增主键来获取主键的id,必须配合insert语句一起使用
添加用户后返回主键 -- 之UUID
例:
<insert id="insertUser3" parameterType="com.aishang.domain.User">
<selectKey keyProperty="uid" resultType="java.lang.String" order="BEFORE">
select UUDI()
</selectKey>
insert into user(uid,username,password,name,email,phone,addr,state)
values(#{uid},#{username},#{password},#{name},#{email},#{phone},#{addr},#{state})
</insert>
1、UUDI():该函数是mysql函数,生成一个32位随机不重复的数据;
2、uid不是自增了,也需要插入进去,采用的值是上一步 select UUDI()的结果,已经封装到了User对象的uid属性了;
添加用户后返回主键 -- 之Oracle序列
<insert id="insertUser4" parameterType="com.aishang.domain.User">
<selectKey keyProperty="uid" resultType="int" order="BEFORE">
select seq.nextval() from dual
</selectKey>
insert into user(uid,username,password,name,email,phone,addr,state)
values(#{uid},#{username},#{password},#{name},#{email},#{phone},#{addr},#{state})
</insert>
1、sequence:是Oracle主键生成策略;
2、uid不是自增了,也需要插入进去,采用的值是上一步 select UUDI()的结果,已经封装到了User对象的uid属性了;
=========================================================================================================================================
3.动态SQL
Mybatis提供的各种动态标签实现动态拼接sql,使得mapper映射文件在编写SQL时更加灵活,方便。常用动态SQL标签有:if、where、foreach;
例:
<select id="findUserList" parameterType="UserWapper" resultType="user">
select * from user
<where>
<if test="user !=null">
<if test="user.username != null and user.username !='' ">
and username like '%${user.username}%'
</if>
<if test="user.password != null and user.password != '' ">
and password= #{user.password}
</if>
</if>
</where>
</select>
1、if标签:如果符合条件,则把if标签内的SQL语句拼接上;
2、where标签:会去掉第一个符合条件的and符号,其余正常拼接
SQL片段
类似于静态包含
例:
<sql id="whereNameAndSexClause">
<if test="user !=null">
<if test="user.username != null and user.username !='' ">
and username like '%${user.username}%'
</if>
<if test="user.password != null and user.password != '' ">
and password= #{user.password}
</if>
</if>
</sql>
<!------------------------------------- 引入sql片段 --------------------------------------------->
<select id="findUserCount" parameterType="UserWapper" resultType="int">
select count(*) from user
<where>
<include refid="whereNameAndSexClause"></include>
</where>
</select>
========================================================================================================================================
4.关联映射查询
复杂查询时,单表对应的po类已不能满足输出结果集的映射。所以要根据需求建立一个扩展类来作为resultType的类型
一对一映射
例:现在要查看一个订单,订单里也要有用户的某些信息。就需要同时包含有user信息(用户)和order信息(订单)的OrdersExt扩展类。
domain/po/bean/源材料类:
Mapper映射文件:
Mapper接口:
直接就都出来了,或者不用 resultType 用 resultMap。
Mapper映射文件:
SQL没有变化,select属性里的resultType变成了resultMap,然后随便给resultMap里起个名,这里叫"ordersAndUserRstMap"
<resultMap>标签里的type是全限定类名,id就是刚才随便起的名
column 是对应数据库中表的字段名称
property 是对应的po类里面的属性名称
<association> 1对1关联映射
一对多映射
一对多查询和一对一查询的配置基本类似。只是如果使用resultMap的话,映射一对多关联关系要使用collection标签。
例:每个一级类目中有多个二级类目。需要category(一级类目)和categorySecond(二级类目),创建一个同时包含两者的CategoryAndSecondExt扩展类。
category: catrgorySecond:
CategoryAndSecondExt:一个一级类目包含多个二级类目集合
PS:这里我试过没用继承而直接将属性写在里面,但是映射失败我也不知道为什么
Mapper映射文件:
已经不是一对一的association而是一对多的collection了,别忘了接口;
多对多映射
例:Product商品类,Orders订单类,Orderitem订单项类,User用户类。
分析
User和Order:
user —— orders:一个用户可以创建多个订单,一对多
orders —— user:一个订单只由一个用户创建,一对一
orders和orderitem:
orders —— orderitem:一个订单可以包括多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderitem记录,一对多关系
orderitem —— orders:一个订单明细只能包括在一个订单中,一对一
orderitem和product:
orderitem —— product:一个订单明细只对应一个商品信息,一对一
product —— orderitem:一个商品可以包括在多个订单明细 ,一对多
Orders和product:
这两张表没有直接的外键关系,通过业务及数据库的间接关系分析出它们是多对多的关系。
orders —— orderitem —— product:一个订单可以有多个订单明细,一个订单明细对应一个商品,所以一个订单对应多个商品
product —— orderitem —— orders:一个商品可以对应多个订单明细,一个订单明细对应一个订单,所以一个商品对应多个订单
user和product:
这两张表没有直接的外键关系,通过业务及数据库的间接关系分析出它们是多对多的关系。
user —— orders —— orderitem —— product:一个用户有多个订单,一个订单有多个订单明细、一个订单明细对应一个商品,所以一个用户对应多个商品
Items —— orderitem —— orders —— user:一个商品对应多个订单明细,一个订单明细对应一个订单,一个订单对应一个用户,所以一个商品对应多个用户
这里不详细说类里的属性了,也不重要,下面说一下包装类,这里为了演示省事写一起了:
Mapper映射文件:
Mapper接口:
小结
实现一对一查询:
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列的别名,需要增加列名对应的属性,即可完成映射。如果没有查询结果的特殊要求建议使用resultType。这是一种平铺式的映射
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的对象属性中。这是一种层叠式的映射。
resultMap可以实现延迟加载,resultType无法实现延迟加载。