繁体   English   中英

处理Hibernate事务

[英]Handling Hibernate Transactions

目前我在每个 Controller方法中复制了这些代码:

Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction();
if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) {
    transaction.begin();
}

这是正确的方法,还是有更好的方法,也许在我可以参考的单独的课程中? 如果是这样,怎么样? 每当我试图将它放在一个单独的类中并从其他类引用它时,它就失败了。

编辑 :我正在尝试使用尽可能少的外部库。 如果Java在JDK中内置了ORM / JPA实现,我就不会使用Hibernate

我自己多次碰到这个。 通常我的第一个建议是Spring事务管理 ,但是我知道你试图限制你正在使用的第三方库的数量。

由于您在HibernateUtil类中使用静态API,您可能会发现在方法中合并逻辑并在回调中放置“您想要在事务中执行的操作”代码(这会将控制器变为控制器)会很有帮助。

首先,定义一个接口来描述每个控制器的inTransaction行为:

public interface TransactionCallback {
    void doInTransaction();
}

现在,在HibernateUtil类中创建一个静态方法来处理开始,提交,并在必要时回滚您的事务:

public class HibernateUtil {
    public static void inTransaction(TransactionCallback tc) {
        Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction();
        if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) {
            transaction.begin();
            try {
                tc.doInTransaction();
                transaction.commit();
            } catch (Exception e) {
                transaction.rollback();
            }
        }
    }
}

在你的控制器中,你将使用一个匿名内部类的新方法:

....
    HibernateUtil.inTransaction(new TransactionCallback() {
        void doInTransaction() {
            // do stuff for this controller
        }
    });
....

这种方法至少应该处理你想要消除的重复,并且有足够的空间来扩展它以处理特定的异常等。

您必须在每次事务后关闭hibernate事务(例如,Controller请求)。 在这种情况下,您将不需要

if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) 

每次请求后你都需要调用.close()。

最好使用以下代码:

class Controller { 
//...
commonActionMethod() {
  begin transaction
  specificActionMethod();
  close transaction
}

这个Controller类的子节点应该实现specificActionMethod()。

代码很干净。 交易是安全的。 不需要第三方库。

  1. 您可以很好地使用JDK Proxies来实现自己的AOP。 参考: Link1 Link2
  2. 有服务层来处理诸如Hibernate等DAO框架。 这样您的控制器就可以控制流程,您的服务可以实现业务。
  3. 让SeviceLocator / FactoryPattern获取您的Service实例(换句话说,返回代理而不是Actual实例)。
  4. 定义您自己的注释并确定您的方法是否需要交易。 如果需要在代理处理程序中处理方法调用周围的事务。

这样,您不需要依赖JDK以外的任何库。 你可以通过注释来关闭或开启交易。
如果你开始管理实例(服务),你可以结合使用FactoryPattern + JDK Proxies(实际接口)+ AOP Concepts来制作很多魔法。

您可以创建单独的连接类。

        public class HibernateUtil {

      private static final SessionFactory sessionFactory = buildSessionFactory();

      @SuppressWarnings("deprecation")
    private static SessionFactory buildSessionFactory() {
        try {
          // Create the SessionFactory from Annotation
          return new AnnotationConfiguration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
          // Make sure you log the exception, as it might be swallowed
          System.err.println("Initial SessionFactory creation failed." + ex);
          throw new ExceptionInInitializerError(ex);
        }
      }

      public static SessionFactory getSessionFactory() {
        return sessionFactory;
      }
    }

在服务器端,您可以写: -

    Session session=null;
    Transaction tx=null;

     try {
        session =HibernateUtil.getSessionFactory().openSession();
        tx=session.beginTransaction();
        } catch (HibernateException e) {
    e.printStackTrace();
    }finally
    {
        session.close();
    }

避免使用其他外部库,您可能希望提供实现该标准J2EE servlet Filter接口的拦截 这种实现有时被称为视图模式中的开放会话 我从这个页面引用了以下内容:

当必须处理HTTP请求时,将开始新的会话和数据库事务。 在将响应发送到客户端之前,在完成所有工作之后,将提交事务,并且将关闭会话。

如果您在项目中使用spring。 我建议使用弹簧AOP使用TX,因为您只需指定事务的切入点。 Spring AOP TX将根据您的切入点开始并提交事务,并且还可以在发生异常时回滚TX。 请仔细阅读示例链接 - 这里

package com.project.stackoverflow;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class HibernateUtil {

    private static final ThreadLocal threadSession = new ThreadLocal();
    private static SessionFactory sessionFactory;

    /**
     * A public method to get the Session.
     * 
     * @return Session
     */
    public static Session getSession() {
        Session session = (Session) threadSession.get();

        // Open a Session, if this thread has none yet
        if ((null == session) || !session.isOpen()) {
            logger.info("Null Session");
            session = sessionFactory.openSession();
            logger.info("Session Opened");
            threadSession.set(session);
        }

        return session;
    }

    public static void closeSession() {
        Session session = (Session) threadSession.get();

        // Open a Session, if this thread has none yet
        if (null != session) {
            session.close();
            session = null;
            threadSession.set(null);
        }
    }

        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        logger.info("Inside set session Factory");
        this.sessionFactory = sessionFactory;
        logger.info("After set session Factory");
    }

    public static void save(Object obj) {
        getSession().save(obj);
        getSession().flush();
    }

    public static void saveOrUpdate(Object obj) {
        getSession().saveOrUpdate(obj);
        getSession().flush();
    }
    public static void batchUpdate(Object obj) {
        getSession().saveOrUpdate(obj);
        getSession().flush();
    }

    public static void update(Object obj) {
        getSession().update(obj);
        getSession().flush();
    }

    public static void delete(Object obj) {
        getSession().delete(obj);
        getSession().flush();
    }
}

您可以选择此解决方案。 我为Hibernate实例化和使用创建了一个单独的JavaClass。 你可以从这里获得会议,这可能满足你的需要。 希望能帮助到你 :)

我用过这种技术。

我的Servlet上下文是这样的:

    <beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
    p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />

    <beans:bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <beans:property name="dataSource" ref="dataSource" />
    <beans:property name="configLocation">
        <beans:value>classpath:hibernate.cfg.xml</beans:value>
    </beans:property>
    <beans:property name="configurationClass">
        <beans:value>org.hibernate.cfg.AnnotationConfiguration</beans:value>
    </beans:property>
    <beans:property name="hibernateProperties">
        <beans:props>
            <beans:prop key="hibernate.dialect">${jdbc.dialect}</beans:prop>
            <beans:prop key="hibernate.show_sql">true</beans:prop>
        </beans:props>
    </beans:property>
</beans:bean>

<beans:bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>

<tx:annotation-driven transaction-manager="transactionManager" />

然后你可以简单地使用

   @Autowired
    private SessionFactory sessionFactory;

每当我想使用会话或进行任何操作时,我只需这样做:

        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        session.save(userAccount);
        transaction.commit();
        session.close();

我认为这会有所帮助。

如果您有像glassfish这样的应用程序服务器,它已经嵌入了eclipselink JPA / ORM实现,您可以使用标准JEE注释来管理事务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM