博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hibernate整合进spring后的事务处理
阅读量:4550 次
发布时间:2019-06-08

本文共 8896 字,大约阅读时间需要 29 分钟。

单独使用hibernate处理事务

  本来只用hibernate开发,从而可以省了DAO层实现数据库访问和跨数据库,也可以对代码进行更好的封装,当我们web中单独使用hibernate时,我们需要单独的处理hibernate的事务,我是使用filter来对事务进行控制的:

  单独使用hibernate使用filter进行事务控制:

01 public class HibernateSessionFilter implements Filter {  
02    
03     public void destroy() {  
04            
05     }  
06    
07     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,  
08             ServletException {  
09         Session session = HibernateUtils.openSession();  
10         Transaction tx = null;  
11         try {  
12             tx = session.beginTransaction();  
13             chain.doFilter(request, response);  
14             tx.commit();  
15         } catch (Exception e) {  
16             if (tx != null) {  
17                 tx.rollback();  
18             }  
19             throw new RuntimeException(e);  
20         } finally {  
21             HibernateUtils.closeAndRemoveSession();  
22         }  
23     }  
24    
25     public void init(FilterConfig arg0) throws ServletException {  
26     }  
27    
28 } 

  web.xml

01 <filter>  
02   <filter-name>hibernateSessionFilter</filter-name>  
03   <filter-class> syx.jpkc.filter.HibernateSessionFilter</filter-class>  
04 </filter>  
05 <filter-mapping>  
06   <filter-name>hibernateSessionFilter</filter-name>  
07   <url-pattern>*.syx</url-pattern>  
08   <url-pattern>*.jsp</url-pattern>  
09   <url-pattern>*.eve</url-pattern>  
10 </filter-mapping> 

   我主要在servlet(*.syx,*.eve)和jsp页面(没用struts)需要和数据库操作,所以需要使用事务处理。

  上面我们还用到了一个 HibernateUtils的小工具类,主要为了获取Session对象和一点优化:

  HibernateUitls.java

01 public class HibernateUtils {  
02     private static Map<Thread, Session> sessionMap;  
03     private static SessionFactory sessionFactory;  
04     static {  
05         sessionMap = new HashMap<Thread, Session>();  
06         sessionFactory = new Configuration().configure().buildSessionFactory();  
07     }  
08    
09     /**  
10      * can only use in web filter, beause it should remove and clear resources  
11      * @return  
12      */ 
13     public static Session openSession() {  
14         System.out.println(Thread.currentThread().getStackTrace()[1] + " run in " + new Date());  
15         Session session = sessionMap.get(Thread.currentThread());  
16         if (session == null) {  
17             session = sessionFactory.openSession();  
18             sessionMap.put(Thread.currentThread(), session);  
19         }  
20         return session;  
21     }  
22     public static Session getCurrentSession() {  
23         return sessionMap.get(Thread.currentThread());  
24     }  
25    
26     public static void closeAndRemoveSession() {  
27         System.out.println(Thread.currentThread().getStackTrace()[1]+ " run in " + new Date());//  
28         Session session = sessionMap.remove(Thread.currentThread());  
29         if (session != null) {  
30             session.close();  
31         }  
32     }  
33 } 
01 public class HibernateUtils {  
02     private static Map<Thread, Session> sessionMap;  
03     private static SessionFactory sessionFactory;  
04     static {  
05         sessionMap = new HashMap<Thread, Session>();  
06         sessionFactory = new Configuration().configure().buildSessionFactory();  
07     }  
08    
09     /**  
10      * can only use in web filter, beause it should remove and clear resources  
11      * @return  
12      */ 
13     public static Session openSession() {  
14         System.out.println(Thread.currentThread().getStackTrace()[1] + " run in " + new Date());  
15         Session session = sessionMap.get(Thread.currentThread());  
16         if (session == null) {  
17             session = sessionFactory.openSession();  
18             sessionMap.put(Thread.currentThread(), session);  
19         }  
20         return session;  
21     }  
22     public static Session getCurrentSession() {  
23         return sessionMap.get(Thread.currentThread());  
24     }  
25    
26     public static void closeAndRemoveSession() {  
27         System.out.println(Thread.currentThread().getStackTrace()[1]+ " run in " + new Date());//  
28         Session session = sessionMap.remove(Thread.currentThread());  
29         if (session != null) {  
30             session.close();  
31         }  
32     }  
33 } 

 

  hibernate整合进spring后的事务处理

  spring事物处理的方式有很多,详见:http://www.blogjava.net/robbie/archive/2009/04/05/264003.html

  介绍常用的:

  spring annotation声明式的事务管理

  事物处理层?

  比如保存一个User,可以在Service层和DAOImpl层实现:

