1.ORM思想、MyBatis概述、日志框架、OGNL
1.1 框架
:是一系列jar包,其本质是对JDK功能的扩展(SDK),是一组程序的集合。
1.2 ORM思想
对象关系映射(Object relational Mapping):主要解决对象-关系的映射
是为了解决面向对象和关系型数据库不匹配的问题的技术。
简而言之,ORM就是通过就是通过使用描述对象和数据库之间映射的元数据,将java程序中的对象自动持久化到关系型数据库中
1.3 常见的ORM框架:
JPA:并非ORM框架,而是ORM规范,由各大ORM框架进行实现
Hibernate、Mybatis
1.4 Mybatis概述及架构图
mybatis是持久层框架,支持定制化sql、存储过程、高级映射,几乎避免了所有的JDBC代码和手动设置参数及获取结果集,使用XML或注解来配置映射。
1.5 Mybatis 核心组件
SqlSessionFactoryBuilder(构建器):创建SqlSessionFactory对象
SqlSessionFactory(会话工厂):创建SqlSession对象
SqlSession(会话):好比是Connection。
Executor(执行器):SqlSession不能直接操作数据库,需要Executor来完成,此接口有两个实现,缓存执行器(缺省)、基本执行器
MappedStatement(映射语句):封装执行sql语句时的信息,例如:SQL、输入参数、输出结果
1.6 Mybatis原理图:
mybatis配置文件/连接池/事务等->会话工厂->会话->执行器->映射语句->DB
更底层的原理图:
SqlSession->Executor->StatementHandler->ParameterHandler、ResultSetHandler->TypeHandler
-> JDBC->DB
Configuration->MappedStatement(SqlSource、ResultMap)->BoundSql
涉及对象说明:
SqlSession:表示和数据库交互的会话,完成数据库增删改查功能
Executor:负责sql语句的生成和查询缓存的维护
StatementHandler:封装了JDBC的DML、DQL操作、参数设置
ParameterHandler:用户传入参数转换为JDBX需要的参数值
ResultHandler:结果集中的数据封装到list集合中
TypeHandler:java类型和JDBC类型的相互转换
MappedStatement:维护了一条<insert|update|delete|select|>节点的封装
SqlSource:根据用户传入的参数生成SQL语句,并封装到BoundSql中
BoundSql:封装SQL语句和参数的信息
Configuration:Mybatis全局配置对象,封装了所有配置信息
1.7 获取mybatis:pom中引入org.mabytis.mybatis
1.8 全局配置文件
一般放在resource目录下,通常命名为 mybatis-config.xml(包含全局配置、属性配置、插件配置、配置环境信息、关联映射文件)
1.9 映射文件
例如XXXMapper.xml。主要包含列和对象的映射,以及insert、delete、update、select 标签
1.10 Mybatis和日志集成配合使用
常见的日志框架:Log4j、Log4j2、Logback、Slf4j。Apache提供的日志规范即日志门面,有了日志门面后,需要用户自行选择第三方的日志组件作为具体实现。
采用最多的日志技术:Slf4j日志门面和Log4j2日志实现
日志级别:ERROR>WARN>INFO>DEBUG>TRACE;如果设置日志级别为INFO,则日志级别为ERROR、WARN、INFO的日志信息会被输出
日志级别设置越低、输出内容越详细
日志文件组成:Log4j2主要由 Loggers、Appenders、Layout 组成。
Loggers:日志记录器,控制日志的输出及输出级别
Appenders:输出控制器,指定日志输出的输出方式(输出到控制台还是文件等)
Layout:日志格式化器,控制日志信息的输出格式
日志使用:pom文件中引入log4j、mybatis配置文件中全局配置、定义日志文件
1.11 作用域和生命周期
SqlSessionFactoryBuilder:此类可被实例化、使用和丢弃,一旦创建SqlSessionFactory对象后,就不再需要。所以此对象放在局部作用域中较合适
SqlSessionFactory:一旦被创建就应该在应用的运行区间一直存在(单例),最佳作用是应用作用域。
SqlSession:每个线程都有自己的SqlSession实例,非线程安全的,因为不能被共享,最佳作用域是请求作用域。
1.12 #和$的异同
相同点:都可以获取对象的信息
不同点:使用#传递的参数会先预编译转换为?占位符,通过$会将解析的数据直接作为SQL的一部分
#好比PrepareStatement,不会导致sql注入问题,相对安全;$好比Statement,可能会导致SQL注入,相对不安全
如何选择:需要设置占位符的参数,全部使用#;如果传递过去的对象参数作为SQL的一部分,则使用$。例如分组、排序等
1.13 Mybatis注解开发,
就不需要XXXMapper.xml了。主配置文件中的mapper标签需要修改为对应Mapper文件全路径
@Insert("sql")、@Delete("sql")、@Update("sql")、@Select("sql")
1.14 多对一数据结构最优查询方案
方案一:查询到人员信息之后,再根据人员信息表中的部门id查询到部门信息
方案二:resultMap中配置association元素(配置单一元素(非数组、集合)的关联对象),将另一个mapper的sql通过association标签嵌入到当前mapper中
方案三:只需要保留一个mapper,但是使用join进行内联映射-多表关联查询
额外SQL的N+1问题:当所有员工,每个员工的部门ID都不一样时,可先查询出所有员工,然后将员工的部门ID提取出来组成Set,然后根据所有部门ID查询所有部门,最后遍历员工信息,将部门赋予员工即可
一对多数据结构最优查询方案
方案一:使用collection标签
1.15 懒加载(延迟加载)、Lazy Load。默认懒加载是禁用的
产生原因:为了避免一些无谓的性能开销提出的方案
定义:当真正需要数据的时候,才会真正执行sql去查询数据
mybatis运行期的属性配置,在settings文件中配置
开启懒加载只需将settings文件中的lazyLoadingEnabled设置为true即可
1.16 mybatis缓存机制
使用缓存可以更快获取数据,mybatis和hibernate一样,也有一级缓存和二级缓存。一级缓存默认开启,二级缓存需要手动开启。
一级缓存:也称本地缓存,默认开启,不能关闭。是基于PerpetualCate的hashmap本地缓存,存储作用域是SqlSession级别,当Session
刷新或者close之后,该SqlSession中的缓存就将清空。SqlSession之间不共享一级缓存。同一个SqlSession会话,发起1条sql语句,才会使用一级缓存。
可以使用SqlSession.clearCache()或增删改操作,都会清空缓存。
一级缓存是基于[namespace:sql语句:参数]作为map的key,查询返回的语句作为value保存的
二级缓存:也称查询缓存,需要手动配置或开启,也可使用第三方缓存框架,例如EhCache、Redis等
也是采用基于PerpretualCache的hashmap对象。不同在于作用域为Mapper(Namespace)级别,多个SqlSession是共享数据的,并且可自定义数据源,如EhCace、Redis等。
开启二级缓存情况下,在一级缓存数据清空或提交之前,会转存到二级缓存中继续存在。
在二级缓存中,两个对象是分别放在两个独立的Map中的(各自的缓存空间)
通常会放到二级缓存中的数据:经常查询;很少修改;不会并并发访问的数据
不适合放到二级缓存的数据:经常被修改
开启二级缓存步骤:setting文件中设置cacheEnabled为true;sql映射文件中添加cache标签。属性有eviction、flushInterval、size、readOnly
eviction表示回收策略:有以下几种选项
LRU:默认值、移除最长时间不被使用的对象
FIFO:按照对象进入缓存的顺序来进行移除
SOFT:移除基于垃圾回收器状态和软引用规则的对象
WEAK:移除基于垃圾回收器状态和弱引用规则的对象
flushInterval:表示刷新间隔,可设置为任意正整数的毫秒数。默认无刷新间隔
size:引用数目,默认值1024
readOnly:只读属性,true或者false(默认)。只读缓存会给所有调用者返回缓存对象的相同实例。
二级缓存的使用:实体类必须实现序列化接口。
二级缓存使用流程:当一个sqlsession执行1个select后,关闭session,会将查询结果保存至二级缓存中。另一个sqlsession查询相同数据时,会先在一级缓存中查询,如果没有会进入二级缓存查询,找到了就返回,从而减轻数据库的压力提高了性能。
注意事项:当sqlsession执行了DML操作(insert、delete、update)后,mybatis会清空缓存中的所有数据,可以保证缓存数据和实时数据是一致的,避免出现脏读。
基于[namespace:sql语句:参数]作为map的key,查询返回的语句作为value
注解开启二级缓存:在Mapper上添加注解@CacheNamespace("blocking = true ")
mapper.xml文件中每个select标签都可以使用useCache属性,默认为true(如果二级缓存开启,则二级缓存生效)。如果为false,即便二级缓存开启,也不会生效。但是一级缓存是没问题的。
增删改查都可以设置 flushCache 属性。增删改此属性默认为true,执行增删改后,会将原来的一、二级缓存全部删除。查询此属性默认为false,如果查询此属性为true,则禁用一切属性。
全部变量 localCacheScopo:SESSION (默认) 开启了一级缓存;STATEMENT:如果设置为此值,相当于关闭一级缓存。
利用自身本地缓存结合redis实现分布式缓存
1.redis实现分布式缓存
缓存:内存中的数据
内存中数据特点:读写快、断点立即丢失
缓存解决问题:提高吞吐量,提升响应速度(效率),缓解数据库压力
适用场景:针对数据库中不常变更的数据适合保存至缓存,如省市县、基础数据
本地缓存和分布式缓存的区别:
本地缓存:存储在应用服务器内存中。mybatis的一级缓存和二级缓存保存在服务器内存中
分布式缓存:存储在当前应用服务器内存之外的数据。redis缓存不局限于某个应用
集群和分布式
集群:将同一种服务创建多个节点共同对外提供服务的过程
分布式系统;多个不同服务集群组成的系统,是共同对系统提供服务
利用mybatis缓存结合redis实现分布式缓存
自定义缓存类,实现mybatis提供的Cache接口
2.搭建springboot和mybatis整合
全局配置文件中定义<setting name="cacheEnabled",value=""true>,具体的xml中添加</cache>,对应查询语句上使用 useCache="true",实体类实现序列化接口即可开启二级缓存
二级缓存也只局限于当前的应用程序,当程序停止(JVM关闭),缓存就不存在了。再次启动程序,还是去数据库中查询
mybatis缓存默认是适用PerpetualCache implements Cache来实现的,底层是HashMap,适用HashMap保存缓存数据时,Key为[nameSpace:SQL:参数],value是查询返回的语句
3.自定义RedisCache缓存
mapper.xml中设置<cache type="RedisCache所在路径">
自定义RedisCache实现Cache接口,重写getId、getObject、putObject等关键方法,重写方法中适用redis进行数据的读写
最终首次读取从数据库读,后续就从redis读取了,即便程序结束再重启,依旧是从redis中读取数据
当执行增删改会执行RedisCache的clear方法,清除redis中的缓存,防止缓存中数据是没有更新过的脏数据
4.多表查询出现的缓存问题
当user表中包含emp表的数据,后面对emp数据进行了更改,redis中emp的缓存数据删除,但是缓存中user的数据还是包含emp的数据,便出现和redis和数据库数据不一致
优化策略:使用<cache-ref namespace="com.zy.dao.UserDao"/>, 将多个有关联关系的表的缓存放到了一起;也可在emp数据清空时,将关联表的user数据也清空
5.缓存优化策略
key长度不要太长,使用MD5散列算法
1.17 ORM概述
ORM(Object-Relation-Mapping)表示对象关系映射,在面向对象软件开发中,通过ORM可以将对象映射到关系数据库中。简而言之,ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就是操作数据库表的目的。
使用ORM的原因:大大减少重复性的数据库访问层代码
常见ORM框架:Mybatis、ibatis、Hibernate、JPA(规范)
1.18 Hibernate和JPA的概述
Hibernate:全自动的ORM框架,自动生成SQL语句、自动执行
JPA:全称为:Java Persistance Api,即java持久化API。SUN公司推出的基于ORM的规范,内部由接口和抽象类构成。
JPA和Hibernate的关系:JPA是规范,Hibernate是JPA的实现
1.19 JPA、Hibernate、SpringDataJpa之间的关系
JPA是规范,
Hibernate是JPA的实现,
SpringDataJpa是spring 提供的简化JPA开发的框架,是JPA规范的再次封装,底层还是使用Hibernate的JPA实现
1.20 JPA API介绍
Persistence对象:主要是通过此类的静态方法createEntityManagerFactory用于获取EntityManagerFactory对象
EntityManagerFactory:此接口主要用于创建EntityManager 实例。线程安全,但是创建非常消耗资源,所以只需要确保工程中只存在一个EntityManagerFactory(单例)即可
EntityManager :此对象是完成持久化操作的核心对象
EntityTransaction :完成事务操作的核心对象
1.21 Spring Data JPA 内部原理剖析
自定义Dao无方法就可以使用很多方法的原因:继承了JpaRepository和JpaSpecificationExecutor,可使用这两个接口的所有方法
SpringDataJPA的实现过程:注入的Dao对象,本质上是通过JdkDynamicAopProxy生成一个代理对象SimpleJpaRepository,借助此对象中对应的方法,通过EntityManagere完成数据库的操作
四种查询方式:SpringDataJPA定义的方法;JPQL;SQL;方法命名规则查询
mybatis-plus
todo
参考资料:https://blog.csdn.net/m0_46313726/article/details/124187527