初识事物处理
业务层的职能不仅仅是调用dao这么简单,事物处理是任何企业级应用开发中不能回避的一个重要问题。意为我们通过在业务中硬编码的方式
进行事物控制,这样的弊端显而易见:事物代码分散在业务方法中难以重用,需要调整时工作量也比较打:复杂事物的编码难度较高,增加了开发
难度等。spring提供了声明事物处理机制,他基于aop实现,无须编写任何事物管理代码,所有的工作全部在配置文件中完成。这意味着与业务代码
完全分离,配置即可用,降低了开发和维护的难度。
定义事物管理器
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <!-- ref为数据源 --> <property name="dataSource" ref="dataSource"></property> </bean>
指定的事物管理器设置事物属性
<!-- 事物管理器id为transactionMapper则可以省略 transaction-manager此属性 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- 定义属性,声明事物规则 --> <tx:attributes> <!-- propagation属性定义事物传播行为 name属性则是对应的方法 以什么开头的--> <tx:method name="find*" propagation="SUPPORTS"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
propagetion:事务传播机制,该属性可选值有以下几种
- REQUIRED:默认值,表示如果存在一个事务,则支持当前事务,如果当前没有事务,则开启一个新的事务
- REQUIRES_NEW:表示总是开启一个新的事务,如果事物以及存在则将这个存在的事务挂起,开启新的事务执行该方法
- MANDATORY:表示如果存在一个事务,则支持当前事务,如果当前没有一个活动的事务,则抛出异常
- NESTED:表示如果存在一个活动的事务,则创建一个事务作为当前事务的嵌套事务运行:如果没有当前事务,该取值与REQUIRED相同
- SUPPORTS:表示如果存在一个事务,则支持当前事务,如果当前没有事务,则按非事物方式执行
- NOT_SUPPORTED:表示总是以非事物方式执行。如果事物已经存在,则将这个存在的事物挂起,然后执行该方法
- NEVER:表示总是以非事物方式执行。如果当前存在一个活动的事物,则抛出异常
使用注解实现事务处理
使用了注解就不需要再声明事物规则
只需要一行就行了如下
<tx:annotation-driven transaction-manager="txManager"/>
剩下的声明事物规则就交给注解处理了如下
在业务类上添加@Transaction注解即可为该类的所有业务方法统一添加事物处理。如果某业务方法需要采用不同的事务规则,可以在该业务方法添加@Transaction注解
单独进行设置。@Transaction注解也可以设置事物属性的值,默认的@Transaction设置如下
- 事务传播设置是:REQUIRED
- 事务隔离级别是:
- 事务是读写
- 事务超时默认是依赖于事物系统的,或者事务超时没有被支持
- 任何RuntimeException将触发事务回滚,但是任何checked exception将不触发事务回滚
@Transaction注解各属性如下
需要注意的点:
@Transactional只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
SOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别
使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应
2. ISOLATION_READ_UNCOMMITTED: 未提交读
事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED: 提交读
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
4. ISOLATION_REPEATABLE_READ: 可重复读
这种事务隔离级别可以防止脏读,不可重复读。但可能出现幻像读。除了保证一个事务不能读取另一个事务未提交的数据外,还保证避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE:串行读
花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除防止脏读,不可重复读外,还避免幻像读。
什么是脏数据,脏读,不可重复读,幻觉读?
Dirty reads--读脏数据。
比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的
non-repeatable reads--不可重复读。
比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。
phantom reads--幻象读数据。
这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name="grace",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"grace",结果取出来了7个数据。
不可重复读的重点是修改: 同样的条件, 读取过的数据, 再次读取出来发现值不一样。
幻读的重点在于新增或者删除:同样的条件, 第1次和第2次读出来的记录数不一样。
而事务的隔离级别会导致读取到非法数据的情况如下表示:
|
Dirty reads |
non-repeatable reads |
phantom reads |
SERIALIZABLE |
不会 |
不会 |
不会 |
REPEATABLE_READ |
不会 |
不会 |
会 |
READ_COMMITTED |
不会 |
会 |
会 |
READ_UNCOMMITTED |
会 |
会 |
会 |
常用数据库默认事务隔离级别
MySQL: 默认为REPEATABLE_READ
SQLSERVER:默认为READ_COMMITTED
oracle: 默认为READ_COMMITTED