hibernate4整合spring3事务问题



hibernate4整合spring3事务问题 对s2sh进行了基本的整合搭建以后,就是对事务的控制管理,将hibernate的事务交由spring管理。根据网上资料,applicationContext.xml中基本的配置如下(注意先后顺序的问题):

 

 

  1. <?xml version=”1.0″ encoding=”UTF-8″?>
  2. <beans xmlns=”http://www.springframework.org/schema/beans”
  3.        xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
  4.        xmlns:p=”http://www.springframework.org/schema/p”
  5.        xmlns:aop=”http://www.springframework.org/schema/aop”
  6.        xmlns:tx=”http://www.springframework.org/schema/tx”
  7.        xsi:schemaLocation=”
  8.           http://www.springframework.org/schema/beans
  9.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  10.           http://www.springframework.org/schema/aop
  11.           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  12.           http://www.springframework.org/schema/tx
  13.           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   ”>
  14. <!– 配置数据源 Hibernate支持  –>
  15.     <bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource” >
  16.         <property name=”driverClassName” value=”oracle.jdbc.driver.OracleDriver”/>
  17.         <property name=”username” value=”scott” />
  18.         <property name=”password” value=”tiger” />
  19.         <property name=”url” value=”jdbc:oracle:thin:@localhost:1521:myorcl” />
  20.     </bean>
  21.     <!–     class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean”>–>
  22.     <bean id=”sessionFactory”
  23.             class=”org.springframework.orm.hibernate4.LocalSessionFactoryBean” >
  24.         <property name=”dataSource”>
  25.             <ref bean=”dataSource” />
  26.         </property>
  27.         <property name=”hibernateProperties”>
  28.             <props>
  29.                 <prop key=”hibernate.dialect”>
  30.                     org.hibernate.dialect.Oracle9Dialect
  31.                 </prop>
  32.                 <prop key=”hibernate.show_sql”>true</prop>
  33.                 <prop key=”hibernate.temp.use_jdbc_metadata_defaults”>false</prop>
  34.             </props>
  35.         </property>
  36.         <property name=”mappingResources”>
  37.             <list>
  38.                 <value>com/neusoft/leehom/model/Emp.hbm.xml</value>
  39.                 <value>com/neusoft/leehom/model/Dept.hbm.xml</value>
  40.             </list>
  41.         </property>
  42.     </bean>
  43.      <!– 事务管理器 –>
  44.     <bean id=”transactionManager”
  45.     class=”org.springframework.orm.hibernate4.HibernateTransactionManager”>
  46.         <property name=”sessionFactory” ref=”sessionFactory”></property>
  47.     </bean>
  48.     <!– 配置那些类的方法进行事务管理,需要aopalliance-1.0.jar和aspectjweaver.jar,当前com.neusoft.leehom.service包中的子包,
  49.                        类中所有方法需要,还需要参考tx:advice的设置 –>
  50.     <!– 需要引入tx的命名空间 –>
  51.     <!– 这是事务通知操作,使用的事务管理器引用自 transactionManager –>
  52.     <tx:advice id=”txAdvice” transaction-manager=”transactionManager”>
  53.         <tx:attributes>
  54.          <!– 指定哪些方法需要加入事务,这里懒惰一下全部加入,可以使用通配符来只加入需要的方法 –>
  55.             <tx:method name=”insert*” propagation=”REQUIRED” />
  56.             <tx:method name=”update*” propagation=”REQUIRED” />
  57.             <tx:method name=”delete*” propagation=”REQUIRED” />
  58.             <tx:method name=”get*” propagation=”REQUIRED” read-only=”true”/>
  59.             <tx:method name=”query*” propagation=”REQUIRED” read-only=”true”/>
  60.             <tx:method name=”*” propagation=”REQUIRED” />
  61.         </tx:attributes>
  62.     </tx:advice>
  63.     <!– 需要引入aop的命名空间 –>
  64.     <aop:config>
  65.         <!– 切入点指明了在执行Service的所有方法时产生事务拦截操作 –>
  66.         <aop:pointcut id=”daoMethods” expression=”execution(* com.neusoft.leehom.service.impl.*.*(..))” />
  67.         <!– 定义了将采用何种拦截操作,这里引用到 txAdvice –>
  68.         <aop:advisor advice-ref=”txAdvice” pointcut-ref=”daoMethods” />
  69.     </aop:config>
  70. </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:p="http://www.springframework.org/schema/p"  
       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-3.0.xsd


