Spring 事务管理

.3  JDBC事务管理

Spring提供编程式的事务管理(Programmatic transaction manage- ment)与声明式的事务管理(Declarative transaction management),为不同的事务实现提供了一致的编程模型,这节以JDBC事务为例,介绍Spring的事务管理。

5.3.1  Spring对事务的支持

事务是一组原子(Atomic)操作的工作单元,以数据库存取的实例来说,就是一组SQL指令,这一组SQL指令必须全部执行成功,若因为某个原因未全部执行成功(例如其中一行SQL有错误),则先前所有执行过的SQL指令都会被撤消。

举个简单的例子,一个客户从A银行转账至B银行,要作的动作为从A银行的账户扣款、在B银行的账户加上转账的金额,两个动作必须成功,如果有一个动作失败,则此次转账失败。

事务还必须保持所参与资源的一致性(Consistent),例如在银行账户的例子中,两个账户的转账金额,B账户取款的金额不能大于A账户的存款金额。每个事务彼此之间必须是隔离的(Isolated),例如在A账户中可能有两笔事务,同时进行存款与提款的动作,两个事务基本上不需意识到彼此的存在。事务还必须是可持续的(Durable),在某一笔事务之后,这笔事务必须是被记录下来的。

在这里将介绍JDBC如何使用事务管理。首先来看看事务的原子性实现,在JDBC中,可以操作 Connection的setAutoCommit() 方法,给定false参数,在下达一连串的SQL语句后,自行执行Connection的commit()来送出变更,如果中间发生错误,则执行 rollback() 来撤消所有的执行,例如:

try {

    .....

    connection.setAutoCommit(false);

    .....

    // 一连串SQL操作

    connection.commit();

} catch(SQLException) {

    // 发生错误,撤消所有变更

    connection.rollback();

}

在Spring中对JDBC的事务管理加以封装,Spring事务管理的抽象关键在于org.springframework.transaction.PlatformTransactionManager接口的实现:

...

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(TransactionDefinition

                    definition)  throws TransactionException;

    void commit(TransactionStatus status)

                                   throws TransactionException;

    void rollback(TransactionStatus status)

                                   throws TransactionException;

}

PlatformTransactionManager接口有许多具体的事务实现类,例如 DataSourceTransactionManager、HibernateTransactionManager、JdoTransaction- Manager、JtaTransactionManager等,通过依赖于PlatformTransactionManager接口及各种的技术实现,Spring在事务管理上可以让开发人员使用一致的编程模型,即使所使用的是不同的事务管理技术。


5.3.2  JDBC编程事务管理

Spring提供两种方式实现编程式的事务管理,一是直接使用PlatformTransactionManager实现,二是使用org.springframework.transaction.support.TransactionTemplate。

1、先来看看如何使用PlatformTransactionManager,在这里使用它的实现类 DataSourceTransactionManager,

public class UserDAO implements IUserDAO {

    private DataSourceTransactionManager transactionManager;

    private DefaultTransactionDefinition def;

    private JdbcTemplate jdbcTemplate;

   

    public void setDataSource(DataSource dataSource) {

        jdbcTemplate = new JdbcTemplate(dataSource);

        transactionManager =

            new DataSourceTransactionManager(dataSource);

        // 建立事务的定义

        def = new DefaultTransactionDefinition();

        def.setPropagationBehavior(

                TransactionDefinition.PROPAGATION_REQUIRED);

    }

   

    public void insert(User user) {

       String name = user.getName();

       int age = user.getAge().intValue();

      

       TransactionStatus status =

           transactionManager.getTransaction(def);

       try {

           jdbcTemplate.update("INSERT INTO user (name,age) "

                   + "VALUES('" + name + "'," + age + ")");

           // 下面的SQL有错误,用以测试事务

           jdbcTemplate.update("INSER INTO user (name,age) "

                   + "VALUES('" + name + "'," + age + ")");

       }

       catch(DataAccessException e) {

           transactionManager.rollback(status);

           throw e;

       }

       transactionManager.commit(status);

    }

2、另一个实现编程式事务管理的方法是使用TransactionTemplate,它需要一个TransactionManager实例,如下所示:

...

TransactionTemplate transactionTemplate =

