从开源项目学到了什么东西
spring ssecurity
token校验
- Token 过滤器,验证 token 的有效性,验证通过后, 构建LoginUser信息,并加入到 Spring Security 上下文
- 再通过authentication.getPrincipal(),获得当前用户
@PreAuthorize
- hasPermission
- hasRole
- 注意bean上要表明注解@Bean(“ss”),才能使用简称
自定义权限配置
- 白名单路径校验
Mybatis Plus区别与Mybatis区别
Mybatis
-
编程步骤
- 创建 SqlSessionFactory 对象
- 通过 SqlSessionFactory 获取 SqlSession 对象
- 通过 SqlSession 获得 Mapper 代理对象
- 通过 Mapper 代理对象,执行数据库操作。
- 执行成功,则使用 SqlSession 提交事务
- 执行失败,则使用 SqlSession 回滚事务
- 最终,关闭会话
-
#{} 和 ${} 的区别是什么
- #{}可以有效防止 SQL 注入,提高系统安全性
-
常见问题除了select、update、insert、delete还有什么标签
-
、 、 、
-
动态sql
- trim|where|set|foreach|if|choose|when|otherwise|bind
-
-
动态SQL
- 执行原理为,使用 OGNL 的表达式,从 SQL 参数对象中计算表达式的值,根据表达式的值动态拼接 SQL ,以此来完成动态 SQL 的功能。
-
Mappser接口映射
-
接口的全限名,就是映射文件中的namespace
-
接口的方法名,就是映射文件中MappedStatement 的id
-
接口方法内的参数,就是传递给 SQL 的参数
-
原理
- 在 Mybatis 中,每一个标签会被解析成MappedStatement 对象
Mapper 接口的实现类,通过 MyBatis 使用 JDK Proxy 自动生成其代理对象 Proxy ,而代理对象 Proxy 会拦截接口方法,从而“调用”对应的 MappedStatement 方法,最终执行 SQL
- 在 Mybatis 中,每一个标签会被解析成MappedStatement 对象
-
-
Mapper接口绑定方式
- 通过 XML Mapper 里面写 SQL 来绑定(namespace+id)
- 通过注解绑定@Select、@Updated等
- 第三种,是第二种的特例,也是通过注解绑定@UpdateProvider、@InsertProvider,编写java代码
-
在 Mapper 中如何传递多个参数
- 使用 Map 集合,装载多个参数进行传递
- 保持传递多个参数,使用 @Param 注解(推荐)
-
Mybatis 是否可以映射 Enum 枚举类
- EnumTypeHandler ,基于 Enum.name 属性( String )。默认
- EnumOrdinalTypeHandler ,基于 Enum.ordinal 属性
- 实际开发场景,我们很少使用 Enum 类型
-
都有哪些 Executor 执行器
-
SimpleExecutor
- 每执行一次 update 或 select 操作,就创建一个 Statement 对象,用完立刻关闭 Statement 对象。
-
ReuseExecutor
- 执行 update 或 select 操作,以 SQL 作为key 查找缓存的 Statement 对象,存在就使用,不存在就创建;用完后,不关闭 Statement 对象,而是放置于缓存
-
BatchExecutor
- 执行 update 操作,缓存了多个 Statement 对象,每个 Statement 对象都是调用 addBatch 方法完毕后,等待一次执行 executeBatch 批处理
-
CachingExecutor
- 在上述的三个执行器之上,增加二级缓存的功能
-
-
如何批量插入
- SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)
//循环插入
session.commit()提交 - 用大白话概括就是获取批量插入的会话,然后循环调用插入接口,最后统一提交事务
- SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)
-
一级缓存和二级缓存概念
-
一级缓存
- 一级缓存的生命周期和SqlSession一致
- 一级缓存内部设计简单,只是一个没有容量限定的HashMap
- 一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement
-
二级缓存
- 二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强
- 多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻
- 在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis、Memcached等分布式缓存可能成本更低,安全性也更高。
-
个人建议MyBatis缓存特性在生产环境中进行关闭,单纯作为一个ORM框架使用可能更为合适。
-
-
延迟加载
- 仅支持 association 关联对象和 collection 关联集合对象的延迟加载。其中,association 指的就是一对一,collection 指的就是一对多查询。可以配置 来启用延迟加载的功能
- 它的原理是,使用 CGLIB 或 Javassist( 默认 ) 创建目标对象的代理对象
-
Mybatis 不仅可以执行一对一、一对多的关联查询,还可以执行多对一,多对多的关联查询,配置映射关系
- 多对一查询,其实就是一对一查询,只需要把 selectOne(…) 修改为 selectList(…) 即可
- 多对多查询,其实就是一对多查询,只需要把 #selectOne(…) 修改为 selectList(…) 即可
-
插件运行原理
- 首先,实现 Mybatis 的 Interceptor 接口,并实现 #intercept(…) 方法
- 然后,在给插件编写注解,指定要拦截哪一个接口的哪些方法即可
- 最后,在配置文件中配置你编写的插件
-
分页原理
-
使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非数据库分页
-
实际场景下,不适合直接使用 MyBatis 原有的 RowBounds 对象进行分页。而是使用如下两种方案
- SQL 内直接书写带有数据库分页的参数来完成数据库分页功能
- 使用分页插件来完成数据库分页
-
-
JDBC 编程有哪些不足之处,MyBatis是如何解决这些问题的
-
SQL 语句写在代码中造成代码不易维护,且代码会比较混乱
- 将 SQL 语句配置在 Mapper XML 文件中,与 Java 代码分离
-
根据参数不同,拼接不同的 SQL 语句非常麻烦
- MyBatis 提供 、 等等动态语句所需要的标签,并支持 OGNL 表达式,简化了动态 SQL 拼接的代码,提升了开发效率
-
对结果集解析麻烦,SQL 变化可能导致解析代码变化,且解析前需要遍历
- Mybatis 自动将 SQL 执行结果映射成 Java 对象
-
-
Mybatis 的 XML 映射文件和 Mybatis 内部数据结构之间的映射关系
- 标签,会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象
- 标签,会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。
- 每一个 、、、 标签,均会被解析为一个 MappedStatement 对象,标签内的 SQL 会被解析为一个 BoundSql 对象。
Mybatis Plus
- 提供了基本的CRUD功能,连SQL语句都不需要编写
- 支持Lambda形式调用
- 自动解析实体关系映射转换为MyBatis内部对象注入容器
优缺点
本地缓存
考虑到本地缓存的实时刷新,并未采用 Spring Cache 框架,而是使用 Map 缓存数据,通过 Redis Pub/Sub 实时刷新,通过 Job 兜底定时刷新
消息队列
Stream特性的集群消费
- 发送短信,发送邮件
Pub/Sub特性的广播消费
- 刷新本地内存的缓存