http://www.springframework.org/schema/aop


http://www.springframework.org/schema/aop/spring-aop-3.0.xsd


http://www.springframework.org/schema/tx

          http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   ">

<!--	配置数据源 Hibernate支持  -->
	<bean id="dataSource" >
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="username" value="scott" />
		<property name="password" value="tiger" />
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:myorcl" />
	</bean>
	<!--		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">-->
	<bean id="sessionFactory" 
            >
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    org.hibernate.dialect.Oracle9Dialect
                </prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
            </props>
        </property>
        <property name="mappingResources">
            <list>
                <value>com/neusoft/leehom/model/Emp.hbm.xml</value>
                <value>com/neusoft/leehom/model/Dept.hbm.xml</value>
            </list>
        </property>
	</bean>    
	 <!-- 事务管理器 -->
    <bean id="transactionManager" 
   >
    	<property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    <!-- 配置那些类的方法进行事务管理,需要aopalliance-1.0.jar和aspectjweaver.jar,当前com.neusoft.leehom.service包中的子包,
                       类中所有方法需要,还需要参考tx:advice的设置 -->
    <!-- 需要引入tx的命名空间 -->
	<!-- 这是事务通知操作,使用的事务管理器引用自 transactionManager -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
         <!-- 指定哪些方法需要加入事务,这里懒惰一下全部加入,可以使用通配符来只加入需要的方法 -->
			<tx:method name="insert*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="delete*" propagation="REQUIRED" />
			<tx:method name="get*" propagation="REQUIRED" read-only="true"/>
			<tx:method name="query*" propagation="REQUIRED" read-only="true"/>
			<tx:method name="*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice> 
	<!-- 需要引入aop的命名空间 -->
	<aop:config>
		<!-- 切入点指明了在执行Service的所有方法时产生事务拦截操作 -->
		<aop:pointcut id="daoMethods" expression="execution(* com.neusoft.leehom.service.impl.*.*(..))" />	
		<!-- 定义了将采用何种拦截操作,这里引用到 txAdvice -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="daoMethods" />
	</aop:config>         
</beans>

 

 

 

配置事务时应该加载aopalliance-1.0.jar和aspectjweaver.jar这两个包,这两个包是必须的。以为这样就可以对事务进行控制了,但是没有想到在测试的时候发现dao层中的save、delete等方法都不能进行持久化。最终发现是取到的session不能为sessionFactory.openSession(),而是应该为sessionFactory.getCurrentSession().同时应该在配置为文件中的propagation传播方式最好为required。这是因为当有一个方法list 传播行为为Supports,当在另一个方法getPage()(无事务)调用list方法时会抛出org.hibernate.HibernateException: No Session found for current thread 异常。

 

根本原因是getCurrentSession()在没有session的情况下不会自动创建一个,因此最好的解决方案是使用REQUIRED的传播行为。

 

现在知道事务的配置了,下面来看一下怎么使用事务管理。

 

