本系列前序文章索引:html
程序员在转型架构师的过程当中须要创建流程化、结构化、系统化的思惟方式,而性能调优是很是可贵的契机,它既给了咱们压力,也给了咱们动力,跨越它就是突破本身的过程。建议在阅读本文内容前,先参考下面这个系列的文章了解 Web 应用是怎样处理 HTTP 请求的:程序员
今天老兵哥将介绍经过优化开发框架 Spring 来优化系统性能的方法。数据库
事务(Transaction),是并发控制的基本单位,是用户定义的一个操做序列。这些操做要么都作,要么都不作,是一个不可分割的工做单位。经过使用事务控制,咱们能够极大地避免逻辑处理失败致使的脏数据等问题。事务具备 4 个属性:原子性、一致性、隔离性、持久性等,这四个属性一般称为 ACID 特性。segmentfault
Spring 事务管理是经过 XML 文件或注解 @Transactional 配置的,其背后是静态代理或动态代理等技术。在代理模式下,那些从代理传递传过来的“外部”方法调用会被拦截,但“自我调用”是不会触发事务的。例如,在目标对象中调用自身其余方法的方法是不会触发事务的,即便被调用的方法标记为 @Transactional。
一般,咱们不多关注 Spring 事务管理相关的属性,但这些属性的取值会影响系统的性能。Spring 事务管理最重要的两个特性是:传播级别、隔离级别。传播级别,定义了事务的控制范围;隔离级别,定义了事务在数据库读写方面的控制范围。咱们知道,事务的控制范围越大,系统的并发性就会越差,性能也就随之下降。事务的隔离级别越高,系统的并发性也会越差,性能也会随之降低。若是不了解这些属性的取值规则,咱们就不能选择最合适的取值,不知不觉中就会浪费许多系统资源,接下来咱们一块儿来看看这些属性。缓存
属性 | 类型 | 描述 |
---|---|---|
propagation | 枚举型:Propagation | 传播级别,可选,默认值:PROPAGATION_REQUIRED |
isolation | 枚举型:Isolation | 隔离级别,可选,默认值:ISOLATION_DEFAULT |
readOnly | 布尔型 | 读写型事务、只读型事务 |
timeout | INT 型,以秒为单位 | 事务超时阈值 |
rollbackFor | 一组 Class 类,必须是 Throwable 的子类 | 一组异常类,遇到时必须回滚。默认状况下 Checked Exceptions 不进行回滚,仅 Unchecked Exceptions(即 RuntimeException 的子类)才进行事务回滚。 |
rollbackForClassname | 一组 Class 类的名字,必须是 Throwable 的子类 | 一组异常类名,遇到时必须回滚 |
noRollbackFor | 一组 Class 类,必须是 Throwable 的子类 | 一组异常类,遇到时不须要回滚 |
Spring 事务管理的传播级别 Propagation 取值有如下几种:安全
传播级别 | 说明 | 备注 |
---|---|---|
PROPAGATION_REQUIRED | 若是上下文中已经存在事务,那么就加入到事务中执行;若是上下文中不存在事务,则新建事务执行。 | 这个级别一般能知足处理大多数的业务场景。 |
PROPAGATION_SUPPORTS | 若是上下文中已经存在事务,则支持加入到事务中执行;若是上下文中不存在事务,则使用非事务的方式执行。 | 这个一般是用来处理那些并不是原子性的非核心业务逻辑操做,应用场景较少。 |
PROPAGATION_MANDATORY | 该级别的事务要求上下文中必需要存在事务,不然就会抛出异常。这是避免上下文调用代码遗漏添加事务控制的保证手段。 | 例如某段代码不能被单独调用执行,可是一旦被调用就必需要有事务包含,这种状况下就可使用这个传播级别。 |
PROPAGATION_REQUIRES_NEW | 每次都会新建一个事务,而且同时将上下文中的事务挂起,执行当前新建事务完成之后,上下文事务恢复再执行。 | 问题1:若是某个子事务发生回滚,父事务是否回滚?答案是不会,由于子事务是新建事务,父事务已经被挂起,二者不会受到影响。问题2:若是父事务发生回滚,子事务是否回滚?答案是不会,一样的理由。可是能够手动控制,一旦子事务回滚,父事务也回滚。 |
PROPAGATION_NOT_SUPPORTED | 若是上下文中已经存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务。 | 这个级别能够帮助你尽量地缩小事务范围。一个事务范围越大,它存在的风险也就越多,例如某段代码是循环 1000 次的非核心业务逻辑操做,此类代码若是包在事务中,势必致使事务太大,很容易出现些难以考虑周全的异常状况,此时这个级别就派上用场了。 |
PROPAGATION_NEVER | 该级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制中止执行。 | 无 |
传播级别 PROPAGATION_REQUIRED 会为每个被应用到的方法建立一个逻辑事务做用域。每个逻辑事务做用域均可以自主地决定回滚条件,当这样的逻辑事务做用域被外部逻辑事务做用域所包含时,它们在逻辑上是独立的,但在实现层面它们会被映射到相同的物理事务上。
传播级别 PROPAGATION_REQUIRES_NEW 为每个相关的事务做用域使用了一个彻底独立的事务。在这种状况下,物理事务也将是不一样的。所以,外部事务能够不受内部事务回滚状态的影响独立提交或者回滚。
Spring 事务管理的隔离级别 Isolation 取值有如下几种:网络
隔离级别 | 说明 |
---|---|
Serializable | 最严格的级别,事务串行执行,资源消耗最大。 |
Repeatable Read | 保证了一个事务不会修改已经由另外一个事务读取但未提交(或回滚)的数据,避免了“脏读取”和“不可重复读取”的状况,但会带来了更多的性能损耗。 |
Read Committed | 大多数主流数据库的默认事务等级,保证了一个事务不会读到另外一个并行事务已修改但未提交的数据,避免了“脏读取”,该级别适用于大多数系统。 |
Read Uncommitted | 保证了读取过程当中不会读取到非法数据。 |
上述说明中涉及的几个专业术语:架构
隔离级别与反作用 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Serializable | 不会 | 不会 | 不会 |
Repeatable Read | 不会 | 不会 | 会 |
Read Committed | 不会 | 会 | 会 |
Read Uncommitted | 会 | 会 | 会 |
从上面这张映射表中,咱们知道最安全的是 Serializable,可是伴随而来的是高昂的性能开销。各类传播级别、隔离级别自己没有好坏,关键是根据业务需求选择最合适的取值,避免无效的性能损耗。另外,Spring 事务管理还有两个经常使用属性,它们的取值也会影响性能:并发
缓存做为提升应用系统性能的一种有效途径,在事务管理配置不当的状况下,将很难发挥应有的效用。所以,在作缓存处理或者其余处理,要考虑事务管理对性能的影响。框架
关注「 IT老兵哥 」,赋能程序人生!近期热评系列《 程序员必须懂的架构师入门课 》: