Spring 事务学习
事务级别
- A (Atomicity原子性):一个事务必须被事务不可分割的最小工作单元,整个操作全部成功或全部失败
- C (Consistency一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏;
通常通过AID三种特性去保证 - I (Isolation隔离性):并行事务之间互不干扰;一个事务相对于另一个事务是隔离的,一个事务所做的修改在最终提交以前,对其他事务是不可见的
- D (Durability持久性):事务提交后,永久生效;即使系统崩溃,修改的数据也不会丢失
并发问题
脏读
一个事务读取另外一个事务未提交的数据 (最低的隔离级别)
不可重复读
在同一个事务中,多次读取同一操作的返回结果有所不同;
换句话说,后续读取可以读到另一个事务已提交的更新数据;
相反,“可重复读”在同一个事务中多次读取数据时,能够保证读取的数据一样;
也就是后续读取不能读到另外一个事务已提交的事务;
脏读也是一种不可重复读
幻读
当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,发现两次不一样,产生幻读
解释一:select 操作得到的结果所表征的数据状态无法支撑后续的业务操作
幻读和脏读的区别:前者是一个数据范围,后者是一种属性概念(行为结果),从总的结果来看, 两者都表现为两次读取的结果不一致;幻读也可以说是不可重复读;
事务隔离级别
Mysql 默认事务隔离级别可重复读(Repeatable Read)
Oracle 默认事务隔离级别读已提交(不可重复读)
- Read Uncommitted ( RU 读取未提交的内容)
最低隔离级别,会读取其他事务未提交的数据 - Read Committed ( RC 读以提交)
事务过程中可以读取其他事务已经提交的数据 - Repeatable Read ( RR 可重复读)
每次读取相同的结果集,不管其他事务是否提交 - Serializable (串行化)
事务排队,隔离级别最高,性能最低
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读(Read Uncommitted) | 可能 | 可能 | 可能 |
已提交读(Read Committed) | 不可能 | 可能 | 可能 |
可重复读(Repeatable Read) | 不可能 | 不可能 | 可能 |
可串行化(Serializable) | 不可能 | 不可能 | 不可能 |
注:事务的隔离级别越高,事务越安全,但是并发能力越差。
Mysql 相关
常见的有多类,InnoDB、MyISAM、MEMORY、MERGE、ARCHIVE、CSV等
一般比较常用的有InnoDB、MyISAM
MySQL 5.5及其以上的版本默认是 InnoDB,5.5之前默认存储引擎是 MyISAM
存储引擎 InnoDB 与 MyISAM 异同点
区别项 | InnoDB | MyISAM |
---|---|---|
事务 | 支持 | 不支持 |
锁粒度 | 行锁(适合高并发) | 表锁(不适合高并发) |
是否默认 | 默认 | 非默认 |
支持外键 | 支持外键(物理外键,建表时显示标明) | 不支持外键 |
适合场景 | 读写均衡,写大于读场景,需要事务 | 读多写少,不需要事务 |
全文索引 | 不支持,可以通过插件实现, 更多使用 ElasticSearch | 支持全文索引 |
Mysql 索引
索引名称 | 特点 | sql语句 |
---|---|---|
普通索引 | 最基本的索引,仅加速查询 | CREATE INDEX idx_name ON table_name(filed_name) |
唯一索引 | 加速查询,列值唯一,允许为空;组合索引则列值的组合必须唯一 | CREATE UNIQUE INDEX idx_name ON table_name(filed_name_1,filed_name_2) |
主键索引 | 加速查询,列值唯一,一个表只有1个,不允许有空值 | ALTER TABLE table_name ADD PRIMARY KEY ( filed_name ) |
组合索引 | 加速查询,多条件组合查询 | CREATE INDEX idx_name ON table_name(filed_name_1,filed_name_2); |
覆盖索引 | 索引包含所需要的值,不需要“回表”查询,比如查询 两个字段,刚好是 组合索引 的两个字段 | |
全文索引 | 对内容进行分词搜索,仅可用于Myisam, 更多用ElasticSearch做搜索 | ALTER TABLE table_name ADD FULLTEXT ( filed_name ) |
业务核心数据存储在Mysql里面,针对业务创建合适的索引
打点数据、日志等存储在ElasticSearch或者MongoDB里面
索引好处
快速定位到表的位置,减少服务器扫描的数据
有些索引存储了实际的值,特定情况下只要使用索引就能完成查询
索引缺点
索引会浪费磁盘空间,不要创建非必要的索引
插入、更新、删除需要维护索引,带来额外的开销
索引过多,修改表的时候重构索引性能差
索引优化实践
前缀索引,特别是TEXT和BLOG类型的字段,只检索前面几个字符,提高检索速度
尽量使用数据量少的索引,索引值过长查询速度会受到影响
选择合适的索引列顺序
内容变动少,且查询频繁,可以建立多几个索引
内容变动频繁,谨慎创建索引
根据业务创建适合的索引类型,比如某个字段常用来做查询条件,则为这个字段建立索引提高查询速度
组合索引选择业务查询最相关的字段
InnoDB
MVCC (多版本并发控制)
Spring 事务传播级别
Spring事务传播级别共7种,可分为2大类,支持当前事务和不支持当前事务
支持当前事务
- PROPAGATION_REQUIRED (必须的)
如果当前没有事务,就新建一个事务,如果已存在就加入当前事务 - PROPAGATION_SUPPORTS (支持)
如果当前没有事务,就新建一个事务,如果已存在就以非事务执行 - PROPAGATION_MANDATORY (强制)
没有当前事务就报错
不支持当前事务
- PROPAGATION_REQUIRED_NEW
新建事务,如果当前存在事务,把当前事务挂起 - PROPAGATION_NOT_SUPPORTS
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
挂起是指用不同的连接,产生不同的事务号,并不是线程挂起 - PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常 - PROPAGATION_NESTED (嵌套事务)
如果当前存在事务,则在嵌套事务内执行;如果没有,则与PROPAGATION_REQUIRED效果相同
Spring 事务失效
Spring 中,申明式事务(开发中通过注解使用)通过 AOP 实现;失效原因,没走动态代理
基本操作:
1.开启事务
TransactionAspectSupport.invokeWithinTransaction transactionManager
2.回滚事务
3.提交事务
4.创建保存点
5.回滚事务点
Spring 事务实现层级
Spring 事务实现方式,自下而上去理解可分为三层,底层是 JDBC,往上是 Spring Transaction,这一层对 JDBC 多了一些封装,再往上是 AOP Transaction,也就是声明式事务的实现层