dao层部分代码:

 

 

 

  1. package com.neusoft.leehom.dao;
  2. public class EmpDAO  {
  3.     private static final Logger log = LoggerFactory.getLogger(EmpDAO.class);
  4.     // property constants
  5.     public static final String ENAME = ”ename”;
  6.     public static final String JOB = ”job”;
  7.     public static final String MGR = ”mgr”;
  8.     public static final String SAL = ”sal”;
  9.     public static final String COMM = ”comm”;
  10.         private SessionFactory sessionFactory;
  11.     public Session getSession() {
  12.         return sessionFactory.getCurrentSession();
  13.     }
  14.     public SessionFactory getSessionFactory() {
  15.         return sessionFactory;
  16.     }
  17.     public void setSessionFactory(SessionFactory sessionFactory) {
  18.         this.sessionFactory = sessionFactory;
  19.     }
  20.     public void save(Emp transientInstance) {
  21.         log.debug(“saving Emp instance”);
  22.         try {
  23.             Session session = getSession();
  24.             session.save(transientInstance);
  25.             log.debug(“save successful”);
  26.         } catch (RuntimeException re) {
  27.             log.error(“save failed”, re);
  28.             throw re;
  29.         }
  30.     }
  31.     public void delete(Emp persistentInstance) {
  32.         log.debug(“deleting Emp instance”);
  33.         try {
  34.             Session session = getSession();
  35.             session.delete(persistentInstance);
  36.             log.debug(“delete successful”);
  37.         } catch (RuntimeException re) {
  38.             log.error(“delete failed”, re);
  39.             throw re;
  40.         }
  41.     }
  42. ……….
  43. }

 

package com.neusoft.leehom.dao;
public class EmpDAO  {
	private static final Logger log = LoggerFactory.getLogger(EmpDAO.class);
	// property constants
	public static final String ENAME = "ename";
	public static final String JOB = "job";
	public static final String MGR = "mgr";
	public static final String SAL = "sal";
	public static final String COMM = "comm";

        private SessionFactory sessionFactory;

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public void save(Emp transientInstance) {
		log.debug("saving Emp instance");
		try { 
			Session session = getSession(); 
			session.save(transientInstance);		
			log.debug("save successful");
		} catch (RuntimeException re) {
			log.error("save failed", re);
			throw re;
		}
	}

	public void delete(Emp persistentInstance) {
		log.debug("deleting Emp instance");
		try {
			Session session = getSession(); 
			session.delete(persistentInstance);
			log.debug("delete successful");
		} catch (RuntimeException re) {
			log.error("delete failed", re);
			throw re;
		}
	}
..........
}

service层部分代码:

 

 


 

 

  1. package com.neusoft.leehom.service.impl;
  2. public class EmpManagerImpl implements IEmpManager {
  3.     private EmpDAO empDao;
  4.     /**
  5.      * 查询所有的数据信息
  6.      */
  7.     public List queryAll() {
  8.         return empDao.findAll();
  9.     }
  10.     /**
  11.      * 插入数据
  12.      */
  13.     public void insertEmp(Emp emp){
  14.         empDao.save(emp);
  15.     }
  16.     /**
  17.      * 删除数据
  18.      */
  19.     public void deleteEmp(short id) {
  20.         Emp emp = empDao.findById(id);
  21.         empDao.delete(emp);
  22.     }
  23.     public void setEmpDao(EmpDAO empDao) {
  24.         this.empDao = empDao;
  25.     }
  26. …….
  27. }

 

package com.neusoft.leehom.service.impl;
public class EmpManagerImpl implements IEmpManager {
	private EmpDAO empDao;
	/**
	 * 查询所有的数据信息
	 */
	public List queryAll() {
		return empDao.findAll();
	}
	/**
	 * 插入数据
	 */
	public void insertEmp(Emp emp){		
		empDao.save(emp);
	}
	/**
	 * 删除数据
	 */
	public void deleteEmp(short id) {
		Emp emp = empDao.findById(id);
		empDao.delete(emp);
	}
	public void setEmpDao(EmpDAO empDao) {
		this.empDao = empDao;
	}
.......
}

