}
} spring2.5 学习笔记 第36页 共46页
User u = new User(); u.setName(\ + System.currentTimeMillis()); service.add(u); Annotation说明:
(二) Spring事务选项
默认的 @Transactional 设置如下:
? ? ? ? ?
事务传播设置是 PROPAGATION_REQUIRED 使用现有事物,没有则启动新事物 事务隔离级别是 ISOLATION_DEFAULT 事务是 读/写 false
事务超时默认是依赖于事务系统的,或者事务超时没有被支持。
任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚
首先需要在配置文件中,配置事务管理器→告诉Spring需要进行事务管理并指定某个事务管理器→在需要进行事务管理的方法上加上@Transactional就可以了。
@Transactional 注解的属性 属性 传播性propagation 隔离性isolation 只读性readOnly 超时timeout 类型 枚举型:Propagation 枚举型:Isolation 布尔型 int型(以秒为单位) 一组 Class 类的实例,必须是Throwable 的子类 一组 Class 类的名字,必须是Throwable的子类 可选的传播性设置 可选的隔离性级别(默认值:ISOLATION_DEFAULT) 读写型事务 vs. 只读型事务 事务超时 一组异常类,遇到时 必须 进行回滚。默认情况下checked exceptions不进行回滚,仅unchecked exceptions(即RuntimeException的子类)才进行事务回滚。 一组异常类名,遇到时 必须 进行回滚 描述 回滚异常类(rollbackFor) 回滚异常类名(rollbackForClassname) 一组 Class 类的实例,必不回滚异常类(noRollbackFor) 一组异常类,遇到时 必须不 回滚。 须是Throwable 的子类 不回滚异常类名一组 Class 类的名字,必一组异常类,遇到时 必须不 回滚 (noRollbackForClassname) 须是Throwable 的子类
1、 Propagation
key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。有以下选项可供使用:
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。 2、 Isolation Level(事务隔离等级):
1、Serializable:最严格的级别,事务串行执行,资源消耗最大;
spring2.5 学习笔记 第37页 共46页
2、REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
3、READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
4、Read Uncommitted:保证了读取过程中不会读取到非法数据。
隔离级别在于处理多事务的并发问题。我们知道并行可以提高数据库的吞吐量和效率,但是并不是所有的并发事务都可以并发运行,这需要查看数据库教材的可串行化条件判断了。 我们首先说并发中可能发生的3中不讨人喜欢的事情
1: Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
2: non-repeatable reads--数据不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。 3: phantom reads--幻象读数据,这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name=\第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由\改成\,结果取出来了7个数据。
Dirty reads non-repeatable reads phantom reads
Serializable 不会 不会 不会 REPEATABLE READ 不会 不会 会 READ COMMITTED 不会 会 会 Read Uncommitted 会 会 会
3、 readOnly
事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。这是一个最优化提示。在一些情况下,一些事务策略能够起到显著的最优化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)时避免dirty checking(试图“刷新”)。 4、 Timeout
在事务属性中还有定义“timeout”值的选项,指定事务超时为几秒。在JTA中,这将被简单地传递到J2EE服务器的事务协调程序,并据此得到相应的解释。
(三) XML文件形式配置Spring事务管理
注意:理论同annotation是一样,只是一个是使用annotation的注解方式,而另一个是使用xml配置文件形式,大多数使用xml配置文件方式的。方便
理解了annotation的事务管理,xml事务管理也就方便了,只是个配置问题, 步骤如下:
spring2.5 学习笔记 第38页 共46页
com.wjt276.service..*.*(..))\/>
当然了,配置文件中需要引入命名空间了: xmlns:tx=\ xsi:schemaLocation=”http://www.springframework.org/schema/tx a、首先需要定义切入点pointcut:说明哪些地方需要进行事务管理 b、再使用advisor说明在什么的pointcut下,使用什么的事务管理。就可以了。 http://www.springframework.org/schema/tx/spring-tx-2.5.xsd\>
四、 HibernateTemplate
当我们在多处使用相同的代码时,我们是否考虑对这些代码进行封装呢?这是当前的了。 这就需要使用一种设计模式:Template Method(模板模式) 我们来见一个hibernate中最常的事务代码,如下: public void save(User u) { } 注意到没有,这个代码中,如果在有更新session.update()/删除session.delete(),上面的事务管理都需要重写一次代码。重复的代码是非常的多。这时我们就需要对代码进行封装,也可以说使用模板,把重复的地方放入模板上,在需要使用时,只需要传入不同的地方就可以了。在hibernate中就有这样的模板那就是HibernateTemplate (一) HibernateTemplate org.springframework.orm.hibernate3.HibernateTemplate; HibernateTemplate是Hiberante的模板,因为一定需要SessionFactory等与数据库相关的信息了。 因为当前的HibernateTemplate没有setSessionFactory方法,因此其父类具有setSessionFactory方法,并且HibernateTemplate封装了Session的save、update等方法。使用如下: Session session = null; try { } session = sessionFactory.openSession(); session.beginTransaction(); session.save(u); //session.update(u); session.getTransaction().commit(); session.getTransaction().rollback(); e.printStackTrace(); session.close(); } catch (HibernateException e) { } finally { spring2.5 学习笔记 第39页 共46页
import org.springframework.orm.hibernate3.HibernateTemplate; @Component(\) public class UserDaoImpl implements UserDao { 因为HibernateTemplate需要交给Spring来管理,因为也需要配置bean,及注入sessionFactory
package com.wjt276.dao.impl; import javax.annotation.Resource; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.stereotype.Component; @Component public class SuperDao extends HibernateDaoSupport { } 其它的dao继承这个就可以了 LogDaoImpl @Component public class LogDaoImpl extends SuperDao implements LogDao { } UserDaoImpl @Component(\) public class UserDaoImpl extends SuperDao implements UserDao { @Override public void save(User u) { }} this.getHibernateTemplate().save(u); //这里可以直接save了,session已经被hibernateTemplate处理了。我们不需要关心它了。 //因为HibernateTemplate中已经注入了SessionFactory了,因为它自己会处理好session及其事务的。 System.out.println(\); @Override public void save(Log log) { } this.getHibernateTemplate().save(log); //this.save(log); @Resource(name=\) public void setSuperHibernateTemplate(HibernateTemplate hibernateTemplate ){ } //在这里为父类HibernateDaoSuppport注入hibernateTemplate或是sessionFactory super.setHibernateTemplate(hibernateTemplate); System.out.println(\);