事务处理在应用程序中起着至关重要的作用。本篇博客将进入Spring的事务处理学习。下面,首先我们来简单回想一下与事务有关的一些概念。
【事务】
    所谓事务,就是一系列必须成功的操作,只要有一步操作失败,所以其他步骤都将要撤销。当所有的步骤都执行完成后,则该事务提交成功。由于操作中的某一个步骤失败,导致所有的步骤都没有提交,则事务必须回滚,即回到事务前的状态。
【Spring事务概述】
    Spring的事务处理分为编程式事务和声明式事务。它们的实现都是基于AOP机制。通过前面的学习,我们也了解到Spring会默认使用Java的动态代理机制,因为Java的动态代理机制要求其代理的对象必须实现一个接口,并且在该接口中定义准备进行代理的方法。而对于没有实现任何接口的对象,则Spring使用CGLIB实现。
【编程式事务】
    下面以添加用户的时候,记录一条日志为实例,通过编程的方式,添加事务。
用户实体:
package com.bjpowernode.usermgr.domain;
public class User {
    private int id;
    
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
日志实体:
package com.bjpowernode.usermgr.domain;
import java.util.Date;
public class Log {
    private int id;  
    //日志类别,日志一般起到一个不可否认性
    //操作日志、安全日志、事件日志
    private String type;   
    private String detail;    
    private Date time;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getDetail() {
        return detail;
    }
    public void setDetail(String detail) {
        this.detail = detail;
    }
    public Date getTime() {
        return time;
    }
    public void setTime(Date time) {
        this.time = time;
    }
}
Hibernate工具类,管理session:
package com.bjpowernode.usermgr.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
    private static SessionFactory factory;
    private HibernateUtils() {
    }    
    static {
        try {
            Configuration cfg = new Configuration().configure();
            factory = cfg.buildSessionFactory();
        }catch(Exception e) {
            e.printStackTrace();
            throw new java.lang.RuntimeException(e);
        }    
    }
    
    public static SessionFactory getSessionFactory() {
        return factory;
    }
    
    public static Session getSession() {
        return factory.openSession();
    }
    
    public static void closeSession(Session session) {
        if (session != null) {
            if (session.isOpen()) {
                session.close();
            }
        }
    }
}
用户管理,编写事务,添加用户的同时添加一条日志信息:
package com.bjpowernode.usermgr.manager;
import java.util.Date;
import org.hibernate.Session;
import com.bjpowernode.usermgr.domain.Log;
import com.bjpowernode.usermgr.domain.User;
import com.bjpowernode.usermgr.util.HibernateUtils;
public class UserManagerImpl implements UserManager {
    public void addUser(User user) {
        Session session = null;
        try {
            //session = HibernateUtils.getSession();
            //取得session
            session = HibernateUtils.getSessionFactory().getCurrentSession();
            session.beginTransaction();  //开启事务
            //保存用户
            session.save(user);
            //设置日志
            Log log = new Log();
            log.setType("操作日志");
            log.setTime(new Date());
            log.setDetail("XXX");          
            LogManager logManager = new LogManagerImpl(); 
            //保存日志
            logManager.addLog(log);     
            Integer.parseInt("adfsadfdsf");        
            session.getTransaction().commit();  //提交事务
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();  //回滚事务
        //}finally {
        //    HibernateUtils.closeSession(session);
        }
    }
}
OpenSession与GetCurrentSession的区别?
    * openSession必须关闭,currentSession在事务结束后自动关闭
    * openSession没有和当前线程绑定,currentSession和当前线程绑定
如果使用currentSession需要在hibernate.cfg.xml文件中进行配置:
    * 如果是本地事务(jdbc事务)
        <property name="hibernate.current_session_context_class">thread</property>
    * 如果是全局事务(jta事务)
    	<property name="hibernate.current_session_context_class">jta</property>  
【声明式事务】
    在系统中,事务的配置只需要在一个地方即可,所以,可以将事务配置到单独的ApplicationContext配置文件中,如下:
<?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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    <!-- 配置SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
    </bean>
    
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>            
        </property>
    </bean>
    
    <!-- 哪些类哪些方法使用事务 -->
    <aop:config>
        <aop:pointcut id="allManagerMethod" expression="execution(* com.bjpowernode.usermgr.manager.*.*(..))"/>
        <aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice"/>
    </aop:config>
    
    <!-- 事务的传播特性 -->    
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="del*" propagation="REQUIRED"/>
            <tx:method name="modify*" propagation="REQUIRED"/>
            <tx:method name="*" propagation="REQUIRED" read-only="true"/>
        </tx:attributes>
    </tx:advice>
</beans>
用户管理代码,不需要在写事务的开启、提交及回滚的代码,继承spring提供的HibernateDaoSupport:
package com.bjpowernode.usermgr.manager;
import java.util.Date;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.bjpowernode.usermgr.domain.Log;
import com.bjpowernode.usermgr.domain.User;
public class UserManagerImpl extends HibernateDaoSupport implements UserManager {
    private LogManager logManager; 
    public void addUser(User user) throws Exception {
         //this.getSession().save(user);
        this.getHibernateTemplate().save(user);
    
        Log log = new Log();
        log.setType("操作日志");
        log.setTime(new Date());
        log.setDetail("XXX");
 
        logManager.addLog(log); 
        throw new Exception();
    }
    public void setLogManager(LogManager logManager) {
        this.logManager = logManager;
    }
}
在Spring配置文件中,将logmanager和usermanager注入,并将logmanager注入到usermanager中:


<?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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
           
    <bean id="userManager" class="com.bjpowernode.usermgr.manager.UserManagerImpl">
        <property name="sessionFactory" ref="sessionFactory"/>
        <property name="logManager" ref="logManager"/>
    </bean>
    
    <bean id="logManager" class="com.bjpowernode.usermgr.manager.LogManagerImpl">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
</beans>
【总结】
    本篇博客介绍了Spring中的事务处理,其中,编程式事务主要是用Hibernate实现的,我们需要在程序中编写事务的开启、提交及回滚的相关代码;而声明式事务是使用Spring与Hibernate集成实现的,使用此方法,我们可以将系统中的事务配置为一个单独的配置文件,对象通过继承HibernateDaoSupport,可以取得Session,从而在Spring配置文件中,将对象间的关系配置即可,相对来说,更加灵活方便。