MyBatis
Mybatis 配置文件
模板
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--
mybatis 配置文件的主要的两个职责
1. 配置数据源
2. 管理映射文件
3. 设置类型别名
-->
<!-- 配置数据源 -->
<properties resource="jdbc.properties"></properties>
<settings>
<!-- 解决 查询 返回 Map 字段 值为 null 不显示 字段的问题 -->
<setting name="callSettersOnNulls" value="true"/>
<!-- 解决驼峰命名和 数据库蛇形命名相互转换的配置 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 设置类型别名 -->
<typeAliases>
<!-- <typeAlias type="com.subai.entity.User" alias="user" /> -->
<!--
如果 通过 package 设置别名,那么 别名的 名字 默认是 类名 (不区分大小写,推荐使用小写!)
-->
<package name="com.subai.entity" />
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--合理化配置 分页的参数 , 当页码小于等于0的时候,查询第一页, 当页码大于总页数的时候,查询最后一页 -->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--
如果使用 package 来管理映射文件, 那么需要满足两个要求
1. 映射文件 和 对应的 接口 名 保持一致
2. 映射文件 和 接口 需要在 同一个包下
如果 后期和 Spring 框架 进行整合, 就可以采用通配符的方式进行一次性的配置
-->
<package name="com.subai.mapper" />
<!-- 该方式只能应用于注解的开发 -->
<!--<mapper class="com.subai.mapper.RoleMapper" />-->
<!--<mapper resource="com/subai/mapper/UserMapper.xml" />-->
<!--<mapper resource="com/subai/mapper/GoodsMapper.xml" />-->
<!--<mapper resource="com/subai/mapper/OrderMapper.xml" />-->
<!--<mapper resource="com/subai/mapper/OrderGoodsMapper.xml" />-->
</mappers>
</configuration>
XML 映射器
- sql : 可被其它语句引用的可重用语句块
- insert : 映射插入语句
- update : 映射更新语句
- delete : 映射删除语句
- select : 映射查询语句
sql
- SQL片段 是通过 sql 标签定义的, 通过 include 标签 引入 对应的 SQL片段
<!-- 通过 sql 标签定义 -->
<sql id="columns">
id, username, password, create_time as createTime
</sql>
<!-- 通过 include 标签 引入 -->
<include refid="columns" />
insert
- 第一种 插入并获取主键
<insert id="save" parameterType="user" useGeneratedKeys="true" keyProperty="id">
insert into tb_user(username, password, create_time) values (#{username}, md5(#{password}), now())
</insert>
- 第二种 插入并获取主键
<insert id="save">
insert into tb_goods(goods_name, goods_price, create_time) values
(#{goodsName}, #{goodsPrice}, now())
<selectKey keyProperty="id" resultType="long" order="AFTER">
select last_insert_id()
</selectKey>
</insert>
update
<update id="update" parameterType="user">
update tb_user set
username = #{username} ,
password = md5(#{password}) ,
create_time = #{createTime} ,
update_time = now()
where id = #{id}
</update>
delete
<delete id="batchRemove">
delete from tb_user where id = #{id}
</delete>
select
- resultType 来定义返回的结果类型
<!-- resultType 设置的是查询单条记录的类型 -->
<select id="findUserById" resultType="user">
select id, username, password, create_time, update_time from tb_user where id = #{id}
</select>
- ResultMap 高级结果映射
- 允许用户 定义 查询的字段名 和 实体 属性的对应的关系
<resultMap id="userMap" type="user">
<!--
result 表示 结果集中的一个字段
column : 用来设置 查询的字段名
property : 是用来设置 type类型对应的属性名
javaType : 用来设置 属性的类型
jdbcType : 用来设置 数据库的类型
id 和 result的用法相同,标记 该映射的是一个主键
-->
<id column="id" property="id" />
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="time" property="createTime" />
</resultMap>
<select id="findUserByUsername" parameterType="string" resultMap="userMap">
<!--
如果 参数的类型是字面量类型 (8种基本数据类型+包装类 + String)
且 有且只有一个参数,那么 #{} 中的占位符,可以任意
如果 参数中使用了 @Param 注解,那么只能使用 注解中提供的值作为占位符
-->
select id, username, password, create_time as time from tb_user where username = #{username}
</select>
- ResultMap 高级结果映射 返回一个对象
<resultMap id="ogResultMap" type="orderGoods">
<id property="id" column="id" />
<result property="goodsId" column="goods_id"/>
<result property="goodsName" column="goods_name"/>
<result property="goodsPrice" column="goods_price"/>
<result property="goodsNum" column="goods_num"/>
<association property="order" javaType="order">
<id property="id" column="order_id" />
<result property="orderNum" column="order_num"/>
<result property="createTime" column="create_time"/>
<result property="status" column="status"/>
</association>
</resultMap>
<select id="findOrderGoodsByOrderIdOrOrderNum" resultMap="ogResultMap">
select g.id,
g.order_id,
g.goods_id,
g.goods_name,
g.goods_price,
g.goods_num,
t.order_num,
t.user_id,
t.create_time,
t.staus
from tb_order_goods g
right join tb_order t on t.id = g.order_id
<trim prefix="where" prefixOverrides="and |or ">
<choose>
<when test="orderNum != null">
and t.order_num = #{orderNum}
</when>
<when test="orderId != null">
and g.order_id = #{orderId}
</when>
</choose>
</trim>
</select>
- ResultMap 高级结果映射 返回一个集合
<resultMap id="resourceResultMap" type="Resource">
<id property="id" column="id"></id>
<result property="resourceName" column="resource_name"></result>
<result property="resourceDesc" column="resource_desc"></result>
<result property="star" column="star"></result>
<result property="createTime" column="create_time"></result>
<collection property="resourceCommentList" ofType="ResourceComment" >
<id property="id" column="res_id"></id>
<result property="userId" column="user_id"></result>
<result property="content" column="content"></result>
<result property="star" column="cstar"></result>
</collection>
</resultMap>
<select id="findResourceById" resultMap="resourceResultMap">
select r.id,
r.resource_name,
r.resource_desc,
r.star,
r.create_time,
c.res_id,
c.user_id,
c.content,
c.star cstar
from tb_resource r
join tb_resource_comment c
on r.id = c.res_id
where r.id = #{id}
</select>
动态 SQL
- if
<update id="update" parameterType="user">
update tb_user set
<if test="username!=null">
username = #{username} ,
</if>
<if test="password!=null">
password = md5(#{password}) ,
</if>
<if test="createTime!=null">
create_time = #{createTime} ,
</if>
update_time = now()
where id = #{id}
</update>
- choose、when、otherwise
<select id="findUser" resultType="user" parameterType="user">
select
id, username, password, create_time as createTime
from tb_user
<!-- where 标签主要适用于 条件的拼接,如果 条件中 多了 and , or , 那么会自动去掉 多余的 and , or -->
<where>
<choose>
<when test="id!=null">and id = #{id}</when>
<when test="username!=null">and username = #{username}</when>
<otherwise>and password = #{password}</otherwise>
</choose>
</where>
</select>
- trim、where、set
<select id="findOrderGoodsByOrderIdOrOrderNum" resultMap="ogResultMap">
select g.id,
g.order_id,
g.goods_id,
g.goods_name,
g.goods_price,
g.goods_num,
t.order_num,
t.user_id,
t.create_time,
t.staus
from tb_order_goods g
right join tb_order t on t.id = g.order_id
<trim prefix="where" prefixOverrides="and |or ">
<choose>
<when test="orderNum != null">
and t.order_num = #{orderNum}
</when>
<when test="orderId != null">
and g.order_id = #{orderId}
</when>
</choose>
</trim>
</select>
- foreach
<insert id="batchSave">
insert into tb_user(username, password, create_time) values
<!--
collection : 定义要遍历的数据
如果传入的参数类型是 List, 那么 collection中的值 写成 list
如果传入的参数类型是 数组 , 那么 collection中的值 写成 array
如果使用了 @Param 注解指定了名字,那么就使用指定的名字
item : 代表 遍历过程中 的 每一条数据 对应的变量, 变量名符合标识符命名规范即可
separator : 用来定义循环中 每一条数据的 分割符号
index : 用来标记该条记录的索引, 从 0 开始
nullable : 是否允许为空,
open : 整个 循环 以 ... 开始
close: 整个循环 以 ... 结尾
-->
<foreach collection="list" item="user" separator=",">
( #{user.username} , md5(#{user.password}) , now() )
</foreach>
</insert>
- bind
模糊查询 ,需要通过 concat 函数 拼接 % ,
在 MySQL数据库中,如果查询的条件 使用了 函数,那么 会导致索引失效
在 mybatis 中, 可以 通过 bind 标签, 来绑定变量 ,
name 是设置的变量名, value 是 要设置的变量值
<select id="findUserByLikeName" resultType="user">
<bind name="name" value="'%' + username + '%'" />
select id,username,password, create_time as createTime from tb_user
where username like #{name}
</select>
MyBatis 中 ${} 和 #{} 的区别
‘#{}’ 是一个占位符 ,主要应用于 SQL中 值 的占位, 在执行的时候,会被自定替换成 ? ,
在底层进行拼接的时候,会自动 在值的前后 添加引号,也可以对值进行转义, 可以用来防止SQL注入
‘${}’ 是一个占位符, 主要应用于 SQL中的 结构上(非值), 在执行的时候,不会被替换成 ?
会将值 原义 输出,作为SQL结构的一部分
‘${}’ 不能滥用,因为会产生SQL注入的风险, 能用 #{} 就绝对不要使用 ${} 进行占位
缓存
- 一级缓存默认开启 不可关闭
- 启用二级缓存 , 会对映射文件中所有的 select 添加缓存效果,
- insert, update, delete 会更新缓存
- 在 select 标签上 useCache 默认是 true , flushCache 默认是 false
- 在 insert , update, delete 标签上, useCache 默认是false, flushCache 默认是 true
- useCache , flushCache 要想生效,必须 启用 二级缓存