• hibernate整合进spring后的事务处理


    单独使用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之类的操作了。

  • 相关阅读:
    阿里风控大脑关于大数据应用的探索与实践
    MaxCompute
    Lyft 基于 Flink 的大规模准实时数据分析平台(附FFA大会视频)
    基于MaxCompute InformationSchema进行血缘关系分析
    阿里经济体大数据平台的建设与思考
    厉害了!阿里云首批通过边缘云标准符合性测试
    边缘计算和“寒武纪”有什么关系?阿里云资深专家刘强如是说
    阿里云荣获最佳智能边缘计算技术创新平台
    阿里云杨敬宇:四层技术构建基于城市场景的边缘计算
    阿里云移动研发平台 EMAS 助力银行业打造测试中台,提升发版效能
  • 原文地址:https://www.cnblogs.com/Coda/p/3662279.html
Copyright © 2020-2023  润新知