目录
一、缓存 Cache
1.MyBatis缓存分类
2.一级缓存
3.二级缓存
二级缓存分开关的设置
4.第三方自定义缓存:整合Ehcache
Ehcache的配置项(了解)
二、日志框架
三、缓存源码 (装饰模式)
1.Cache相关的API
2.一级Cache的源码
3.二级Cache的源码
四、逆向工程(了解)
QBC(了解)
五、其他
1.Mapper映射、实体类别名
2.插件机制(了解)
3.类型处理器typeHandler(了解)
六、MBatis底层对JDBC的封装
1.Mbatis底层四大对象:
2.Mybatis底层四大步骤:
七、Mybatis大总结
一、缓存 Cache
缓存:存在内存中的临时数据
使用缓存可以减少对硬盘(数据库)的访问次数(IO操作),提高查询效率,减少系统开销,解决了高并发系统的性能问题。
1.MyBatis缓存分类
一级缓存:自动开启,默认开启,针对同一个SqlSessio (不同的SqlSession有不同的一级缓存)
二级缓存:手动开启,默认关闭,针对同一个SqlSessioinFactory (由这一个SqlSessionFactory) 创建的所有SqlSession可以共享二级缓存中的数据)。
缓存命中率 = 命中缓存的次数/查询的总次数
查询的顺序是:
- 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
- 如果二级缓存没有命中,再查询一级缓存
- 如果一级缓存也没有命中,则查询数据库
- 查询数据库的结果,会立刻放入一级缓存 (不会立刻放入二级缓存)
- SqlSession关闭之前,一级缓存中的数据会写入二级缓存
2.一级缓存
一级缓存失效的情况
- 不是同一个SqlSession
- 同一个SqlSession但是查询条件发生了变化
- 同一个SqlSession两次查询期间执行了任何一次增删改操作 (清空、刷新一级缓存)
- 同一个SqlSession两次查询期间手动清空了缓存
- 同一个SqlSession两次查询期间提交了事务
3.二级缓存
结论:SqlSession关闭的时候,一级缓存中的内容会被存入二级缓存
1.全局开关:默认开启
2.局部开关:二级缓存以namespace为单位。
SELECT emp_id empId ,emp_name empName,emp_salary empSalary FROM t_emp WHERe emp_id = #{empId}
3.实体类要序列化
什么时候需要序列化:在在内存中存储不需要序列化,如果内存的数据要存入硬盘,或者在网络上传输,就要序列化(其实是变成字节数组)
一级缓存肯定在内存中,二级缓存可能在内存中,但是二级缓存数据多,也可以存储到外存中,所以存在二级缓存中的数据必须序列化。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee implements Serializable {
private Integer empId;
private String empName;
private Double empSalary;
}
4.测试
运行之前访问一级缓存的代码,发现已经查询二级缓存,但是在二级缓存中一次也没有发现数据
一级缓存的数据,何时放入二级缓存:
SqlSession关闭的时候,一级缓存中的内容会被存入二级缓存
//二级缓存
@Test
public void testCache2(){
//创建SqlSession1
SqlSession sqlSession1 = factory.openSession();
EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
Employee emp1 = mapper1.findById(21);
System.out.println(emp1);
sqlSession1.close(); //关闭了sqlSession,存入二级缓存
//创建SqlSession2
SqlSession sqlSession2 = factory.openSession();
EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);
Employee emp2 = mapper2.findById(2);
System.out.println(emp2);
}
二级缓存分开关的设置
- Type:指定具体的二级缓存类型。如果不指定,就使用MyBatis自带的二级缓存。
- Size:代表缓存最多可以存储多少个对象,太大容易导致内存溢出
- flushInterval:刷新(清空缓存)间隔。默认情况是不设置,也就是没有刷新间隔
- readOnly:只读。True:性能高 false,性能低,安全性高
- Eviction:缓存清除策略。比如二级缓存中最多放100个缓存内容,第101来了,怎么办?
- LRU – 最近最少使用(默认):移除最长时间不被使用的对象 (Least Recently Used )
- FIFO – 先进先出:按对象进入缓存的顺序来移除它们。(First in First out)
- Blocking 阻塞:访问某个缓存数据,在访问过程中对key(sql语句)加锁,其他的请求同一个SQL语句,要等待。保证了只有一个请求来访问缓存中的一份数据。
4.第三方自定义缓存:整合Ehcache
Ehcache是一种开源的、缓存的技术。整合Ehcache,就是使用Ehcache做MyBatis的二级缓存
①添加依赖
org.mybatis.caches mybatis-ehcache1.2.1
②整合EHCache
在resources下创建配置文件:ehcache.xml。文件内容:
③加入log4j适配器依赖
存在SLF4J时,是无法直接访问log4j的,需要加入一个适配器类:slf4j-log4j12。
因为log4j不是slf4j的直接实现
org.slf4j slf4j-log4j121.7.30 test
④mapper.xml 指明二级缓存使用Ehcache
⑤测试查看结果
使用了Ehcache的效果:
Ehcache的配置项(了解)
| 属性名 | 是否必须 | 作用 |
|---|---|---|
| maxElementsInMemory | 是 | 在内存中缓存的element的最大数目 |
| maxElementsOnDisk | 是 | 在磁盘上缓存的element的最大数目,若是0表示无穷大 |
| eternal | 是 | 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断 |
| overflowToDisk | 是 | 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 |
| timeToIdleSeconds | 否 | 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大 |
| timeToLiveSeconds | 否 | 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 |
| diskSpoolBufferSizeMB | 否 | DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 |
| diskPersistent | 否 | 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 |
| diskExpiryThreadIntervalSeconds | 否 | 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s, 相应的线程会进行一次EhCache中数据的清理工作 |
| memoryStoreEvictionPolicy | 否 | 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) |
二、日志框架
① 日志框架选择
情况1:如果开发项目中已经确定采用哪种具体日志系统,直接使用即可(不引入SLF4J等抽象的日志门面)。
- log4j:日志框架的鼻祖,作者Ceki Gülcü将其捐献给Apache开源,吸引了无数的人无偿帮助测试它,扩展它,改进它,很快就成了最流行的日志工具。
- JDK logging:从JDK1.4开始,JDK中提供了java.util.logging包,也来记录日志。这可是官网日志包,而不是第三方日志包,但是已经无法撼动log4j了。
- log4j2:2015年9月,Apache软件基金业宣布,Log4j不在维护,建议所有相关项目升级到Log4j2。log4j2性能优异。但内部实现和log4j完全不同
情况2:如果开发项目中无法确定采用哪种具体的日志系统,使用SLF4J等日志门面,也要引入一种具体的日志框架。引入一个抽象的日志框架:SLF4j
- SLF4j:由log4j的作者设计完成的,简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,而是通过Facade Pattern提供一些Java logging API,它只服务于各种各样的日志系统。按照官方的说法,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统。作者创建SLF4J的目的是为了替代Jakarta Commons-Logging。
- Jakarta Commons-Logging,现在叫Apache Commons-Logging,也是一个日志门面,希望解决的问题和Slf4j类似。common-logging通过动态查找的机制,在程序运行时自动找出真正使用的日志库; slf4j在编译时静态绑定真正的Log库。
- logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,并给出了slf4j的原生实现(即直接实现了slf4j的接口,而log4j因为出现早于slf4j,并没有直接实现,就需要一个适配器slf4j-log4j12.jar)。
② 日志框架类型
门面:
| 名称 | 说明 |
|---|---|
| JCL(Jakarta Commons Logging) | 陈旧 |
| SLF4J(Simple Logging Facade for Java)★ | 适合 |
| jboss-logging | 特殊专业领域使用 |
实现:★表示同一个作者
| 名称 | 说明 |
|---|---|
| log4j★ | 最初版 |
| JUL(java.util.logging) | JDK自带 |
| log4j2 | Apache收购log4j后全面重构,内部实现和log4j完全不同 |
| logback★ | 优雅、强大 |
③ logback的使用
[1] 依赖信息
ch.qos.logback logback-classic1.2.3
[2] 配置信息
[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n
如果有过个日志框架,哪个依赖在前,就启用哪个。
logback:时间在前
三、缓存源码 (装饰模式)
设计模式:装饰模式 :动态组装
蛋糕接口:(Cache接口)
蛋糕实现类:奶油蛋糕 冰激凌蛋糕(PerpetualCache EhcacheCache)
蛋糕的装饰:卡片、干果、蜡烛(FifoCache、LruCache是添加了装饰的蛋糕)
如果采用继承,就会数不清的实现类。采用装饰模式,可以减少子类的数量,是继承的一种替代方案。现场组装。
蛋糕接口:(InputStream抽象类)
蛋糕实现类:奶油蛋糕 冰激凌蛋糕(FileInputStream ByteArrayInputStream)
蛋糕的装饰:卡片、干果、蜡烛(BufferedInputStream DataInputStream)
1.Cache相关的API
设计模式:装饰模式 :动态组装
蛋糕接口:(Cache接口)
蛋糕实现类:奶油蛋糕 冰激凌蛋糕(PerpetualCache EhcacheCache)
蛋糕的装饰:卡片、干果、蜡烛(FifoCache、LruCache是添加了装饰的蛋糕)
如果采用继承,就会数不清的实现类。采用装饰模式,可以减少子类的数量,是继承的一种替代方案。现场组装。
蛋糕接口:(InputStream抽象类)
蛋糕实现类:奶油蛋糕 冰激凌蛋糕(FileInputStream ByteArrayInputStream)
蛋糕的装饰:卡片、干果、蜡烛(BufferedInputStream DataInputStream)
Cache内部有一个Map,存储缓存的信息
所有的装饰类中必须有一个Cache的引用,说明对谁进行装饰。(类似包装流内的节点流)
PerpetualCache 是Mybatis的默认缓存,也是Cache接口的默认实现。Mybatis一级缓存和自带的二级缓存都是通过 PerpetualCache 来操作缓存数据的。
PerpetualCache 如何区分不同级别的缓存:根据调用者不同
- 一级缓存:由BaseExecutor调用PerpetualCache
- 二级缓存:由CachingExecutor调用PerpetualCache,而CachingExecutor可以看做是对BaseExecutor的装饰
2.一级Cache的源码
3.二级Cache的源码
底层使用Ehcache
底层使用自带的二级缓存
底层不使用二级缓存:会调用一级缓存
四、逆向工程(了解)
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成Java实体、Mapper接口、Mapper配置文件
添加插件
org.mybatis.generator mybatis-generator-maven-plugin1.3.0 org.mybatis.generator mybatis-generator-core1.3.2 com.mchange c3p00.9.2 mysql mysql-connector-java8.0.26
2.添加、修改配置文件 generatorConfig.xml
进行测试
QBC(了解)
QBC:Query By Criteria 查询标准
QBC查询最大的特点就是将SQL语句中的WHERe子句进行了组件化的封装,让我们可以通过调用Criteria对象的方法自由的拼装查询条件。
// 1.创建EmployeeExample对象
EmployeeExample example = new EmployeeExample();
// 2.通过example对象创建Criteria对象
EmployeeExample.Criteria criteria01 = example.createCriteria();
EmployeeExample.Criteria criteria02 = example.or();
// 3.在Criteria对象中封装查询条件
criteria01
.andEmpAgeBetween(9, 99)
.andEmpNameLike("%o%")
.andEmpGenderEqualTo("male")
.andEmpSalaryGreaterThan(500.55);
criteria02
.andEmpAgeBetween(9, 99)
.andEmpNameLike("%o%")
.andEmpGenderEqualTo("male")
.andEmpSalaryGreaterThan(500.55);
SqlSession session = factory.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
// 4.基于Criteria对象进行查询
List employeeList = mapper.selectByExample(example);
for (Employee employee : employeeList) {
System.out.println("employee = " + employee);
}
session.close();
// 最终SQL的效果:
// WHERe ( emp_age between ? and ? and emp_name like ? and emp_gender = ? and emp_salary > ? ) or( emp_age between ? and ? and emp_name like ? and emp_gender = ? and emp_salary > ? )
五、其他
1.Mapper映射、实体类别名
- Mapper映射
- Mapper映射
注意:Mapper配置文件夹名称 需要和 mapper接口保持一致
Mapper配置文件放在Mapper接口所在的包内
- 实体类别名
2.插件机制(了解)
插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行。
著名的Mybatis插件包括 PageHelper(分页插件)、通用 Mapper(SQL生成插件)等。
如果想编写自己的Mybatis插件可以通过实现org.apache.ibatis.plugin.Interceptor接口来完成
但是由于插件涉及到Mybatis底层工作机制,在没有足够把握时不要轻易尝试。
3.类型处理器typeHandler(了解)
Mybatis内置类型处理器
Mybatis自定义类型处理器
1.开发自定义类型转换器:AddressTypeHandler
//自定义类型转换器
public class AddressTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Address address, JdbcType jdbcType) throws SQLException {
}
@Override
public Address getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
String name = resultSet.getString(columnName);
System.out.println(name);
String[] adds = name.split(",");
Address address = new Address(adds[0],adds[1],adds[2]);
return address;
}
@Override
public Address getNullableResult(ResultSet resultSet, int i) throws SQLException {
return null;
}
@Override
public Address getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return null;
}
}
2.在配置文件中进行注册
mybatis-config.xml
3.修改实体类、数据库表,测试
六、MBatis底层对JDBC的封装
SqlSession是一个接口,这里返回的是其实现类DefaultSqlSession的一个实例。其中有一个Executor类型的成员变量。其实进行数据库操作时SqlSession就是一个门面,真正干活的却是Executor。
1.Mbatis底层四大对象:
你以为的四大对象:SqlSessionFactory,SqlSession,Mapper,
JDBC四大对象:DriverManager Connection Statement ResultSet
真正的四大对象:Executor、StatementHandler、ParameterHandler、ResultSetHandler
①Executor
执行器,由它来调度 StatementHandler。
②StatementHandler
使用数据库的 Statement 、PreparedStatement 执行操作
③ParameterHandler
处理SQL参数;比如查询的where条件、和insert、update的字段值的占位符绑定。
④ResultSetHandler(只针对查询操作)
处理结果集ResultSet的封装返回。将数据库字段的值赋给实体类对象的成员变量。
2.Mybatis底层四大步骤:
| BaseExecutor 父类 | SimpleExecutor 子类 | Statement JDBC | |
| 查询 | query() | doQuery() | executeQuery() |
| DML | update() | doUpdate() | executeUpdate() |
第一步:获取数据库连接
Connection connection = getConnection(statementLog);
第二步:获取Statement、PreparedStatement
Statement stmt = handler.prepare(connection, transaction.getTimeout());
第三步:处理参数 (SELECT和DML),给SQL语句中的占位符赋值 ParameterHanlder
handler.parameterize(stmt);
第四步:执行操作
return handler.update(stmt);//insert update delete
return handler.query(stmt, resultHandler); //select 会涉及到结果集ResultHandler
handler是StatementHandler,果真是常务副总经理
七、Mybatis大总结
-
一、简介
-
理解框架
-
生活案例:毛坯房;技术理解:jar+配置文件。
-
好处:提供开发效率 统一了开发风格。
-
ORM
-
Object-Relational Mapping 对象关系映射。
-
数据库表---类 数据库表字段---类的成员变量 数据库表记录--对象。
-
开发者对对象进行操作,结果反应到数据库表,避免了手动的转换。
-
和Hibernate对比
-
都是持久层框架,都是对JDBC进行了封装。
-
半自动化的MyBatis战胜了全自动化的Hibernate。
-
MyBatis将手写SQL语句的工作丢给开发者,可以更加精确的定义SQL,更加灵活,也便于优化性能。
-
符合互联网高并发、大数据、高性能、高响应的要求,使它取代Hibernate成为了Java互联网中首选的持久框架.
-
二、单表操作(基础)
-
项目构成
-
配置文件:数据库连接参数、别名、开启二级缓存、指定映射文件的位置.
-
映射文件:指定SQL语句(select、insert、update、delete)
-
测试类:SqlSessionFactory、SqlSession、Mapper
-
两种方式
-
无接口方式,直接调用SqlSession的方法(selectList、selectOne、update...)
-
Mapper接口方式:需提供接口,但是实现使用动态代理动态生成。(推荐)
-
数据输入:#{} ${}
-
数据输出:resultType resultMap
-
三、多表操作(重点难点)
-
多表连接查询
-
优点:一条SQL语句,速度快。
-
缺点:不灵活,只有立即加载没有延迟加载。
-
分步查询
-
缺点:多条SQL语句,速度慢。
-
优点:灵活,不仅有立即加载还有延迟加载。
-
Java类中添加属性
-
Customer:List orderList = new ArrayList()
-
Order:Customer customer;
-
XML映射文件中配置
-
association
-
collection
-
重点掌握一对多操作基础上能够完成一对一、多对多的操作。
-
四、动态SQL(开发中有应用)
-
使用场合:避免了多条件查询下StringBuilder和append的字符串拼接,还可以应用insert、update操作
-
if where trim 处理多条件查询,有几个条件就执行几个
-
choose/when/otherwise 只执行第一个满足条件的条件
-
foreach:循环
-
set:update
-
sql :提取SQL片段,避免重复修改
-
五、缓存
-
作用:减少数据库访问次数,提高查询速度
-
分类:一级缓存(SqlSession)、二级缓存(SqlSessionFactory)
-
先查询二级缓存,再查询一级缓存、最后是查询数据库
-
一级缓存自动开启,二级缓存需要手动开启,可以引入第三方的二级缓存,比如Ehcache
-
日志框架体系,建议slf4j门面+logback/log4j2具体日志框架
-
六、底层源码原理(面试中使用)
-
四大对象:Executor、StatementHandler、ParameterHandler、ResultSetHandler
-
四大步骤:获取数据库连接、获取Statement|PreparedStatement、处理参数 (SELECT和DML),给SQL语句中的占位符赋值 ParameterHanlder、执行操作
-
缓存的源码
-
读取属性文件
-
一、简介
-
理解框架
-
生活案例:毛坯房;技术理解:jar+配置文件。
-
好处:提供开发效率 统一了开发风格。
-
-
ORM
-
Object-Relational Mapping 对象关系映射。
-
数据库表---类 数据库表字段---类的成员变量 数据库表记录--对象。
-
开发者对对象进行操作,结果反应到数据库表,避免了手动的转换。
-
-
和Hibernate对比
-
都是持久层框架,都是对JDBC进行了封装。
-
半自动化的MyBatis战胜了全自动化的Hibernate。
-
MyBatis将手写SQL语句的工作丢给开发者,可以更加精确的定义SQL,更加灵活,也便于优化性能。
-
符合互联网高并发、大数据、高性能、高响应的要求,使它取代Hibernate成为了Java互联网中首选的持久框架.
-
-
-
二、单表操作(基础)
-
项目构成
-
配置文件:数据库连接参数、别名、开启二级缓存、指定映射文件的位置.
-
映射文件:指定SQL语句(select、insert、update、delete)
-
测试类:SqlSessionFactory、SqlSession、Mapper
-
-
两种方式
-
无接口方式,直接调用SqlSession的方法(selectList、selectOne、update...)
-
Mapper接口方式:需提供接口,但是实现使用动态代理动态生成。(推荐)
-
-
数据输入:#{} ${}
-
数据输出:resultType resultMap
-
-
三、多表操作(重点难点)
-
多表连接查询
-
优点:一条SQL语句,速度快。
-
缺点:不灵活,只有立即加载没有延迟加载。
-
-
分步查询
-
缺点:多条SQL语句,速度慢。
-
优点:灵活,不仅有立即加载还有延迟加载。
-
-
Java类中添加属性
-
Customer:List
orderList = new ArrayList() -
Order:Customer customer;
-
-
XML映射文件中配置
-
association
-
collection
-
-
重点掌握一对多操作基础上能够完成一对一、多对多的操作。
-
-
四、动态SQL(开发中有应用)
-
使用场合:避免了多条件查询下StringBuilder和append的字符串拼接,还可以应用insert、update操作
-
if where trim 处理多条件查询,有几个条件就执行几个
-
choose/when/otherwise 只执行第一个满足条件的条件
-
foreach:循环
-
set:update
-
sql :提取SQL片段,避免重复修改
-
-
五、缓存
-
作用:减少数据库访问次数,提高查询速度
-
分类:一级缓存(SqlSession)、二级缓存(SqlSessionFactory)
-
先查询二级缓存,再查询一级缓存、最后是查询数据库
-
一级缓存自动开启,二级缓存需要手动开启,可以引入第三方的二级缓存,比如Ehcache
-
日志框架体系,建议slf4j门面+logback/log4j2具体日志框架
-
-
六、底层源码原理(面试中使用)
-
四大对象:Executor、StatementHandler、ParameterHandler、ResultSetHandler
-
四大步骤:获取数据库连接、获取Statement|PreparedStatement、处理参数 (SELECT和DML),给SQL语句中的占位符赋值 ParameterHanlder、执行操作
-
缓存的源码
-
读取属性文件
-



