Spring学习六(事物管理)

参考链接

http://www.mamicode.com/info-detail-1248286.html

http://www.cnblogs.com/wangdaqian/archive/2017/06/01/6929843.html

http://www.cnblogs.com/fjdingsd/p/5632949.html

http://blog.csdn.net/bao19901210/article/details/41724355

http://blog.csdn.net/u011726984/article/details/45421151

Spring的事物管理分为两种,一种是编程式,一种是声明式。因为声明式基于AOP原理,不侵入代码。所以常用声明式。

Spring学习六(事物管理)

根据这个图分析:

1 无论声明式还是编程式,transactionmanager必须加载,对应的不同形式的transactionmanager也不同,比如Hibernate, JDBC原生(DataSourceTransactionManager) Jta ,Spring只是提供一个manager的接口,具体的实现要具体的框架去加载,不同的事物详细配置请看上方链接。

2 常用申明式

3 编程式分为Transaction template 和PlatformTransactionManager 一般用前者。

4 声明式是基于AOP的非侵入式,所以常用,但是编程式有更佳控制。

重点:

Spring学习六(事物管理)

spring事务特性

spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口

其中TransactionDefinition接口定义以下特性:

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

事务只读属性

      只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。
默认为读写事务。

“只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。

但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。

因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可

 

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

代码如下

xml全部配置如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <!-- 配置配置文件 -->
<context:property-placeholder location="classpath:db.properties" /> <!-- 配置数据源文件 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="initialPoolSize" value="${jdbc.iniPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean> <!-- 两种编程式的事物管理 一种是 TransactionTemplate 一种是PlatformTransactionManager --> <!-- 配置template -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 配置带参template -->
<bean id="namedtemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource"></constructor-arg>
</bean> <!-- 事物管理器接口 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 编程式templete方法 -->
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean> <bean id="accountDao" class="Test.AccountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean> <!-- 声明式方法,因为是基于AOP方式,所以下面要配置AOP -->
<tx:advice id="txadvice" transaction-manager="transactionManager">
<tx:attributes><!-- 可以在里面指定很多方法 这里我就只指定一个了 -->
<tx:method name="transactionMoney2" rollback-for="Exception"/><!--
可以在里面设置propagation,timeout,isolation,rollbackfor and no for 等等-->
</tx:attributes>
</tx:advice> <!-- 没有注释掉就是非注解声明式 模式
<aop:config>
<aop:pointcut expression="execution(* Test.AccountDao.*(..))" id="AccountPointCut" />
<aop:advisor advice-ref="txadvice" pointcut-ref="AccountPointCut" />
</aop:config>
--> <!-- 开启事务控制的注解回滚模式 @Transactional -->
<tx:annotation-driven transaction-manager="transactionManager"/> <context:component-scan base-package="Test"></context:component-scan>
</beans>

java测试代码如下

package Test;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate; public class AccountDao {
private JdbcTemplate jdbcTemplate;
private TransactionTemplate transactionTemplate; public TransactionTemplate getTransactionTemplate() {
return transactionTemplate;
} public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
} public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
} public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
} public int getCount(int id) {
// String sql ="SELECT count FROM account where id=?"; 不要用count
// 这是sql里面计算要用的 String sql = "SELECT count1 FROM account where id=?";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class, id);
return count;
} public void addMoney(int id, int number) {
String sql = "UPDATE account SET count1=count1+? where id=?";
jdbcTemplate.update(sql, number, id);
} public void subMoney(int id, int number) throws Exception {
if ((this.getCount(id) - number) < 0) {
throw new Exception();
} String sql = "UPDATE account SET count1=count1-? where id=?";
jdbcTemplate.update(sql, number, id); } //编程式
public void transactionMoney(int id1, int id2, int money) { // transactionTemplate.setIsolationLevel(1);
// transactionTemplate.setPropagationBehavior(2);//等等
// 是权限之类的设置,但是添加后出现错误? 为什么 不知道 再看看 transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override
protected void doInTransactionWithoutResult(TransactionStatus statu) {
try {
addMoney(id1, money);
subMoney(id2, money);
} catch (Exception e) {
statu.setRollbackOnly();
e.printStackTrace();
} }
}); } //声明式一
public void transactionMoney2(int id1, int id2, int money) throws Exception { addMoney(id1, money);
subMoney(id2, money);
//千万千万不能再try catch里面捕获,不让相当于他觉得你已经处理了,所以不会正确回滚,并且,他默认
//只能在跑出RuntimeException的时候才会回滚,像这里的Exception 需要在xml文件里面加入rollback-for="Exception"。 } //声明式二
@Transactional(rollbackFor=Exception.class)//同理上面,这里也需要指定为Exception抛出异常也必须回滚。还有很多属性可以设置,比如time什么的。
public void transactionMoney3(int id1, int id2, int money) throws Exception { addMoney(id1, money);
subMoney(id2, money); } } //测试单元如下
@Test
public void testAccountDao() throws Exception{
//之前先捕获accountDao
accountDao.transactionMoney3(1, 3, 15); }
上一篇:Openstack Nova network


下一篇:oracle中创建表时添加注释