local="sessionFactory"I>
下面是采用TransactionTemplate和HibemateTemplate的事务操作代码:
publicclassTransactionTest
{
publicstaticvoidmain(String[]args)
{
/I因为并未在web应用中测试,故需要手动创建Spring的上下文
finalApplicationContextctx=
newFileSystemXrnlApplicationContext("bean.xml");
II获得Spring上下文的事务管理器
PlatformTransactionManagertransactionManager=
(PlatformTransactionManager)ctx.getBean("transactionManager");
finalSessionFactorysessionFactory=
(SessionFactory)ctx.getBean("sessionFactory");
/I以事务管理器实例为参数,创建TransactionTemplate对象
TransactionTemplatett=newTransactionTemplate(transactionManager);
II设置TransactionTemplate的事务传播属性
tt.setPropagationBehavior(TransactionDef工nition.PROPAGATION_REQUlRED);
II执行TransactionTemplate的execute方法,该方法需要TransactionCallback实例tt.execute(newTransactionCallbackW工thoutResult()
II采用TransactionCallbackWithoutResult匿名内部类的形式执行
protectedvoiddolnTransactionWithoutResult(TransactionStatusts)
try
{
以SessionFactory实例为参数创建HibernateTemplate
HibernateTemplatehibernateTemplate=
newHibernateTemplate(sessionFactory);
MyTestpl=丑ewMyTest("Jack");
II保存第一个实例
hibernateTemplate.save(pl);
II让下面的数据库操作抛出异常即可看出事务效果。
前面的操作也
II不会生效
MyTestp2=newMyTest("Jack");
II保存第二个实例,可将Person的name属性设为标识属性,并
II引起主键重复的异常,可看出前一条记录也不会加入数据库中
hibernateTemplate.save(p2);
}
catch(Exceptione)
{
ts.setRollbackOnly();
}).,
查看数据库的mytable表,该表中没有任何记录(如果没有采用事务,第一条记录应该可以进去。
而两次保存记录放在doInTransactionWithoutResult方法中执行),因为该方法的方法体具有事务性,该方法的数据库操作要么全部生效,要么全部失效。
由于第二条记录违反了数据库的主键约束,因此,记录全部失效。
声明式事务管理
通常建议采用声明式事务管理。
声明式事务管理的优势非常明显,代码中无须关注事务逻辑,由Spring声明式事务管理负责事务逻辑:
声明式事务管理无须与具体的事务逻辑糯合,可以方便地在不同事务逻辑之间切换。
声明式事务管理的配置方式通常有如下四种。
使用TransactionProxyFactoryBean为目标bean生成事务代理的配置。
此方式最传统,但配置文件膝肿,难以阅读。
采用bean继承的事务代理配置方式比较简沽,但依然是增量式配置。
使用BeanNameAutoProxyCreator,根据beanname自动生成事务代理的方式,这是直接利用Spring的AOP框架配置事务代理的方式,需要对Spring的AOP框架有所理解,但这种方式避免了增量式配置,效果非常不错。
?
DefaultAdvisorAutoProxyCreator:
这也是直接利用Spring的AOP框架配置事务代理的方式,效果也非常不错,只是这种配置方式的可读性不如第三种方式。
1.利用TransactionProxyFactoryBean生成事务代理
采用这种方式的配置时,其配置文件的增加非常快,每个bean有需要两个bean配置一个目标,另外还需要使用TransactionProxyFactoryBean配置一个代理bean。
这是一种最原始的配置方式,下面是使用TransactionProxyFactoryBean的配置文件:
xmlversion="1.0"encoding="gb2312"?
>
<'一Spring配置文件的文件头,包含DTD等信息->
DOCTYPEbeansPUBL工C"-//SPRING//DTDBEAN//EN"
''http:
//www.springframework.org/dtd/spring-beans.dtd''>
一定义数据源>
DriverManagerDataSource">
一定义数据库驱动-->
com.mysql.jdbc.Driver
value>
定义数据库url-->
jdbc:
mysql:
//localhost:
3306/s工pnrg
value>
一定义数据库用户名>
root
<1--定义数据库密码一〉
32147
<'定义一个hibernate的SessionFactory-->
LocalSessionFactoryBean">
一定义SessionFactory必须注入DataSource-->
<1--以下用来列出所有的PO映射文件一〉
Person.hbm.xml
一此处用来定义hibernate的SessionFactory的属性:
不同数据库连接启动时选择create.update.create-drop-->
org.hibernate.dialect.
MySQLDialect
update
一定义事务管理器,适用于Hibernte的事务管理器一〉
class="org.springframework.口o口.hibernate3.HibernateTransactihoManager">
--HibernateTransactiohManagerbean需要依赖注入一个
SessionFactorybean的引用-->
property>
一定义DAOBean,作为事务代理的目标一〉
一为DAObean注入SessionFactory引用一〉
property>
一定义DAObean的事务代理>
TransactionProxyFactoryBean">
一为事务代理bean注入事务管理器一〉
/>
<'设置事务属性>
--所有以f工口d开头的方法,采用required的事务策略,并且只读…〉
PROPAGATION_REQU工RED,readOnly
…其他方法,采用required的事务策略->
PROPAGATION_REQUIRED
<'一为事务代理bean设置目标bean一〉
在上面的配置文件中,personDao需要配置两个部分:
一个是personDao的目标bean,该目标bean是实际DAObean,以实际的DAObean为目标,建立事务代理;另一个是组件,需要一个目标bean和一个事务代理来组成。
但这种配置方式还有一个缺点:
目标bean直接暴露在Spring容器中,可以直接引用,如果目标bean被误引用,将导致业务操作不具备事务性。
为了避免这种现象,可将目标bean配置成嵌套bean,~面是目标bean和事务代理的配置代码:
定义DAObean的事务代理一〉
TransactionProxyFactoryBean">
一为事务代理bean注入事务管理器>
>
一设置事务属性>
--所有以find开头的方法,采用required的事务策略,并且只读一〉
PROPAGAT工ON_REQUIRED,readOnly
其他方法,采用required的事务策略->
PROPAGATION_REQUIRED
一为事务代理bean设置目标bean-->
<'采用嵌套bean配置目标bean-->
一为DAObean注入SessionFactory引用一〉
2.利用继承简化配置
大部分情况下,每个事务代理的事务属性大同小异,事务代理的实现类都T是ransactionProxyFactoryBean,事务代理bean都必须注入事务管理器。
对于这种情况,Spring提供了bean与bean之间的继承,可以简化配置。
将大部分通用的配置,配置成事务模板,而实际的事务代理bean,则继承事务模板。
这种配置方式可以减少部分配置代码。
下面是采用继承的配置文件:
xmlversion="l.O"encoding="gb2312"?
>
--Spring配置文件的文件头,包含DTD等信息一〉
DOCTYPEbeansPUBLIC"-//SPR工NG//DTDBEAN//EN"
''http:
//www.springframework.org/dtd/spring-beans.dtd''>
一定义数据源二〉
DrJ.verManagerDataSource">
--定义数据库驱动一〉
com.mysql.jdbc.Driver
value>
--定义数据库url-->
jdbc:
mysql:
//localhost:
3306/spring
value>
-定义数据库用户名…〉
root
<1--定义数据库密码一〉
32147
--定义一个hibernate的SessionFactory-->
LocalSessionFactoryBean">
--定义Sess工onFactory必须注入DataSource-->
--以下用来列出所有的PO映射文件一〉
Person.hbm.xml
1工st>