1、概述
mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis 通过xml 或注解的方式将要执行的各种statement 配置起来,并通过java 对象和statement 中sql的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql并将结果映射为 java 对象并返回。
采用 ORM 思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与 jdbc api打交道,就可以完成对数据库的持久化操作。
2、Mapper动态代理方式规范
- 映射配置文件存储的路径在resources里面,要和对应的Dao接口的路径保持一致
- 映射配置文件的文件名必须和Dao接口名保持一致
- 一定要引入约束文件
- namespace属性的值和对应Dao接口的全限定名一致
- 每一个子标签,就对应Dao接口中的一个方法
查询方法就对应select标签
添加方法就对应insert标签
删除方法就对应delete标签
修改方法就对应update标签 - 标签的id就对应方法的名字
- 标签的parameterType就对应方法的参数类型
- 标签的resultType(只有select标签才有)就对应方法的返回值类型,如果返回值类型是List,那么
resultType就是List的泛型类型
<?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.cyy.mapper.UserMapper">
<cache/>
<select id="findAll" resultType="user">
select * from t_user
</select>
</mapper>
3、核心配置文件详解
3.1、properties
用来引入properties配置文件,例如常见的数据库的配置文件。
<!--引入JDBC的配置文件-->
<properties resource="jdbc.properties"></properties>
3.2、typeAliases
类别名扫描,给类取别名
<!--别名表扫描-->
<typeAliases>
<package name="com.cyy.pojo"/>
<!-- <typeAlias type="com.cyy.pojo.User" alias="user"/>-->
</typeAliases>
package
使用package定义的别名:扫描给定name下所有类,别名就是pojo的类名,大小写都可以
typeAlias
给单个类取别名,type为类的全限定类名,alias为别名
3.3、environments
环境集合属性对象,里面可以配置多个environment
<!--配置连接数据库的环境 default:指定使用哪一个环境-->
<environments default="dev">
<environment id="dev">
<!--配置事务管理者,MyBatis事务用的是jdbc-->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接池, POOLED:使用连接池(mybatis内置的); UNPOOLED:不使用连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///demo"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
3.5、Mappers
映射配置
<!-- 配置映射文件-->
<mappers>
<!--<mapper resource="com/cyy/mapper/UserMapper.xml"/>-->
<package name="com/cyy/mapper"/>
</mappers>
mapper
配置单个映射文件,resource为映射配置文件地址,class为借口全限定类名
package
批量配置,配置该包下的所有映射配置文件
4、查询添加数据之后的自增长id
- SelectKey获取主键
属性 | 描述 |
---|---|
keyProperty | selectKey 语句结果应该被设置的目标属性。 |
resultType | 结果的类型。MyBatis 通常可以算出来,但是写上也没有问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。 |
order | 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素-这和如 Oracle 数据库相似,可以在插入语句中嵌入序列调用。 |
<!--parameterType属性: 参数的类型 ; 赋值的时候直接写对象里面的属性名-->
<insert id="save" parameterType="com.cyy.pojo.User">
<!--presultType: 主键类型; keyProperty:pojo里面对应的id的属性名; order属性: 指定是在目标的sql语句之前还是之后执行 -->
<selectKey resultType="int" keyProperty="uid" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO t_user(username,sex,birthday,address)VALUES(#{username},#{sex},#{birthday},#{address})
</insert>
4.1 #{}与${}的区别【面试】
- #{}一定不能写在引号里面,${}一定要写在引号里面
- 如果是pojo、map类型的参数,无论是#{}还是${}里面都是些属性名
- 如果是简单类型的参数,#{}里面可以写任意字符串,但是${}里面只能写value
- 如果使用#{}引入参数的话,其实是先使用?占位符,然后再设置参数;而使用${}引入参数的话,是直接拼接SQL语句
5、parameterType深入
5.1传递简单类型
基本的类型,字符串
直接写#{任意字符串}
或者'${value}'
5.2传递 pojo 对象 或者 Map
Mybatis 使用 ognl 表达式解析对象字段的值, #{}或者’${}'括号中的值为 pojo 属性名称或者Map的key。
5.3传递 pojo 包装对象类型
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。Pojo 类中包含 pojo。
6、resultType深入
6.1输出简单类型
直接写对应的Java类型. eg: 返回int
<select id="findCount" parameterType="int" resultType="int">
SELECT COUNT(*) FROM t_user
</select>
6.2输出pojo对象(一个pojo对象就对应一行数据)或者一个Map
直接写当前pojo类的全限定名 eg: 返回User
<select id="findByUid" parameterType="int" resultType="com.cyy.pojo.User">
select * from t_user where uid = #{uid}
</select>
6.3输出pojo列表(一个pojo列表就对应多行数据)或者Map的列表
直接写当前pojo类的全限定名 eg: 返回 List list;
<select id="findAll" resultType="com.cyy.pojo.User">
select * from t_user
</select>
6.4resultMap结果类型
resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
7、Mybatis 映射文件的 SQL 深入【重点】
7.1、动态 SQL 之if标签
我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。
<select id="findByAddressAndSex" resultType="LinkMan" parameterType="LinkMan">
select * from linkman where 1=1
<!--
判断,如果address不为空,则添加address的条件
如果sex不为空,则添加sex的条件
-->
<if test="address != null and address.length > 0">
and address=#{address}
</if>
<if test="sex != null and sex.length > 0">
and sex=#{sex}
</if>
</select>
7.2、动态 SQL 之where标签
为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。
<select id="findByAddressAndSex" resultType="LinkMan" parameterType="LinkMan">
select * from linkman
<!--
where标签的作用是,如果有if条件成立,则会在SQL语句中添加WHERE关键字
而且还会自动去掉第一个条件的and
-->
<where>
<!--
判断,如果address不为空,则添加address的条件
如果sex不为空,则添加sex的条件
-->
<if test="address != null and address.length > 0">
and address=#{address}
</if>
<if test="sex != null and sex.length > 0">
and sex=#{sex}
</if>
</where>
</select>
7.3、动态标签之foreach标签
遍历标签
<delete id="deleteByIds" parameterType="int">
delete from linkman
<!--
使用foreach标签进行遍历
collection属性就是要遍历的对象,如果要遍历的对象是一个集合,就写list
item属性就是遍历出来的每一个元素
index属性就是遍历出来的每一个元素的下标
separator属性就是分隔符
open属性 表示在遍历出来的第一个元素之前拼接字符串
close属性 表示在遍历出来的最后一个元素之后拼接字符串
-->
<foreach open="where id in(" close=")" collection="list" item="id" index="i" separator=",">
#{id}
</foreach>
</delete>
7.4、动态标签之Sql片段
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
<!--
使用sql标签定义SQL片段:
将当前映射配置文件中反复出现的SQL语句,定义成一个SQL片段,在需要使用的地方使用include标签引入即可
-->
<sql id="selectAll">
select id,name,sex,age,qq,email,address from linkman
</sql>
<select id="findById" parameterType="int" resultType="LinkMan">
<include refid="selectAll"></include>
where id=#{id}
</select>
8、Mybatis缓存
mybatis缓存分为:
-
一级缓存:它是sqlSession对象的缓存,自带的(不需要配置)不可卸载的(不想使用还不行). 一级缓存的生命周期与sqlSession一致。
-
二级缓存:它是SqlSessionFactory的缓存。只要是同一个SqlSessionFactory创建的SqlSession就共享二级缓存的内容,并且可以操作二级缓存。二级缓存如果要使用的话,需要我们自己手动开启(需要配置的)。
8.1、一级缓存
第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息。
如果 sqlSession 去执行 commit操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
8.2、二级缓存
二级缓存是SqlSessionFactory的缓存。只要是同一个SqlSessionFactory创建的SqlSession就共享二级缓存的内容,并且可以操作二级缓存.
-
在 SqlMapConfig.xml 文件开启二级缓存
<!--配置开启二级缓存--> <settings> <setting name="cacheEnabled" value="true"/> </settings>
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为 false 代表不开启二级缓存。
- 配置相关的 Mapper 映射文件
<cache>
标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值 - 要进行二级缓存的POJO类必须实现Serializable接口
9、Mybatis 的多表关联查询【重点】
9.1、一(多)对一(association )
<resultMap id="accountUserMap" type="Account">
<id column="aid" property="aid"></id>
<result column="money" property="money"></result>
<result column="uid" property="uid"></result>
<!--
要进行一对一的映射配置
property表示要映射的pojo的属性名
javaType表示要进行映射的POJO的属性的类型
-->
<association property="user" javaType="User">
<result column="uid" property="uid"></result>
<result column="username" property="username"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
<result column="address" property="address"></result>
</association>
</resultMap>
9.2、一对多(collection )
<resultMap id="userAccountMap" type="User">
<id column="uid" property="uid"></id>
<result column="address" property="address"></result>
<result column="username" property="username"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
<!--
使用collection标签进行一对多映射
-->
<collection property="accountList" ofType="Account">
<result column="aid" property="aid"></result>
<result column="money" property="money"></result>
<result column="uid" property="uid"></result>
</collection>
</resultMap>
9.3、多对多(collection )
多对多可以拆分为两个一对多
<resultMap id="userRoleMap" type="User">
<!--能够一一对应的属性,我不写-->
<id column="uid" property="uid"></id>
<result column="address" property="address"></result>
<result column="username" property="username"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
<collection property="roleList" ofType="Role">
<result property="rid" column="rid"></result>
<result property="rName" column="rName"></result>
<result property="rDesc" column="rDesc"></result>
</collection>
</resultMap>
9.4、总结
- 以哪张表作为主体查询,那么就将查询到的结果封装到哪张表对应的POJO对象中
- 如果表的关系是一对一,那么就在一个POJO中添加另外一个POJO的对象属性
- 如果表的关系是一对多,那么就在一个POJO中添加另外一个POJO的集合属性
- 使用association标签可以进行一对一的映射
- 使用collection标签可以进行一对多的映射
10、Mybatis 延迟加载策略【重点】
延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
坏处: 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
好处: 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快.
<!--
一对一映射
select属性表示调用其它的select标签
column属性表示往要调用的其它的select标签中传入参数
fetchType="lazy"表示延迟加载(局部配置,只有配置了这个的地方才会延迟加载)
-->
<association property="user"
javaType="User"
column="uid"
select="com.itheima.dao.UserDao.findUserByUid"
fetchType="lazy">
</association>
总结
类别 | 特点 |
---|---|
立即加载 | 只要一调用方法,则马上发起查询 |
延迟加载 | 只有在真正使用时,才发起查询,如果不用,则不查询。 |