最近在学习项目的过程中,总涉及到事务、日志。我所理解的日志,是为了记录用户的使用情况,用于记录软件或者系统运行使用过程中出现的异常和错误。当然这是日志的普通功能。但这里日志不是主角,主角是一个叫事务的东西。一开始接触事务,是从数据库部分了解到的。因为在写后台业务逻辑的过程中,总会遇到一些错误,最经典的例子就是银行转账。当然,我想先总结一下事务的基础知识。然后结合例子来分析一下吧。
1.什么是事务
事务逻辑上是一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败。(我认为最主要的是成功了如何处理,失败了如何处理。)
2.事务特性
事务涉及一定的术语总结起来就是ACID
A:(atom)原子性:顾名思义,原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。不会结束在中间的某一过程。(想一想化学反应中原子是参与反应的最小粒子你就可以更好地理解了)
C:(constant)一致性:事务开始之前和事务结束之后,数据库的完整性没有被破坏。这就意味着事务执行过程中数据的读写都遵循一定的规则(不会对数据库造成破坏)
I:(isolate)隔离性:数据库允许多个并发事务同时对数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。这里引入一个隔离级别的概念。总结起来就是:事务执行过程中,不受其他事务的影响。(包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable))
D:(durable) 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
3.不考虑隔离性引发安全性问题
脏读:当一个事务正在访问数据,并对数据进行了修改,而这种修改还没有提交到数据库中,这是另外一个事务访问了这个数据,然后使用了这个数据。当然读的结果是修改之前的,但是,却不是准确的。
不可重复读:在一个事务内,多次读同一个数据,在这个事务还没有结束的时候,另外一个事务也访问该同一数据,那么,在第一个事务中两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据就不一样。这样就发生了在一个事务内,两次读到的数据是不一样的。因此称为不可重复读。这样的情况我遇到过,在这里顺便吐槽一下学习的饭卡充值系统,这天中午我去充卡机充值了100块钱,当时使用的时候卡顿了一下,没有立即显示充值成功,当时一想反正这是支付宝与系统连接的,钱也丢不了。就想着再充一次。然后按照同样的操作,我就又充值了100,这次系统反而不卡顿了。然后就去买饭了。结果再去刷卡,发现没有到账,大概可能也许是到账有点慢吧。老板让我先吃,吃完再去刷卡(老板人挺好的哈。)然后我就先吃吧,吃完再去刷卡时,发现卡里只多了100元。我就很纳闷。支付宝记录我确实支付了200啊。但是卡里只多了100怎么整。后来学习后才知道到这是事务的问题。当然最后那钱也回来了。毕竟是个成熟的系统嘛。第一次出现卡顿可能是第一次读的过程中处理过程有些卡顿,第二次读的过程还是读第一次读的结果,第二次更改了原始数据,而第一次更改后提交结果却发现自己要提交的结果已经在数据库中更新了。
虚读(幻读)是指事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中全部的数据行,同时,第二个事务也修改这个表中的数据,这种修改是想表中插入一行数据。那么以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就像发生了幻觉一样。例如:一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已经将未编辑的新材料添加到该文档中,如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。
4.事务隔离级别
基于元数据的 Spring 声明性事务 :
Isolation 属性一共支持五种事务设置,具体介绍如下:
1 DEFAULT 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别 .
2 未提交读 READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
3 已提交读 READ_COMMITTED 会出现不可重复读、幻读问题(锁定正在读取的行)
4 可重复读 REPEATABLE_READ 会出幻读(锁定所读取的所有行)
5 串行化 SERIALIZABLE 保证所有的情况不会发生(锁表)
5.Spring的事务管理
Spring事务管理高层抽象主要包括3个接口:PlatformTransactionManager(事务管理器)
TransactionDefinition(事务定义信息,包含隔离级别、事务传播行为、超时、只读)
TransactionStatus(事务具体运行状态)
5.1事务管理器:PlatformTransactionManager
spring 为不同的持久化框架提供了不同的事务管理器
5.2事务定义信息
事务定义信息,隔离级别我们上面介绍了。
下面分别是事务传播行为:
超时和只读用的并不是很多。
5.3事务具体状态TransactionStatus

6.总结
Spring将事务管理分成了两类:
编程式事务管理:
手动编写代码进行事务管理.(很少使用)
声明式事务管理:
基于TransactionProxyFactoryBean的方式.(很少使用)
需要为每个进行事务管理的类,配置一个TransactionProxyFactoryBean进行增强.
基于AspectJ的XML方式.(经常使用)
一旦配置好之后,类上不需要添加任何东西
基于注解方式.(经常使用)
配置简单,需要在业务层上添加一个@Transactional的注解.