配置文件和映射文件还有挺多的属性我还没有讲的, 现在就把它们一一补全
映射文件
在 mapper.xml 文件中配置很多的 sql 语句, 执行每个 sql 语句时, 封装为 MappedStatement 对象, mapper.xml 以 statement 为单位管理 sql 语句
Statement 的实际位置就等于 namespace+StatementId
占位符
在 Mybatis 中, 有两种占位符
#{} 解析传递进来的参数数据
${} 对传递进来的参数原样拼接在 SQL 中
主键生成策略
如果我们在 Hibernate 中, 当我们插入数据的时候, 我们是可以选择是 UUID 策略的...
那么在 Mybatis 是怎么做的呢??
- UUID
- <!-- mysql 的 uuid 生成主键 -->
- <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
- <selectKey keyProperty="id" order="BEFORE" resultType="string">
- select uuid()
- </selectKey>
- INSERT INTO USER(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address})
- </insert>
主键返回
如果我们一般插入数据的话, 如果我们想要知道刚刚插入的数据的主键是多少, 我们可以通过以下的方式来获取
需求:
user 对象插入到数据库后, 新记录的主键要通过 user 对象返回, 通过 user 获取主键值
解决思路:
通过 LAST_INSERT_ID() 获取刚插入记录的自增主键值, 在 insert 语句执行后, 执行 select LAST_INSERT_ID() 就可以获取自增主键
- mysql:
- <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
- <selectKey keyProperty="id" order="AFTER" resultType="int">
- select LAST_INSERT_ID()
- </selectKey>
- INSERT INTO USER(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address})
- </insert>
- oracle:
实现思路:
先查询序列得到主键, 将主键设置到 user 对象中, 将 user 对象插入数据库
- <!-- oracle
- 在执行 insert 之前执行 select 序列. nextval() from dual 取出序列最大值, 将值设置到 user 对象 的 id 属性
- -->
- <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
- <selectKey keyProperty="id" order="BEFORE" resultType="int">
select 序列. nextval() from dual
- </selectKey>
- INSERT INTO USER(id,username,birthday,sex,address) VALUES( 序列. nextval(),#{username},#{birthday},#{sex},#{address})
- </insert>
- resultMap
有的时候, 我们看别的映射文件, 可能看不到以下这么一段代码:
- <resultMap id="userListResultMap" type="user">
- <!-- 列名
- id_,username_,birthday_
- id: 要映射结果集的唯 一标识 , 称为主键
- column: 结果集的列名
- property:type 指定的哪个属性中
- -->
- <id column="id_" property="id"/>
- <!-- result 就是普通列的映射配置 -->
- <result column="username_" property="username"/>
- <result column="birthday_" property="birthday"/>
- </resultMap>
因为, 如果我们的数据表的字段和 JavaBean 的属性名称是相同时, 我们就不用上面那段代码了 Mybatis 会自动帮我们把返回的结果进行封装成 JavaBean
那当我们数据表的字段和 JavaBean 的属性名称不是相同时, 我们就需要使用 resultMap, 也就是上面那段代码
当然了, 在正常情况下列名和 JavaBean 的属性名一般都是不同的, 因此还是需要 resultMap 的
resultMap 和 resultType 区别
resultType : 指定输出结果的类型 (pojo 简单类型 hashmap..), 将 sql 查询结果映射为 java 对象
使用 resultType 注意: sql 查询的列名要和 resultType 指定 pojo 的属性名相同, 指定相同 属性方可映射成功, 如果 sql 查询的列名要和 resultType 指定 pojo 的属性名全部不相同, list 中无法创建 pojo 对象的
resultMap: 将 sql 查询结果映射为 java 对象
如果 sql 查询列名和最终要映射的 pojo 的属性名不一致 **, 使用 resultMap 将列名和 pojo 的属性名做一个对应关系 (列名和属性名映射配置)**
使用 resultMap
- <resultMap id="userListResultMap" type="user">
- <!-- 列名
- id_,username_,birthday_
- id: 要映射结果集的唯 一标识 , 称为主键
- column: 结果集的列名
- property:type 指定的哪个属性中
- -->
- <id column="id_" property="id"/>
- <!-- result 就是普通列的映射配置 -->
- <result column="username_" property="username"/>
- <result column="birthday_" property="birthday"/>
- </resultMap>
resultType 和 resultMap 用法总结
resultType:
作用:
将查询结果按照 sql 列名 pojo 属性名一致性映射到 pojo 中
场合:
常见一些明细记录的展示, 将关联查询信息全部展示在页面时, 此时可直接使用 resultType 将每一条记录映射到 pojo 中, 在前端页面遍历 list(list 中是 pojo) 即可
resultMap:
使用 association 和 collection 完成一对一和一对多高级映射
association:
作用:
将关联查询信息映射到一个 pojo 类中
场合:
为了方便获取关联信息可以使用 association 将关联订单映射为 pojo, 比如: 查询订单及关联用户信息
collection:
作用:
将关联查询信息映射到一个 list 集合中
场合:
为了方便获取关联信息可以使用 collection 将关联信息映射到 list 集合中, 比如: 查询用户权限范围模块和功能, 可使用 collection 将模块和功能列表映射到 list 中
Collection 在前面好像并没有用过, 下面就看一下它的用法:
Order 与 OrderDetails 关系
- package cn.itcast.mybatis.po;
- import java.io.Serializable;
- import java.util.Date;
- import java.util.List;
- public class Orders implements Serializable {
- private Integer id;
- private Integer userId;
- private String number;
- private Date createtime;
- private String note;
- // 关联用户信息
- private User user;
- // 订单明细
- private List<Orderdetail> orderdetails;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public Integer getUserId() {
- return userId;
- }
- public void setUserId(Integer userId) {
- this.userId = userId;
- }
- public String getNumber() {
- return number;
- }
- public void setNumber(String number) {
- this.number = number == null ? null : number.trim();
- }
- public Date getCreatetime() {
- return createtime;
- }
- public void setCreatetime(Date createtime) {
- this.createtime = createtime;
- }
- public String getNote() {
- return note;
- }
- public void setNote(String note) {
- this.note = note == null ? null : note.trim();
- }
- public User getUser() {
- return user;
- }
- public void setUser(User user) {
- this.user = user;
- }
- public List<Orderdetail> getOrderdetails() {
- return orderdetails;
- }
- public void setOrderdetails(List<Orderdetail> orderdetails) {
- this.orderdetails = orderdetails;
- }
- }
SQL 语句
- <!-- 一对多查询使用 reusltMap 完成
- 查询订单关联查询订单明细
- -->
- <select id="findOrderAndOrderDetails" resultMap="orderAndOrderDetails">
- SELECT
- orders.*,
- user.username,
- user.sex ,
- orderdetail.id orderdetail_id,
- orderdetail.items_num,
- orderdetail.items_id
- FROM
- orders,
- USER,
- orderdetail
- WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id
- </select>
- resultMap
- <!-- 一对多, 查询订单及订单明细 -->
- <resultMap type="orders" id="orderAndOrderDetails" extends="ordersUserResultMap">
- <!-- 映射订单信息, 和用户信息, 这里使用继承 ordersUserResultMap -->
- <!-- 映射订单明细信息
- property: 要将关联信息映射到 orders 的哪个属性中
- ofType: 集合中 pojo 的类型
- -->
- <collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
- <!-- id: 关联信息订单明细的唯 一标识
- property:Orderdetail 的属性名
- -->
- <id column="orderdetail_id" property="id"/>
- <result column="items_num" property="itemsNum"/>
- <result column="items_id" property="itemsId"/>
- </collection>
- </resultMap>
一般地使用 resultMap 会多一点
Mybatis 映射文件处理特殊字符
第一种方法:
用了转义字符把 > 和 < 替换掉, 然后就没有问题了
SELECT * FROM test WHERE 1 = 1 AND start_date <= CURRENT_DATE AND end_date>= CURRENT_DATE
第二种方法:
<![CDATA[ ]]>
配置文件
别名
typeAliases 别名:
自定义别名:
- <!-- 定义 别名 -->
- <typeAliases>
- <!--
- 单个别名的定义
- alias: 别名, type: 别名映射的类型 -->
- <!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> -->
- <!-- 批量别名定义
- 指定包路径, 自动扫描包下边的 pojo, 定义别名, 别名默认为类名 (首字母小写或大写)
- -->
- <package name="cn.itcast.mybatis.po"/>
- </typeAliases>
Mapper 加载
- <mappers>
- <!-- 通过 resource 引用 mapper 的映射文件 -->
- <mapper resource="sqlmap/User.xml" />
- <!-- <mapper resource="mapper/UserMapper.xml" /> -->
- <!-- 通过 class 引用 mapper 接口
- class: 配置 mapper 接口全限定名
- 要求: 需要 mapper.xml 和 mapper.java 同名并且在一个目录 中
- -->
- <!-- <mapper class="cn.itcast.mybatis.mapper.UserMapper"/> -->
- <!-- 批量 mapper 配置
- 通过 package 进行自动扫描包下边的 mapper 接口,
- 要求: 需要 mapper.xml 和 mapper.java 同名并且在一个目录 中
- -->
- <package name="cn.itcast.mybatis.mapper"/>
- </mappers>
延迟加载
在进行数据查询时, 为了提高数据库查询性能, 尽量使用单表查询, 因为单表查询比多表关联查询速度要快
如果查询单表就可以满足需求, 一开始先查询单表, 当需要关联信息时, 再关联查询, 当需要关联信息再查询这个叫延迟加载
在 Mybatis 中延迟加载就是在 resultMap 中配置具体的延迟加载..
在 Mybatis 的文件中配置全局延迟加载
- <!-- 全局配置参数 -->
- <settings>
- <!-- 延迟加载总开关 -->
- <setting name="lazyLoadingEnabled" value="true" />
- <!-- 设置按需加载 -->
- <setting name="aggressiveLazyLoading" value="false" />
- </settings>
延迟加载测试
当需要用户时调用 Orders 类中的 getUser() 方法执行延迟加载 , 向数据库发出 sql
由于是对 User 进行延迟加载, 那么我们只要查询 Orders 相关的信息即可了
- <!-- 一对一查询延迟加载
- 开始只查询订单, 对用户信息进行延迟加载
- -->
- <select id="findOrderUserListLazyLoading" resultMap="orderCustomLazyLoading">
- SELECT
- orders.*
- FROM
- orders
- </select>
使用 resultMap 来配置延迟加载
- <!-- 一对一查询延迟加载 的配置 -->
- <resultMap type="orders" id="orderCustomLazyLoading">
- <!-- 完成了订单信息的映射配置 -->
- <!-- id: 订单关联用户查询的唯 一 标识 -->
- <id column="id" property="id" />
- <result column="user_id" property="userId" />
- <result column="number" property="number" />
- <result column="createtime" property="createtime" />
- <result column="note" property="note" />
- <!--
- 配置用户信息的延迟加载
- select: 延迟加载执行的 sql 所在的 statement 的 id, 如果不在同一个 namespace 需要加 namespace
- sql: 根据用户 id 查询用户信息 column 就是参数
- column: 关联查询的列
- property: 将关联查询的用户信息设置到 Orders 的哪个属性 -->
- <!-- 当需要 user 数据的时候, 它就会把 column 所指定的 user_id 传递过去给 cn.itcast.mybatis.mapper.UserMapper.findUserById 作为参数来查询数据 -->
- <association property="user"
- select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id"></association>
- </resultMap>
总结
在程序中调用的 SQL 语句是由映射文件的命令空间 + sql 片段的 id 所组成的它内部会生成一个 Statement 对象的
在使用别名的时候, 可以指定包名, 在使用总配置文件加载映射文件时, 也可以指定包名
主键如果需要返回的话, 使用 selectKey 标签即可 UUID 也可以返回在 Oracle 的话, 是使用序列来返回自动增长的主键的
占位符有两种, 一种是解析传递进来的参数数据一种是原样输出传递进来的数据
来源: https://juejin.im/post/5aa62bd4f265da239866e82c