在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);
}

 


一个service实现

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();
    }
}

 

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 >

 

使用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 >