- 注解
- 持久化与持久层
- 什么是 ORM 框架?
- *mybatis 中 #{}和 ${}的区别是什么?
- {}是预编译处理,${}是字符串替换;
注解
@MapKey
这是一个用在返回值为 Map 的方法上的注解。它能够将存放对象的 List 转化为 key 值为对象的某一属性的 Map。属性有: value,填入的是对象的属性名,作为 Map 的 key 值。
通过@MapKey注解设置map集合的键,值是每条数据所对应的map集合
持久化与持久层
什么是“持久化”
持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。
什么是 “持久层”
持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联。
什么是 ORM 框架?
对象-关系映射(Object-Relational Mapping,简称ORM),面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
只要提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。
它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。
*mybatis 中 #{}和 ${}的区别是什么?
{}是预编译处理,${}是字符串替换;
- Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用
- PreparedStatement的set方法来赋值;
- Mybatis在处理${}时,就是把${}替换成变量的值;
- 使用#{}可以有效的防止SQL注入,提高系统安全性
- ${}的本质就是字符串拼接,#{}的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
resultType和resultMap
resultMap:设置自定义映射
- 属性:
- id:表示自定义映射的唯一标识,不能重复
- type:查询的数据要映射的实体类的类型
- 子标签:
- id:设置主键的映射关系
- result:设置普通字段的映射关系
- 子标签属性:
- property:设置映射关系中实体类中的属性名
- column:设置映射关系中表中的字段名
- 属性:
- 若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射,即使字段名和属性名一致的属性也要映射,也就是全部属性都要列出来
MyBatis的各种查询功能
- 如果查询出的数据只有一条,可以通过
- 实体类对象接收
- List集合接收
- Map集合接收,结果
{password=123456, sex=男, id=1, age=23, username=admin}
- 如果查询出的数据有多条,一定不能用实体类对象接收,会抛异常TooManyResultsException,可以通过
- 实体类类型的LIst集合接收
- Map类型的LIst集合接收
- 在mapper接口的方法上添加@MapKey注解
添加功能获取自增的主键
- 使用场景
- t_clazz(clazz_id,clazz_name)
- t_student(student_id,student_name,clazz_id)
- 添加班级信息
- 获取新添加的班级的id
- 为班级分配学生,即将某学的班级id修改为新添加的班级的id
在mapper.xml中设置两个属性
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
- lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
- aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载
- 此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=”lazy(延迟加载)|eager(立即加载)”
mybatis 是否支持延迟加载?延迟加载的原理是什么?
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载, association指的就是多对一,collection指的就是一对多查询。在Mybatis配 置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入 拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB() 是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上 来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成 a.getB().getName()方法的调用。这就是延迟加载的基本原理。当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都 是一样的mybatis 有几种分页方式?
- 数组分页
2. sql分页
3. 拦截器分页
4. RowBounds分页mybatis 逻辑分页和物理分页的区别是什么?
物理分页速度上并不一定快于逻辑分页,逻辑分页速度上也并不一定 快于物理分页。
物理分页总是优于逻辑分页:没有必要将属于数据库端的压力加诸到应用端来,就算速度上存在优势,然而其它性能上的优点足以弥补这个缺点说一下 mybatis 的一级缓存和二级缓存?
一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有缓存就将 清空,默认打开一级缓存。
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储 源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性 类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件 中配置;
对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存 Namespaces)的进行了C/U/D 操作后,默认该作用域下所有select 中的缓存 将被 清空动态标签
if
- if标签可通过test属性(即传递过来的数据)的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行
在where后面添加一个恒成立条件
1=1
trim用于去掉或添加标签中的内容
- 常用属性
- prefix:在trim标签中的内容的前面添加某些内容
- suffix:在trim标签中的内容的后面添加某些内容
- prefixOverrides:在trim标签中的内容的前面去掉某些内容
- suffixOverrides:在trim标签中的内容的后面去掉某些内容
若trim中的标签都不满足条件,则trim标签没有任何效果,也就是只剩下
select * from t_emp
choose、when、otherwise
choose、when、otherwise
相当于if...else if..else
-
foreach
属性:
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次通过SqlSession查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
使一级缓存失效的四种情况:
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
- 二级缓存开启的条件
- 在核心配置文件中,设置全局配置属性
cacheEnabled="true"
,默认为true,不需要设置 - 在映射文件中设置标签
- 二级缓存必须在SqlSession关闭或提交之后有效
- 查询的数据所转换的实体类类型必须实现序列化的接口
- 在核心配置文件中,设置全局配置属性
使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
Mybatis动态sql有什么用?执行原理?有哪些动态 sql?
Mybatis动态sq可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值完成逻辑判断并动态拼接sql的功能。
Mybatis提供了9种动态sql标签 :trim | where | set | foreach | if | choose| when | otherwise | bind。二级缓存的相关配置
在mapper配置文件中添加的cache标签可以设置一些属性
- eviction属性:缓存回收策略
- LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
- FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
- SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
- WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
- 默认的是 LRU
- flushInterval属性:刷新间隔,单位毫秒
- 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句(增删改)时刷新
- size属性:引用数目,正整数
- 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
readOnly属性:只读,true/false
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
- 如果二级缓存没有命中,再查询一级缓存
- 如果一级缓存也没有命中,则查询数据库
- SqlSession关闭之后,一级缓存中的数据会写入二级缓存
mybatis 和 hibernate 的区别有哪些?
(1)Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需 要程序员自己编写Sql语句。
(2)Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一 但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
(3)Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求 高的软件,如果用hibernate开发可以节省很多代码,提高效率。
mybatis 有哪些执行器(Executor)?
Mybatis有三种基本的执行器(Executor):
1. SimpleExecutor:每执行一次update或select,就开启一个 Statement对象,用完立刻关闭Statement对象。
2. ReuseExecutor:执行update或select,以sql作为key查找Statement 对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而 是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
3. BatchExecutor:执行update(没有select,JDBC批处理不支持 select),将所有sql都添加到批处理中(addBatch()),等待统一执行 (executeBatch()),它缓存了多个Statement对象,每个Statement对 象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
mybatis 分页插件的实现原理是什么?
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应 的物理分页语句和物理分页参数。
开启分页功能
在查询功能之前使用
PageHelper.startPage(int pageNum, int pageSize)
开启分页功能在查询获取list集合之后,使用
PageInfo<T> pageInfo = new PageInfo<>(List<T> list, intnavigatePages)
获取分页相关数据pageNum:当前页的页码
- pageSize:每页显示的条数
- size:当前页显示的真实条数
- total:总记录数
- pages:总页数
- prePage:上一页的页码
- nextPage:下一页的页码
- isFirstPage/isLastPage:是否为第一页/最后一页
- hasPreviousPage/hasNextPage:是否存在上一页/下一页
- navigatePages:导航分页的页码数
- navigatepageNums:导航分页的页码,[1,2,3,4,5]