        new TransactionTemplate(transactionManager);

...

transactionTemplate.execute(new TransactionCallback() {

    public Object doInTransaction(TransactionStatus status) {

         return jdbcTemplate.update("INSERT INTO user (name,age) "

               + "VALUES('" + name + "'," + age + ")");

    }

});

如果发生了异常,则会进行Rollback,否则提交事务,如果没有回传值,则也可以使用TransactionCallbackWithoutResult:

...

transactionTemplate.execute(

        new TransactionCallbackWithoutResult() {

                public void doInTransactionWithoutResult(

                                TransactionStatus status) {

            .        ...

                }

            });

5.3.3  JDBC声明事务管理

Spring声明式的事务管理依赖它的AOP框架来完成。使用声明事务管理的好处是,事务管理不能侵入您所开发的组件,具体来说,DAO对象不会意识到正在事务管理之中,事实上也应当如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策略的话,也只需要在定义文件中重新配置。

1、一个简单的方法是使用TransactionProxyFactoryBean,指定要介入的事务管理对象及其方法。

第一种方式:每个Bean都有一个代理

<? 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:context
="http://www.springframework.org/schema/context"
    xmlns:aop
="http://www.springframework.org/schema/aop"
    xsi:schemaLocation ="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
>

    
< bean  id ="sessionFactory"   
            class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >   
        
< property  name ="configLocation"  value ="classpath:hibernate.cfg.xml"   />   
        
< property  name ="configurationClass"  value ="org.hibernate.cfg.AnnotationConfiguration"   />
    
</ bean >   

    
<!--  定义事务管理器(声明式的事务)  -->   
    
< bean  id ="transactionManager"
        class
="org.springframework.orm.hibernate3.HibernateTransactionManager" >
        
< property  name ="sessionFactory"  ref ="sessionFactory"   />
    
</ bean >
    
    
<!--  配置DAO  -->
    
< bean  id ="userDaoTarget"  class ="com.bluesky.spring.dao.UserDaoImpl" >
        
< property  name ="sessionFactory"  ref ="sessionFactory"   />
    
</ bean >
    
    
< bean  id ="userDao"   
        class
="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" >   
           
<!--  配置事务管理器  -->   
           
< property  name ="transactionManager"  ref ="transactionManager"   />      
        
< property  name ="target"  ref ="userDaoTarget"   />   
         
< property  name ="proxyInterfaces"  value ="com.bluesky.spring.dao.GeneratorDao"   />
        
<!--  配置事务属性  -->   
        
< property  name ="transactionAttributes" >   
            
< props >   
                
< prop  key ="*" > PROPAGATION_REQUIRED </ prop >
            
</ props >   
        
</ property >   
    
</ bean >   
</ beans >