01 public void save(User u) {  
02     userDAO.save(u);  
03 }  
04    
05 public void save(User u) {  
06     System.out.println("save user from:" + this);  
07     Session s = sessionFactory.openSession();  
08     s.beginTransaction();  
09     s.save(u);  
10     s.getTransaction().commit();  
11     s.close();  
12 } 

   假如我们还有个日志记录,没保存一个User对象,要写入日志进入数据库。

  而save(log) 和 save(user)必须处在同一事务中,所以不能放在DAOImpl层,事务处理在Service层。

   一般的事务处理

01 Session sess = factory.openSession();  
02 Transaction tx;  
03 try {  
04     tx = sess.beginTransaction();  
05     //do some work  
06     //save(user);  
07     //save(log);  
08     ...  
09     tx.commit();  
10 } catch (Exception e) {  
11     if (tx!=null) tx.rollback();  
12     throw e;  
13 } finally {  
14     sess.close();  
15 } 

  并且要在实现层中的save()方法中也要加入事务处理,如果出出现异常要throws给上级处理!

  并且实现层中的session必须使用openCurrentSession()得到。

1 Session s = sessionFactory.getCurrentSession();  
2 s.save(u); 

    spring annotation事务处理

  Beans.xml中引入相应的xml命名空间和相应配置:

01 xmlns:tx="http://www.springframework.org/schema/tx" 
02 http://www.springframework.org/schema/tx   
03 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
04 <tx:annotation-driven transaction-manager="txManager"/>  
05 <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
06   <property name="sessionFactory" ref="sessionFactory" />  
07 </bean>  
08 <bean id="dataSource" 
09     class="org.apache.commons.dbcp.BasicDataSource" 
10     destroy-method="close">  
11     <property name="driverClassName" 
12         value="${jdbc.driverClassName}" />  
13     <property name="url" value="${jdbc.url}" />  
14     <property name="username" value="${jdbc.username}" />  
15     <property name="password" value="${jdbc.password}" />  
16 </bean>  
17 <bean id="sessionFactory" 
18     class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">  
19     <property name="dataSource" ref="dataSource" />  
20     <property name="annotatedClasses">  
21         <list>  
22             <value>com.syx.model.User</value>  
23             <value>com.syx.model.Log</value>  
24         </list>  
25     </property>  
26     <property name="hibernateProperties">  
27         <props>  
28             <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>  
29             <prop key="hibernate.show_sql">true</prop>  
30             <prop key="current_session_context_class">thread</prop>  
31         </props>  
32     </property>  
33 </bean>  
34 Save方法:  
35 public void save(User u) {  
36     Session s = sessionFactory.getCurrentSession();  
37     s.save(u);  
38 }  
39 public void save(Log log) {  
40     Session s = sessionFactory.getCurrentSession();  
41     s.save(log);  
42 }  
43 Service层处理:  
44 @Component("userService")  
45 public class UserService {  
46     UserDAO userDAO = null;  
47     LogDAO logDAO = null;  
48        
49     public LogDAO getLogDAO() {  
50         return logDAO;  
51     }  
52     @Resource(name="logDAOMySQLImpl")  
53     public void setLogDAO(LogDAO logDAO) {  
54         this.logDAO = logDAO;  
55     }  
56     @Transactional 
57     public void save(User u) {  
58         userDAO.save(u);  
59         Log log = new Log();  
60         log.setMsg(u.getName() + " saved in " + new Date());  
61         logDAO.save(log);  
62     }  
63     public UserDAO getUserDAO() {  
64         return userDAO;  
65     }  
66     @Resource(name="userDAOMySQLImpl")  
67     public void setUserDAO(UserDAO userDAO) {  
68         this.userDAO = userDAO;  
69     }  
70 } 

   @Transactional详解

  什么时候rollback

  运行期异常,非运行期异常不会触发rollback

  必须uncheck (没有catch)

  不管什么异常,只要你catch了,spring就会放弃管理

  事务传播特性:propagation_required

  propagation 默认是 REQUIRED ,意思是有我们就用现成的,没的我们就创造一个,其他详细见文档

  spring xml声明式的事务管理

  配置环境和annotation版本一致,只是在用@Transactional处注释调用,在beans.xml中加入如下配置:

