事物管理,spring事物详解,spring @transactional
对于spring@transactional标签的使用时出现意料之外的错误,数据不同步。后来详细研究spring的事物机制和回滚的触发时机得到解决。以下资料收集于网络:
1.声明式事务配置
*配置SessionFactory
*配置事务管理器
*事务的传播特性
*那些类那些方法使用事务
2、编写业务逻辑方法
*继承HibernateDaoSupport类,使用HibernateTemplate来持久化,HibernateTemplate是HibernateSession的轻量级封装
*默认情况下运行期异常才会回滚(包括继承了RuntimeException子类),普通异常是不会滚的
*编写业务逻辑方法时,最好将异常一直向上抛出,在表示层(struts)处理
*关于事务边界的设置,通常设置到业务层,不要添加到Dao上
3、了解事务的几种传播特性
1.PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启
2.PROPAGATION_SUPPORTS:如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
3.PROPAGATION_MANDATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4.PROPAGATION_REQUIRES_NEW:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5.PROPAGATION_NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务。
6.PROPAGATION_NEVER:总是非事务地执行,如果存在一个活动事务,则抛出异常
7.PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动事务,
则按TransactionDefinition.PROPAGATION_REQUIRED属性执行
4、Spring事务的隔离级别
1.ISOLATION_DEFAULT:这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与JDBC的隔离级别相对应
2.ISOLATION_READ_UNCOMMITTED:这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读。
3.ISOLATION_READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
4.ISOLATION_REPEATABLE_READ:这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5.ISOLATION_SERIALIZABLE这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
除了防止脏读,不可重复读外,还避免了幻像读。
*事务隔离:当前事务和其它事务的隔离的程度。例如,这个事务能否看到其他事务未提交的写数据?
*事务传播:通常在一个事务中执行的所有代码都会在这个事务中运行。但是,如果一个事务上下文已经存在,有几个选项可以指定一个事务性方法的执行行为:例如,简单地在现有的事务中继续运行(大多数情况);或者挂起现有事务,创建一个新的事务。Spring提供EJBCMT中常见的事务传播选项。
*事务超时:事务在超时前能运行多久(自动被底层的事务基础设施回滚)。
*只读状态:只读事务不修改任何数据。只读事务在某些情况下(例如当使用Hibernate时),是一种非常有用的优化。
*回滚规则的概念比较重要:它使我们能够指定什么样的异常(和throwable)将导致自动回滚。我们在配置文件中声明式地指定,无须在Java代码中。同时,我们仍旧可以通过调用TransactionStatus的setRollbackOnly()方法编程式地回滚当前事务。通常,我们定义一条规则,声明MyApplicationException必须总是导致事务回滚。这种方式带来了显著的好处,它使你的业务对象不必依赖于事务设施。典型的例子是你不必在代码中导入SpringAPI,事务等。
*在理解Spring的声明式事务管理方面最重要的概念是:Spring的事务管理是通过AOP代理实现的。其中的事务通知由元数据(目前基于XML或注解)驱动。代理对象与事务元数据结合产生了一个AOP代理,它使用一个PlatformTransactionManager实现品配合TransactionInterceptor,在方法调用前后实施事务。
*
*Spring框架的事务基础架构代码将默认地只在抛出运行时和uncheckedexceptions时才标识事务回滚。也就是说,当抛出一个RuntimeException或其子类例的实例时。(Errors也一样-默认地-标识事务回滚。)从事务方法中抛出的Checkedexceptions将不被标识进行事务回滚。
*就是这些默认的设置;严格规定了哪些Exception类型将被标识进行事务回滚。
默认的<tx:advice/>设置如下:
*事务传播设置是REQUIRED
*隔离级别是DEFAULT
*事务是读/写
*事务超时默认是依赖于事务系统的,或者事务超时没有被支持。
*任何RuntimeException将触发事务回滚,但是任何checkedException将不触发事务回滚
Table?9.1.?<tx:method/>有关的设置
属性是否需要?默认值描述name是? 与事务属性关联的方法名。通配符(*)可以用来指定一批关联到相同的事务属性的方法。如:'get*'、'handle*'、'on*Event'等等。propagation不REQUIRED事务传播行为isolation不DEFAULT事务隔离级别timeout不-1事务超时的时间(以秒为单位)read-only不false事务是否只读?rollback-for不? 将被触发进行回滚的Exception(s);以逗号分开。如:'com.foo.MyBusinessException,ServletException'no-rollback-for不? 不被触发进行回滚的Exception(s);以逗号分开。如:'com.foo.MyBusinessException,ServletException'
事务回滚陷阱
清单1.没有回滚支持
@Transactional(propagation=Propagation.REQUIRED)
publicTradeDataplaceTrade(TradeDatatrade)throwsException{
try{
insertTrade(trade);
updateAcct(trade);
returntrade;
}catch(Exceptionup){
//logtheerror
throwup;
}
}
假设帐户中没有足够的资金来购买需要的股票,或者还没有准备购买或出售股票,并抛出了一个受控异常(例如FundsNotAvailableException),那么交易订单会保存在数据库中吗?还是整个逻辑工作单元将执行回滚?答案出乎意料:根据受控异常(不管是在SpringFramework中还是在EJB中),事务会提交它还未提交的所有工作。使用清单13,这意味着,如果在执行updateAcct()方法期间抛出受控异常,就会保存交易订单,但不会更新帐户来反映交易情况。
这可能是在使用事务时出现的主要数据完整性和一致性问题了。运行时异常(即非受控异常)自动强制执行整个逻辑工作单元的回滚,但受控异常不会。因此,清单13中的代码从事务角度来说毫无用处;尽管看上去它使用事务来维护原子性和一致性,但事实上并没有。
尽管这种行为看起来很奇怪,但这样做自有它的道理。首先,不是所有受控异常都是不好的;它们可用于事件通知或根据某些条件重定向处理。但更重要的是,应用程序代码会对某些类型的受控异常采取纠正操作,从而使事务全部完成。例如,考虑下面一种场景:您正在为在线书籍零售商编写代码。要完成图书的订单,您需要将电子邮件形式的确认函作为订单处理的一部分发送。如果电子邮件服务器关闭,您将发送某种形式的SMTP受控异常,表示邮件无法发送。如果受控异常引起自动回滚,整个图书订单就会由于电子邮件服务器的关闭全部回滚。通过禁止自动回滚受控异常,您可以捕获该异常并执行某种纠正操作(如向挂起队列发送消息),然后提交剩余的订单。
使用Declarative事务模式(本系列的第2部分将进行更加详细的描述)时,必须指定容器或框架应该如何处理受控异常。在SpringFramework中,通过@Transactional注释中的rollbackFor参数进行指定,如清单2所示:
清单2.添加事务回滚支持—Spring
@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
publicTradeDataplaceTrade(TradeDatatrade)throwsException{
try{
insertTrade(trade);
updateAcct(trade);
returntrade;
}catch(Exceptionup){
//logtheerror
throwup;
}
}
注意,@Transactional注释中使用了rollbackFor参数。这个参数接受一个单一异常类或一组异常类,您也可以使用rollbackForClassName参数将异常的名称指定为JavaString类型。还可以使用此属性的相反形式(noRollbackFor)指定除某些异常以外的所有异常应该强制回滚。通常大多数开发人员指定Exception.class作为值,表示该方法中的所有异常应该强制回滚。
受控异常就是checkedException,这些异常在你写代码时候必须用try{}catch语句抓住,或者throw抛出,不然代码编译时候就通不过。比如IOException,SqlException,FileNotFoundExcption等等,
而运行时异常是你写代码的时候不需要catch,或者throw就可以通过编译的异常,一般由于程序员的错误引起的,比如NullPointException异常,数组越界异常,这些都是没法在trycatch中恢复的,异常需要程序员细心检查出错误。
而error是继承throwable接口,但和异常是不同的概念,error基本上就是jvm运行时内存耗尽,系统崩溃等等重大的错误,级别高于Exception,而且没法恢复。
另见:
http://www.ibm.com/developerworks/cn/java/j-ts1.html
http://www.javaworld.com.tw/confluence/display/opensrc/Spring
http://www.redsaga.com/spring_ref/2.0/html/transaction.html#transaction-declarative