    第二种方式:所有Bean共享一个代理基类

<? 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:context
="http://www.springframework.org/schema/context"
    xmlns:aop
="http://www.springframework.org/schema/aop"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
>

    
< bean  id ="sessionFactory"   
            class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >   
        
< property  name ="configLocation"  value ="classpath:hibernate.cfg.xml"   />   
        
< property  name ="configurationClass"  value ="org.hibernate.cfg.AnnotationConfiguration"   />
    
</ bean >   

    
<!--  定义事务管理器(声明式的事务)  -->   
    
< bean  id ="transactionManager"
        class
="org.springframework.orm.hibernate3.HibernateTransactionManager" >
        
< property  name ="sessionFactory"  ref ="sessionFactory"   />
    
</ bean >
    
    
< bean  id ="transactionBase"   
            class
="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"   
            lazy-init
="true"  abstract ="true" >   
        
<!--  配置事务管理器  -->   
        
< property  name ="transactionManager"  ref ="transactionManager"   />   
        
<!--  配置事务属性  -->   
        
< property  name ="transactionAttributes" >   
            
< props >   
                
< prop  key ="*" > PROPAGATION_REQUIRED </ prop >   
            
</ props >   
        
</ property >   
    
</ bean >     
   
    
<!--  配置DAO  -->
    
< bean  id ="userDaoTarget"  class ="com.bluesky.spring.dao.UserDaoImpl" >
        
< property  name ="sessionFactory"  ref ="sessionFactory"   />
    
</ bean >
    
    
< bean  id ="userDao"  parent ="transactionBase"   >   
        
< property  name ="target"  ref ="userDaoTarget"   />    
    
</ bean >
</ beans >

2、 您也可以设置不同的拦截器(TransactionInterceptor来得到更多的管理细节

第三种方式:使用拦截器

<? 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:context
="http://www.springframework.org/schema/context"
    xmlns:aop
="http://www.springframework.org/schema/aop"
    xsi:schemaLocation ="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
>

    
< bean  id ="sessionFactory"   
            class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >   
        
< property  name ="configLocation"  value ="classpath:hibernate.cfg.xml"   />   
        
< property  name ="configurationClass"  value ="org.hibernate.cfg.AnnotationConfiguration"   />
    
</ bean >   

    
<!--  定义事务管理器(声明式的事务)  -->   
    
< bean  id ="transactionManager"
        class
="org.springframework.orm.hibernate3.HibernateTransactionManager" >
        
< property  name ="sessionFactory"  ref ="sessionFactory"   />
    
</ bean >  
   
    
< bean  id ="transactionInterceptor"   
        class
="org.springframework.transaction.interceptor.TransactionInterceptor" >   
        
< property  name ="transactionManager"  ref ="transactionManager"   />   
        
<!--  配置事务属性  -->   
        
< property  name ="transactionAttributes" >   
            
< props >   
                
< prop  key ="*" > PROPAGATION_REQUIRED </ prop >   
            
</ props >   
        
</ property >   
    
</ bean >
      
    
< bean  class ="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >   
        
< property  name ="beanNames" >   
            
< list >   
                
< value > *Dao </ value >
             </ list >   
        
</ property >   
        
< property  name ="interceptorNames" >   
            
< list >   
                
< value > transactionInterceptor </ value >   
            
</ list >   
        
</ property >   
    
</ bean >   
  
    
<!--  配置DAO  -->
    
< bean  id ="userDao"  class ="com.bluesky.spring.dao.UserDaoImpl" >
        
< property  name ="sessionFactory"  ref ="sessionFactory"   />
    
</ bean >
</ beans >

3、

第四种方式:使用tx标签配置的拦截器

<? 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:context
="http://www.springframework.org/schema/context"
    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.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
>

    
< context:annotation-config  />
    
< context:component-scan  base-package ="com.bluesky"   />

    
< bean  id ="sessionFactory"   
            class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >   
        
< property  name ="configLocation"  value ="classpath:hibernate.cfg.xml"   />   
        
< property  name ="configurationClass"  value ="org.hibernate.cfg.AnnotationConfiguration"   />
    
</ bean >   

    
<!--  定义事务管理器(声明式的事务)  -->   
    
< bean  id ="transactionManager"
        class
="org.springframework.orm.hibernate3.HibernateTransactionManager" >
        
< property  name ="sessionFactory"  ref ="sessionFactory"   />
    
</ bean >

    
< tx:advice  id ="txAdvice"  transaction-manager ="transactionManager" >
        
< tx:attributes >
            
< tx:method  name ="*"  propagation ="REQUIRED"   />
        
</ tx:attributes >
    
</ tx:advice >
    
    
< aop:config >
        
< aop:pointcut  id ="interceptorPointCuts"
            expression
="execution(* com.bluesky.spring.dao.*.*(..))"   />
        
< aop:advisor  advice-ref ="txAdvice"
            pointcut-ref
="interceptorPointCuts"   />         
    
</ aop:config >       
</ beans >

第五种方式:全注解

<? 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:context
="http://www.springframework.org/schema/context"
    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.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
>

    
< context:annotation-config  />
    
< context:component-scan  base-package ="com.bluesky"   />

    
< tx:annotation-driven  transaction-manager ="transactionManager" />

    
< bean  id ="sessionFactory"   
            class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >   
        
< property  name ="configLocation"  value ="classpath:hibernate.cfg.xml"   />   
        
< property  name ="configurationClass"  value ="org.hibernate.cfg.AnnotationConfiguration"   />
    
</ bean >   

    
<!--  定义事务管理器(声明式的事务)  -->   
    
< bean  id ="transactionManager"
        class
="org.springframework.orm.hibernate3.HibernateTransactionManager" >
        
< property  name ="sessionFactory"  ref ="sessionFactory"   />
    
</ bean >
    
</ beans >

此时在DAO上需加上@Transactional注解,如下:

package  com.bluesky.spring.dao;

import  java.util.List;

import  org.hibernate.SessionFactory;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import  org.springframework.stereotype.Component;

import  com.bluesky.spring.domain.User;

@Transactional
@Component(
" userDao " )
public   class  UserDaoImpl  extends  HibernateDaoSupport  implements  UserDao {

    
public  List < User >  listUsers() {
        
return   this .getSession().createQuery( " from User " ).list();
    }
    
    
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值