01 <!-- spring tranception xml config --> 
02     <aop:config>  
03         <aop:pointcut id="serviceOperation" 
04             expression="execution(* com.syx.service..*.*(..))" />  
05         <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />  
06     </aop:config>  
07    
08     <tx:advice id="txAdvice"  transaction-manager="txManager">  
09         <tx:attributes>  
10             <tx:method name="getUser" read-only="true" />  
11             <tx:method name="save" /><!-- 相当于在上面切面pointcut@Transactional效果 --> 
12         </tx:attributes>  
13     </tx:advice> 

   hibernateTemplate.getSessionFactory().getCurrentSession()

  我们使用spring和hibernate结合,操作数据库最常用可能是HibernateTemplate,HibernateTemplate中集成了很多使用的方法,可惜的是没的createQuery方法,也许我们使用hibernate的时候喜欢使用Query,我们可能会封装hibernateTemplate.getSessionFactory().getCurrentSession()方法得到Session,session创建Query,这是一个方法,但你应该会得到异常 “createQuery without an active transaction”,因为使用hibernateTemplate.getSessionFactory().getCurrentSession(),你是使用的hibernate的事务管理,而你指望spring管理的事务是hibernateTemplate,所以你会提示没有打开事务的异常,解决方法:1)使用hibernate事务处理,就像上面单独使用hibernate一样,但这也许不是你想要的。2)使用hibernateTemplate的HibernateCallBack回调:

1 return hibernateTemplate.executeWithNativeSession(  
2     new HibernateCallback<List<T>>() {  
3     public  List<T> doInHibernate(Session session)   
4     throws HibernateException, SQLException {  
5         return session.createQuery  
6         ("FROM " + entityClass.getName() + " WHERE id IN (:ids)")//  
7         .setParameterList("ids", idList).list();  
8     } 

   实际上hibernateTemplate中封装的find方法也很强大,如果熟练使用完全可以替代createQuery的。

  备注:

  如果出现异常:对同一个集合处理不能使用2个session,这是因为getCurrentSession方法出错,导致打开一个新的session,检查配置文件,如果使用tomcat+spring+hibernate 配置hibernate.current_session_context_class 最好为thread,虽然支持jta,配置比较麻烦,而且jta支持多个sessionFactory,即可以跨数据库,比较强大!

  如果hibernate+spring出现session没有提交情况,应该是你让spring负责事务处理,而你有使用了hibernate的session,从而脱离spring事务处理,即没的begintransaction和commit之类的操作了。

转载于:https://www.cnblogs.com/Coda/p/3662279.html

你可能感兴趣的文章
BOM浏览器对象模型
查看>>
python实现排序奇数在前偶数在后
查看>>
hdu 3368 曾经下过的棋
查看>>
Linux Shell 删除三天前文件
查看>>
微信小程序 使用mpvue
查看>>
常用模块-02
查看>>
接口测试总结
查看>>
测试的基本概念
查看>>
【ZOJ】3209 Treasure Map
查看>>
ActiveMQ 消息队列服务
查看>>
《程序是给自己看的还是给别人看的》
查看>>
(12) PHP 随笔---Smarty模板引擎 单模板多缓存、局部不缓存 20--21
查看>>
【转】Math.Atan2 方法
查看>>
C++设计模式之工厂方法模式
查看>>
poj3984_bfs+回溯路径
查看>>
MyEclipse使用技巧
查看>>
[译]径向镜片反畸变滤波
查看>>
畅通工程-最小生成树+并查集
查看>>
top命令输出解释以及load average 详解及排查思路
查看>>
Ajax的封装
查看>>