action层部分代码:

 

 

  1. package com.neusoft.leehom.action;
  2. public class EmpAction extends ActionSupport {
  3.     private IEmpManager empManager;
  4.     private List list;
  5.     private String message;
  6.     private Emp emp;
  7.     /**
  8.      * 查询所有记录
  9.      * @return
  10.      */
  11.     public String showList(){
  12.         list = empManager.queryAll();
  13.         message = new String(“shuju来说”);
  14.         //System.out.println(list);
  15.         return new String(“ok”);
  16.     }
  17.     /**
  18.      * 删除数据
  19.      * @return
  20.      */
  21.     public String delete(){
  22.         System.out.println(emp.getEmpno());
  23.         if(emp.getEmpno()!=null && !”".equals(emp.getEmpno())){
  24.             empManager.deleteEmp(emp.getEmpno());
  25.         }
  26.         return new String(“delete_ok”);
  27.     }
  28.     /**
  29.      * 修改数据
  30.      * @return
  31.      */
  32.     public String update(){
  33.         System.out.println(emp.getEmpno());
  34.         empManager.updateEmp(emp.getEmpno());
  35.         return new String(“update”);
  36.     }
  37.     /**
  38.      * 插入数据
  39.      * @return
  40.      */
  41.     public String insert(){
  42.         System.out.println(emp.getEname()+”–”+emp.getEmpno());
  43.         empManager.insertEmp(emp);
  44.         return new String(“insert_ok”);
  45.     }
  46. ……..
  47. }

 

package com.neusoft.leehom.action;
public class EmpAction extends ActionSupport {
	private IEmpManager empManager;
	private List list;
	private String message;
	private Emp emp;
	/**
	 * 查询所有记录
	 * @return
	 */
	public String showList(){
		list = empManager.queryAll();
		message = new String("shuju来说");
		//System.out.println(list);
		return new String("ok");
	}
	/**
	 * 删除数据
	 * @return
	 */
	public String delete(){
		System.out.println(emp.getEmpno());
		if(emp.getEmpno()!=null && !"".equals(emp.getEmpno())){
			empManager.deleteEmp(emp.getEmpno());
		}
		return new String("delete_ok");
	}
	/**
	 * 修改数据
	 * @return
	 */
	public String update(){
		System.out.println(emp.getEmpno());
	    empManager.updateEmp(emp.getEmpno());
		return new String("update");
	}
	/**
	 * 插入数据
	 * @return
	 */
	public String insert(){
		System.out.println(emp.getEname()+"--"+emp.getEmpno());
		empManager.insertEmp(emp);
		return new String("insert_ok");
	}
........	
}

applicationContext.xml配置文件后面增加如下代码:

 

 

  1. <bean name=”empDao” class=”com.neusoft.leehom.dao.EmpDAO” >
  2.         <property name=”sessionFactory”>
  3.          <ref bean=”sessionFactory” />
  4.     </property>
  5. </bean>
  6. <bean name=”empManager” class=”com.neusoft.leehom.service.impl.EmpManagerImpl”>
  7.         <property name=”empDao” ref=”empDao”></property>
  8. </bean>
  9. <bean id=”empAction” class=”com.neusoft.leehom.action.EmpAction” >
  10.         <property name=”empManager” ref=”empManager”></property>
  11. </bean>

 

<bean name="empDao" >
     	<property name="sessionFactory">
	     <ref bean="sessionFactory" />
	</property>
</bean>
<bean name="empManager">
        <property name="empDao" ref="empDao"></property>
</bean>    
<bean id="empAction" >
        <property name="empManager" ref="empManager"></property>
</bean>


struts.xml的部分配置内容如下:

 

 

 

 

  1. <package name=”my” namespace=”/” extends=”struts-default”>
  2.         <action name=”*_emp” class=”empAction” method=”{1}”>
  3.             <result name=”ok”>/show.jsp</result>
  4.             <result name=”insert_ok”>/insert.jsp</result>
  5.             <result name=”delete_ok”>/delete.jsp</result>
  6.             <result name=”update_ok”>/update.jsp</result>
  7.         </action>
  8. </package>

 

<package name="my" namespace="/" extends="struts-default">
    	<action name="*_emp" method="{1}">
    		<result name="ok">/show.jsp</result>
    		<result name="insert_ok">/insert.jsp</result>
    		<result name="delete_ok">/delete.jsp</result>
    		<result name="update_ok">/update.jsp</result>
    	</action>
</package>

注意:struts也是交与spring管理,如上的struts.xml中的class=“empAction”,会到spring的配置文件找id为empAction的bean,从而找到具体的实现类。