采用编程式事务 事务主要分为:编程式事务和声明式事务 1、SessionFactory.getCurrentSession()和SessionFactory.openSession()的区别? * 如果是SessionFactory.getCurrentSession()来创建session,在commit后session就 自动关闭了,也就是不用再session.close()了 * 如果使用的是SessionFactory.openSession()必须显示的关闭session,因为commit后不会关闭 参见:HIBERNATE_HOME/doc/tutorial下的项目 2、SessionFactory.getCurrentSession()的配置,需要在hibernate.cfg.xml文件中加入,如下配置: *本地事务jdbc事务 <property name="hibernate.current_session_context_class">thread</property> *全局事务jta事务 <property name="hibernate.current_session_context_class">jta</property>
关于Hibernate的编程式事务,我们以增加用户的同时向数据库插入日志为例说明。
主要代码如下:
package com.bjsxt.usermgr; import com.bjsxt.usermgr.manager.UserManager; import com.bjsxt.usermgr.manager.UserManagerImpl; import com.bjsxt.usermgr.model.User; public class UserMangerTest { public static void main(String[] args) { User user = new User(); user.setName("张三"); UserManager userManager = new UserManagerImpl(); userManager.addUser(user); } }
package com.bjsxt.usermgr.manager; import java.util.Date; import org.hibernate.Session; import com.bjsxt.usermgr.model.Log; import com.bjsxt.usermgr.model.User; import com.bjsxt.usermgr.util.HibernateUtils; public class UserManagerImpl implements UserManager { public void addUser(User user) { Session session = null; try { //session = HibernateUtils.getSession(); session = HibernateUtils.getSessionFactory().getCurrentSession(); session.beginTransaction(); //持久化user session.save(user); Log log = new Log(); //log.setType("安全日志"); log.setType(null); log.setDetail("xxx用户尝试登录。。。"); log.setTime(new Date()); LogManager logManager = new LogManagerImpl(); logManager.addLog(log); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } } }
package com.bjsxt.usermgr.manager; import org.hibernate.Session; import com.bjsxt.usermgr.model.Log; import com.bjsxt.usermgr.util.HibernateUtils; public class LogManagerImpl implements LogManager { public void addLog(Log log) { Session session = HibernateUtils.getSessionFactory().getCurrentSession(); session.save(log); } }
注意上面我们使用了getCurrentSession,所以没用显式调用closeSession方法关闭session.
当增加用户的时候将插入一条数据到user表,而同时加入一条日志到log表。
那么当log.setType(null);时因为type字段不能为空,所以按编程式事务将不会在user,log表中的任何一个插入数据。即发生回滚。
具体代码见spring_hibernate_1项目。
下面我们使用spring的声明式事务来对上面代码进行改进。
显然我们将要集成spring与hibernate.
配置方法:
集成spring和hibernate * 把hibernate和spring的包引入 * 声明式事务的配置 --配置SessionFactory --配置事务管理器 --配置事务的传播特性 --配置哪些类的哪些方法进行事务管理 * 继承HibernateDaoSupport类,使用HibernateTemplate这个类来持久化数据,HibernateTemplate类 实际上是session的封装 * 默认回滚异常是RuntimException,即运行时异常,普通异常不回滚 * 在编写异常时最好一直向上抛出,有呈现层处理 * spring的事务管理需要添加在业务逻辑方法上,不要添加到DAO上
按照上面方法我们对spring_hibernate_1项目进行改进。
首先我们引入spring所需类库:我的自定义spring库里有:spring.jar,log4j-1.2.15.jar, common-logging.jar, aspectjrt.jar, aspectjweaver.jar, cglib-nodep-2.1.3.jar
第二步进行声明式事务的配置:
我们新建一个spring的配置文件applicationContext-common.xml
内容如下:
<?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.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" > <!-- 配置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="sessionFactory"></property> </bean> <!-- 配置事务传播特性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice> <!-- 配置哪些类的方法进行事务管理 --> <aop:config> <aop:pointcut expression="execution(* com.bjsxt.usermgr.manager.*.*(..))" id="addManagerMethod"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="addManagerMethod"/> </aop:config> </beans>
第三步,我们把Dao层UserManagerImpl,LogManagerImpl继承HibernateDaoSupport,并利用getHibernateTemplate方法来获得session,对UserManagerImpl增加属性logManager,并通过ioc设置属性。
package com.bjsxt.usermgr.manager; import java.util.Date; import org.hibernate.Session; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import com.bjsxt.usermgr.model.Log; import com.bjsxt.usermgr.model.User; import com.bjsxt.usermgr.util.HibernateUtils; public class UserManagerImpl extends HibernateDaoSupport implements UserManager { private LogManager logManager; public void addUser(User user) { this.getHibernateTemplate().save(user); Log log = new Log(); // log.setType("安全日志"); log.setType(null); log.setDetail("xxx用户尝试登录。。。"); log.setTime(new Date()); logManager.addLog(log); } public void setLogManager(LogManager logManager) { this.logManager = logManager; } }
package com.bjsxt.usermgr.manager; import org.hibernate.Session; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import com.bjsxt.usermgr.model.Log; import com.bjsxt.usermgr.util.HibernateUtils; public class LogManagerImpl extends HibernateDaoSupport implements LogManager { public void addLog(Log log) { this.getHibernateTemplate().save(log); } }
第四步:创建另一个配置文件applicationContext-beans.xml
<?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.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" > <bean id="logManager" class="com.bjsxt.usermgr.manager.LogManagerImpl"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <bean id="userManager" class="com.bjsxt.usermgr.manager.UserManagerImpl"> <property name="logManager" ref="logManager"></property> <property name="sessionFactory" ref="sessionFactory"></property> </bean> </beans>
测试类:
package com.bjsxt.usermgr; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.bjsxt.usermgr.manager.UserManager; import com.bjsxt.usermgr.model.User; public class UserMangerTest { public static void main(String[] args) { User user = new User(); user.setName("张三"); ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext-*.xml"); UserManager userManager = (UserManager)act.getBean("userManager"); userManager.addUser(user); } }
测试插入成功,然后将log.setType("安全日志");改为 log.setType(null);,看是否有事务回滚。
具体代码见spring_hibernate_3.rar