在service层控制事务
Spring推荐事务的控制在service层实现,而不是像单独使用hibernate那样,在dao层实现,这样的好处在于更好地支持declear方式的事务(service层通常提供接口,这样可以针对接口来定义事务策略,而不是针对具体的service实现,因此可以很方便地替换service的实现,而不需要修改事务的配置),更加灵活。同时,可以更加方面自然地实现全局事务的控制。
举例如下:
service接口
package
x.y.service;
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
package
x.y.service;
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
throw new UnsupportedOperationException();
}
public Foo getFoo(String fooName, String barName) {
throw new UnsupportedOperationException();
}
public void insertFoo(Foo foo) {
throw new UnsupportedOperationException();
}
public void updateFoo(Foo foo) {
throw new UnsupportedOperationException();
}
}
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
throw new UnsupportedOperationException();
}
public Foo getFoo(String fooName, String barName) {
throw new UnsupportedOperationException();
}
public void insertFoo(Foo foo) {
throw new UnsupportedOperationException();
}
public void updateFoo(Foo foo) {
throw new UnsupportedOperationException();
}
}
spring.xml,注意在声明事务的时候,是针对service接口的,而不是针对service实现的
<?
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:aop ="http://www.springframework.org/schema/aop"
xmlns:tx ="http://www.springframework.org/schema/tx"
xsi:schemaLocation ="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd" >
<!-- this is the service object that we want to make transactional -->
< bean id ="fooService" class ="x.y.service.DefaultFooService" />
<!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
< tx:advice id ="txAdvice" transaction-manager ="txManager" >
<!-- the transactional semantics -->
< tx:attributes >
<!-- all methods starting with 'get' are read-only -->
< tx:method name ="get*" read-only ="true" />
<!-- other methods use the default transaction settings (see below) -->
< tx:method name ="*" />
</ tx:attributes >
</ tx:advice >
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
< aop:config >
< aop:pointcut id ="fooServiceOperation"
expression ="execution(* x.y.service.FooService.*(..))" />
< aop:advisor advice-ref ="txAdvice"
pointcut-ref ="fooServiceOperation" />
</ aop:config >
<!-- don't forget the DataSource -->
< bean id ="dataSource"
class ="org.apache.commons.dbcp.BasicDataSource"
destroy-method ="close" >
< property name ="driverClassName" value ="org.h2.Driver" />
< property name ="url"
value ="jdbc:h2:tcp://localhost/D:/try/data/sample;IFEXISTS=TRUE" />
< property name ="username" value ="sa" />
< property name ="password" value ="123456" />
</ bean >
<!-- similarly, don't forget the PlatformTransactionManager -->
< bean id ="txManager"
class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name ="dataSource" ref ="dataSource" />
</ bean >
<!-- other <bean/> definitions here -->
</ beans >
< beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop ="http://www.springframework.org/schema/aop"
xmlns:tx ="http://www.springframework.org/schema/tx"
xsi:schemaLocation ="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd" >
<!-- this is the service object that we want to make transactional -->
< bean id ="fooService" class ="x.y.service.DefaultFooService" />
<!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
< tx:advice id ="txAdvice" transaction-manager ="txManager" >
<!-- the transactional semantics -->
< tx:attributes >
<!-- all methods starting with 'get' are read-only -->
< tx:method name ="get*" read-only ="true" />
<!-- other methods use the default transaction settings (see below) -->
< tx:method name ="*" />
</ tx:attributes >
</ tx:advice >
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
< aop:config >
< aop:pointcut id ="fooServiceOperation"
expression ="execution(* x.y.service.FooService.*(..))" />
< aop:advisor advice-ref ="txAdvice"
pointcut-ref ="fooServiceOperation" />
</ aop:config >
<!-- don't forget the DataSource -->
< bean id ="dataSource"
class ="org.apache.commons.dbcp.BasicDataSource"
destroy-method ="close" >
< property name ="driverClassName" value ="org.h2.Driver" />
< property name ="url"
value ="jdbc:h2:tcp://localhost/D:/try/data/sample;IFEXISTS=TRUE" />
< property name ="username" value ="sa" />
< property name ="password" value ="123456" />
</ bean >
<!-- similarly, don't forget the PlatformTransactionManager -->
< bean id ="txManager"
class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name ="dataSource" ref ="dataSource" />
</ bean >
<!-- other <bean/> definitions here -->
</ beans >
使用service层方便了使用全局事务
对于横跨多个Hibernate SessionFacotry的分布式事务,只需简单地将 JtaTransactionManager 同多个 LocalSessionFactoryBean 的定义结合起来作为事务策略。你的每一个DAO通过bean属性得到各自的 SessionFactory 引用。在需要进行跨多个数据库的事务操作时,只需要定义一个service层,使用 JtaTransactionManager 作为事务策略,横跨多个DAO和多个session factories来划分事务,而不需要特殊的处理。
示例的配置文件如下:
<
beans
>
< bean id ="mySessionFactory1" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
< property name ="dataSource" ref ="myDataSource1" />
..
</ bean >
< bean id ="mySessionFactory2" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
< property name ="dataSource" ref ="myDataSource2" />
…
</ bean >
< bean id ="myTxManager" class ="org.springframework.transaction.jta.JtaTransactionManager" />
< bean id ="myProductDao" class ="product.ProductDaoImpl" >
< property name ="sessionFactory" ref ="mySessionFactory1" />
</ bean >
< bean id ="myInventoryDao" class ="product.InventoryDaoImpl" >
< property name ="sessionFactory" ref ="mySessionFactory2" />
</ bean >
< aop:config >
< aop:pointcut id ="productServiceMethods" expression ="execution(* product.ProductService.*(..))" />
< aop:advisor advice-ref ="txAdvice" pointcut-ref ="productServiceMethods" />
</ aop:config >
< tx:advice id ="txAdvice" transaction-manager ="myTxManager" >
< tx:attributes >
< tx:method name ="increasePrice*" propagation ="REQUIRED" />
< tx:method name ="someOtherBusinessMethod" propagation ="REQUIRES_NEW" />
< tx:method name ="*" propagation ="SUPPORTS" read-only ="true" />
</ tx:attributes >
</ tx:advice >
< bean class ="product.ProductServiceImpl" >
< property name ="productDao" ref ="myProductDao" />
< property name ="inventoryDao" ref ="myInventoryDao" />
</ bean >
</ beans >
< bean id ="mySessionFactory1" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
< property name ="dataSource" ref ="myDataSource1" />
..
</ bean >
< bean id ="mySessionFactory2" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
< property name ="dataSource" ref ="myDataSource2" />
…
</ bean >
< bean id ="myTxManager" class ="org.springframework.transaction.jta.JtaTransactionManager" />
< bean id ="myProductDao" class ="product.ProductDaoImpl" >
< property name ="sessionFactory" ref ="mySessionFactory1" />
</ bean >
< bean id ="myInventoryDao" class ="product.InventoryDaoImpl" >
< property name ="sessionFactory" ref ="mySessionFactory2" />
</ bean >
< aop:config >
< aop:pointcut id ="productServiceMethods" expression ="execution(* product.ProductService.*(..))" />
< aop:advisor advice-ref ="txAdvice" pointcut-ref ="productServiceMethods" />
</ aop:config >
< tx:advice id ="txAdvice" transaction-manager ="myTxManager" >
< tx:attributes >
< tx:method name ="increasePrice*" propagation ="REQUIRED" />
< tx:method name ="someOtherBusinessMethod" propagation ="REQUIRES_NEW" />
< tx:method name ="*" propagation ="SUPPORTS" read-only ="true" />
</ tx:attributes >
</ tx:advice >
< bean class ="product.ProductServiceImpl" >
< property name ="productDao" ref ="myProductDao" />
< property name ="inventoryDao" ref ="myInventoryDao" />
</ bean >
</ beans >