Mybatis学习笔记
Mybatis学习
概念了解
一个基于ORM的轻量级半自动持久层框架
- orm
- Objcet/Relation Mapping 对象关系映射
- 把关系数据库包装成面向对象的模型
- 实现效果:把对持久化对象的保存、修改、删除等操作,准换为数据库的操作
- 轻量级
- 占用资源少
- 半自动
- 相对于hibernate的全自动,Mybatis需要自己编写sql文件
- 持久层
- 什么意思,不知道
Mapper接口开发遵循规范
- Mapper.xml文件的nameSpace与mapper接口的全限定名相同
- Mapper接口方法名和mapper.xml中定义的每个statement的id相同
- 接口输入参数类型和parameterType类型相同
- 接口输出参数类型和resultType类型相同
Mybatis四大组件
- Executor
- StatementHandler
- ParameterHandler
- ResultSetHanler
配置文件解析
Properties
额外配置信息
<!--加载外部properties文件-->
<properties resource="jdbc.properties"> </properties>
properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///zdy_mybatis
jdbc.username=root
jdbc.password=root
typeAliases
类型别名
<!--给实体类的全限定类名给别名-->
<typeAliases>
<!--<typeAlias type="com.lagou.pojo.User" alias="User"></typeAlias>-->
<!--常用包装类mybatis已经起好别名-->
<!--批量起别名: 该包下所有的类的类名:别名不区分大小写-->
<package name="com.lagou.pojo"/>
</typeAliases>
mybatis已经为一些常用类型起了别名
| 别名 | 数据类型 |
|---|---|
| string | String |
| long | Long |
| int | Integer |
| double | Double |
| boolean | Boolean |
environments
数据库环境配置
<!--运行环境-->
<environments default="development">
<environment id="development">
<!--当前事务交由JDBC管理-->
<transactionManager type="JDBC"/>
<!--当前使用mybatis提供的连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
mapper
加载映射文件
<mappers>
<!-- 加载单个映射配置文件 -->
<mapper resource="com/lagou/mapper/UserMapper.xml"/>
<!-- 加载该包下的全部配置文件 -->
<!--要保证同包同名-->
<!-- com.lagou.dao.OrderMapper.java 对应 com.lagou.dao.OrderMapper.xml -->
<package name="com.lagou.dao"/>
</mappers>
动态sql
if
根据实体类取值,使用不同SQL语句进行查询
<select id="findByCondition" parameterType="user" resultType="user">
select * from User
<where>
<if test="id!=0">and id=#{id}</if>
<if test="username!=null">and username=#{username}</if>
</where>
</select>
foreach
循环执行sql的拼接操作
<select id="findByIds" parameterType="list" resultType="User">
<include refid="selectUser"></include>
<where>
<foreach collection="array" separator="," open="id in (" close=")" item="id">
#{id}
</foreach>
</where>
</select>
标签属性:
- collection 代表要遍历的元素,分三种情况, array(array), list(list), map 需要的value对应的key(key值 )
- open 代表语句的开头
- close 结束部分
- item 遍历的每个元素,生成的变量名
- sperator 分割符
SQL片段抽取
抽取重复sql语句,使用include引用,达到sql复用
<sql id="selectUser">
select *
from user
</sql>
<select id="findAll" resultType="user">
<include refid="selectUser"></include>
</select>
复杂映射开发
一对一
方式一: 通过association
<resultMap id="OrderAndOrder" type="Order">
<result column="id" property="id"></result>
<result column="ordertime" property="orderTime"></result>
<result column="total" property="total"></result>
<result column="uid" property="uid"></result>
<association property="user" javaType="User">
<result column="uid" property="id"></result>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
方式二: 通过 .
<resultMap id="orderMap" type="com.lagou.pojo.Order">
<!--字段名和属性名相同的可以不写,任然可以赋值-->
<result column="uid" property="user.id"></result>
<result column="username" property="user.username"></result>
<result column="password" property="user.password"></result>
<result column="birthday" property="user.birthday"></result>
</resultMap>
一对多
collection 标签,配置一对多
<resultMap id="UserMap" type="com.lagou.pojo.User">
<result property="id" column="uid"></result>
<result property="username" column="username"></result>
<collection property="orderList" ofType="com.lagou.pojo.Order">
<result property="id" column="oid"></result>
<result property="orderTime" column="ordertime"></result>
<result property="total" column="total"></result>
</collection>
</resultMap>
缓存
一级缓存是SqlSession级别的缓存,不同sqlSession之间的缓存数据区域(是相互不影响的
二级缓存是mapper级别的缓存, 多个sqlSession可以共用二级缓存,二级缓存跨SqlSession
一级缓存
一级缓存默认开启
二级缓存
二级缓存需要手动开启
开始方式:
mybatis配置文件
<!-- 开启二级缓存-->
<settings>
<!--默认值为true -->
<setting name="cacheEnabled" value="true"/>
</settings>
具体的mapper配置文件
<!--标识 这个namespace开启二级缓存 -->
<cache></cache>
二级缓存整合redis
Sql标签中的缓存配置
flushCache 是否刷新缓存
useCache 是否使用缓存
<!--flushCache 默认true, 刷新缓存-->
<!--useCache=false 禁用缓存,避免脏读,直接从数据库获取 -->
<select id="select" resultType="com.lagou.pojo.User" flushCache="false" useCache="false">
select *
from user
</select>
Mybatis插件
对mybatis来说,插件就是拦截器, 用来增强核心对象的功能, 借助底层的动态代理实现
自定义插件
实例实现:
实现Interceptor接口
/**
* 自定义插件
* @author fjhua
* @create 2021-04-18 22:01
*/
@Intercepts({
@Signature(type = StatementHandler.class, //拦截的目标对象
method = "prepare", //拦截的目标方法
args = {Connection.class, Integer.class}) // 拦截目标方法的参数
})
public class MyPlugin implements Interceptor {
/**
* 拦截方法: 只要被拦截的目标对象的目标方法被执行时, 每次都会执行intercept方法
* @param invocation 拦截的方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("对方法增强");
return invocation.proceed();
}
/**
* 主要是为了把当前的拦截器生成的代理存到拦截器链中
* @param target
* @return
*/
@Override
public Object plugin(Object target) {
Object wrap = Plugin.wrap(target, this);
return wrap;
}
/**
* 获取配置文件参数
* @param properties 配置文件中 property 的键和值
*/
@Override
public void setProperties(Properties properties) {
System.out.println("获取到的配置文件参数: " + properties);
// 日志打印: 获取到的配置文件参数: {name=tom}
}
}
配置文件注册插件
<!--注意该标签的位置, 需要在typeAliases标签之后 -->
<plugins>
<plugin interceptor="com.lagou.config.MyPlugin">
<property name="name" value="tom"/>
</plugin>
</plugins>
pageHelper
通用mapper
延迟加载
基于嵌套查询实现延迟加载
优缺点
选择策略
实现/局部延迟/全局延迟
实现原理
延迟加载配置的标签和属性
sql是否延迟加载各种策略的执行(源码剖析)
相关设计模式
P79
构建者模式
使用多个简单的对象一步一步构建成一个复杂的对象
工厂模式
简单工厂模式
接口和具体产品
public abstract class Book {
public void read() {
System.out.println("开始读书");
}
}
class MathBook extends Book {
@Override
public void read() {
super.read();
System.out.println("读数学书");
}
}
class ChineseBook extends Book {
@Override
public void read() {
super.read();
System.out.println("读语文书");
}
}
工厂类及测试
public class BookFactory {
public static Book build(String bookType) {
Book book = null;
switch (bookType) {
case "math":
book = new MathBook();
break;
case "chinese":
book = new ChineseBook();
break;
}
return book;
}
public static void main(String[] args) {
Book book = BookFactory.build("math");
book.read();
}
/**
* 开始读书
* 读数学书
*/
}
代理模式
接口
public interface Book {
void read();
}
实现类
public class MathBook implements Book {
@Override
public void read() {
System.out.println("读数学书");
}
}
代理
public class BookProxy implements InvocationHandler {
private Book book;
public BookProxy(Book book) {
this.book = book;
}
public Book getProxyBook() {
Object proxyInstance = Proxy.newProxyInstance(book.getClass().getClassLoader(), book.getClass().getInterfaces(), this);
return (Book) proxyInstance;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法增强");
Object invoke = method.invoke(book, args);
System.out.println("方法后置增强");
return invoke;
}
}
测试
class TestBook {
public static void main(String[] args) {
MathBook mathBook = new MathBook();
mathBook.read();
System.out.println("===========");
Book proxyBook = new BookProxy(new MathBook()).getProxyBook();
proxyBook.read();
}
/**
* 读数学书
* ===========
* 方法增强
* 读数学书
* 方法后置增强
*/
}

浙公网安备 33010602011771号