在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>