SpringData
按应用场景分
- 关系数据库:Mysql、PostgreSQL、Oracle、SqlServer、SQLite
- 键值数据库:Redis、Memcached、LevelDB、RocksDB、Tair、Hbase、Cassandra
- 文档数据库:MongoDB
- 图形数据库:Neo4j
- 时序数据库:OpenTSDB、InfluxDB
按存储方式分
- 行式存储数据库:Mysql、PostgreSQL、Oracle、SqlServer、SQLite
- 列式存储数据库:Hbase、Cassandra
- 键值存储数据库:Redis、Memcached、LevelDB、RocksDB、Tair、Hbase、Cassandra
- 文档存储数据库:MongoDB
- 图形存储数据库:Neo4j
SpringMysql
Framework
Jdbc
JdbcUtils
JdbcTemplate
Jpa
Hibernate
JpaTemplate
Mybatis
Basic
SqlSession
- Mybatis之SqlSession入门
- Mybatis之SqlSession进阶
- Mybatis之SqlSession详解
- Mybatis之SqlSession线程安全详解
- Mybatis之SqlSession和Executor的关系详解
- Mybatis之SqlSession和Statement的关系详解
- Mybatis之SqlSession和Connection的关系详解
- Mybatis之SqlSession和DefaultSqlSession详解
- Mybatis之SqlSession和SqlSessionManager详解
- Mybatis之SqlSession和SqlSessionTemplate详解
- Mybatis之SqlSessionTemplate和SqlSessionManager的区别
- Mybatis之SqlSessionTemplate和SqlSessionManager是如何保证线程安全的
核心对象的作用
- SqlSession:会话,负责抽象的数据库操作和事务
- Executor:执行器,负责具体的数据库操作和事务,执行sql语句,管理事务和缓存
- Statement:sql语句
- Connection:数据库连接,可被复用但同一时刻只能被一个使用者使用
SqlSession的实现类
- DefaultSqlSession:不是线程安全的
- SqlSessionManager:是线程安全的
- SqlSessionTemplate:是线程安全的
ps:SqlSessionManager和SqlSessionTemplate的线程安全是通过ThreadLocal实现的
Mapper
- Mybatis之Mapper入门
- Mybatis之Mapper进阶
- Mybatis之Mapper详解
- Mybatis之Mapper和SqlSession的关系入门
- Mybatis之Mapper和SqlSession的关系详解
- Mybatis之Mapper注解入门
- Mybatis之Mapper注解进阶
- Mybatis之Mapper注解详解
- Mybatis之Mapper原理入门
- Mybatis之Mapper原理进阶
- Mybatis之Mapper原理详解
- Mybatis之Mapper实现类是怎么生成的
- Mybatis之Mapper线程安全详解
- Mybatis通用Mapper详解
- Mybatis通用Mapper原理
- Mybatis映射之Mapper和xml的映射规范
- Mybatis映射之Mapper的方法重载
Mapper是数据持久对象(PO),执行多条sql语句,执行sql是通过SqlSession来实现的
ps:Mapper的线程安全取决于SqlSession的线程安全,Mapper使用了SqlSessionTemplate来保证线程安全
Mapper和SqlSession的关系
- Mapper里的方法执行多条sql时,方法不使用事务时,每条sql都会创建一个SqlSesssion对象
- Mapper里的方法执行多条sql时,方法使用事务时,多条sql只会创建一个SqlSesssion对象
ps:Mapper获取SqlSession时会先在事务管理器的ThreadLocal里面查找,找不到就创建SqlSession对象使用
ps:有事务时新创建的SqlSession会注册到事务管理器的ThreadLocal中,无事务时不会注册
Usage
Field
id
返回主键方案
- 数据库支持主键自增时:useGeneratedKeys + keyProperty
- 数据库不支持主键自增时:selectKey
type
mapping
类的属性名和表的字段名不一样的解决办法
- 启用下划线转驼峰的配置
- 在sql中起别名保持一致
- 使用ResultMap自定义映射
Query
动态 sql 标签
<if></if>
<choose></choose>(when, otherwise)
<foreach></foreach>
<where></where>
<set></set>
<trim></trim>
<bind/>
fuzzy(模糊查询)
pagenation(分页查询)
分页查询方案
- 使用RowBounds来完成内存分页(它是针对ResultSet结果集执行的内存分页,而非物理分页)
- 直接在sql中写分页条件来完成物理分页
- 通过分页插件来完成物理分页
ps:分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql语句并改写sql,改写时会根据方言(dialect)添加对应的物理分页条件
reference(关联查询)
- 一对一查询(selectOne): association + result、association + select
- 一对多查询(selectOne):collection + result、collection + select
- 多对一查询(selectMany): association + result、association + select
- 多对多查询(selectMany):collection + result、collection + select
ps:result方式是连接查询,需要在sql中进行join
ps:select方式是分步查询,不需要在sql中进行join
ps:多对一
本质上还是一对一
,多对多
本质上还是一对多
Param
- 参数名称
- 参数个数
- 单个参数
- 多个参数
- 参数类型
- 基本类型
- 对象类型
- 容器类型
- Map
- Array/List/Set
Result
Cache
Extend
tkMybatis
ps:insert、update有Selective方法代表插入或者更新非null字段
MybatisPlus
MyBatisFlex
Question
${}和#{}的区别
- ${}是属性替换符,生成sql时会直接替换成属性的值(不会被转义)
- #{}是参数占位符,生成sql时会被处理为问号并通过PreparedStatement设置参数执行(会转义)
where中的1=1的作用
为了保证没有筛选条件时sql语句的正确性
Problem
Cache
一级缓存
一级缓存是session范围的
因为一级缓存是session范围的,所以BSession的更新不会使ASession的缓存失效,ASession再次查询时还会读缓存,导致BSession数据的更新读不到
二级缓存
二级缓存是mapper范围的
因为二级缓存是mapper范围的,所以BMapper的更新不会使AMapper的缓存失效,AMapper再次查询时还会读缓存,导致BMapper数据的更新读不到
Transaction
Basic
Usage
- 编程式事务管理:TransactionTemplate、TransactionManager
- 声明式事务管理:@Transactional、TransactionProxyFactoryBean
- 配置式事务管理:Aspectj AOP
Invalid
事务的失效场景
- 所有AOP失效的场景(例外是事务对protected也不生效)
- 多线程或者异步调用(事务是线程隔离的)
- 事务传播方式使用不当
ps:@Transactional是通过AOP实现的,所以失效的场景包含AOP失效的场景
事务不回滚的场景
- 异常被吞掉了
- 未指定rollbackFor参数时抛出的异常不是RuntimeException
- 指定rollbackFor参数时抛出的异常和指定的异常不匹配
Rollback
Propagation
事务传播方式处理的是两个方法之间的事务关系,比如加入当前事务或者新建事务等等
事务传播方式
- PROPAGATION_REQUIRED:如果当前存在事务就
加入当前事务
,否则就以新建事务
的方式运行 - PROPAGATION_SUPPORTS:如果当前存在事务就
加入当前事务
,否则就以非事务
的方式运行 - PROPAGATION_MANDATORY:如果当前存在事务就
加入当前事务
,否则就抛出异常
- PROPAGATION_REQUIRES_NEW:以
新建事务
的方式运行,如果当前存在事务就挂起当前事务
- PROPAGATION_NOT_SUPPORTED:以
非事务
的方式运行,如果当前存在事务就挂起当前事务
- PROPAGATION_NEVER:以
非事务
的方式运行,如果当前存在事务就抛出异常
- PROPAGATION_NESTED:如果当前存在事务就
开启嵌套事务
运行,否则就新建事务
运行
ps:传播方式为PROPAGATION_REQUIRES_NEW和PROPAGATION_NOT_SUPPORTED时如果存在当前事务,当前事务会被挂起
ps:传播方式为PROPAGATION_NESTED时嵌套事务回滚不会影响主事务,但主事务回滚会将嵌套事务一起回滚了
事务传播处理
- 当前事务存在时
- 加入当前事务
- 挂起当前事务
- 抛出异常
- 当前事务不存在时
- 新建事务
- 非事务
- 抛出异常
Question
Spring事务之为什么要加在Service层
Spring事务之到底能不能加到Controller层
Spring事务实现为什么不推荐@Transactional注解
- 使用不当时事务不会生效,比如同类方法调用等
- 容易出现长事务问题,占用数据库连接
- 事务内的非数据库操作不能回滚,会导致不一致的问题
Problem
@Transactional + @Async
:在事务方法里面调用异步方法时异步方法可能读不到最新的数据(因为事务可能还没有提交)@Transactional + @Retryable
:对事务方法进行重试可能读不到最新的数据(因为隔离级别为可重复读时只会在事务启动时生成快照)@Transactional + Lock
:锁的提前释放导致锁的作用失效(因为解锁会先于事务提交执行)
Async
事务方法A调用异步方法B会启动另一个事务B(因为事务是线程隔离的),因为事务A和B之间存在隔离性,所以异步方法B执行时,如果事务方法A未结束时是查不到变更的数据的(因为此时事务A还未提交),如果事务方法A已结束是可以查到变更的数据的(因为此时事务A已提交)
Retry
重试如果在事务开始之后可能会不起作用(隔离级别为可重复读时只在事务启动时生成快照)
Lock
解锁如果在事务提交之前可能会导致业务逻辑错误