Java 处理Hibernate事务

Java 处理Hibernate事务,java,hibernate,jakarta-ee,transactions,Java,Hibernate,Jakarta Ee,Transactions,目前,我在每个控制器方法中都复制了此代码: Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction(); if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) { transaction.begin(); } 这是正确的方法还是有更好

目前,我在每个控制器方法中都复制了此代码:

Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction();
if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) {
    transaction.begin();
}
这是正确的方法还是有更好的方法,也许在我可以参考的单独的类中?如果是,怎么做?每次我试图将它放在一个单独的类中,并从其他类中引用它时,它都失败了


编辑:我正在尝试使用尽可能少的外部库。如果Java在JDK中内置了ORM/JPA实现,我不会使用Hibernate,因为您可以为连接创建单独的类

        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();
    }

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

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。您可以从这里获得满足您需要的会话。希望有帮助:)

我自己也遇到过很多次。通常我的第一个建议是,但是我知道您正在试图限制您使用的第三方库的数量

由于您在HibernateUtil类中使用的是静态API,您可能会发现将逻辑整合到一个方法中,并将“在事务中要做什么”代码(根据控制器的不同而不同)放入回调中很有帮助

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

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
        }
    });
....

这种方法至少应该考虑到您希望消除的重复,并且有足够的空间扩展它以处理特定的异常等。

为了避免使用额外的外部库,您可能希望提供一个实现标准J2EE servlet接口的拦截器。这种实现有时被称为视图中的开放会话模式。我引述如下:


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


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

if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) 
每次请求后都需要调用.close()

最好使用以下代码:

class Controller { 
//...
commonActionMethod() {
  begin transaction
  specificActionMethod();
  close transaction
}
此控制器类的子类应实现specificActionMethod()


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

如果您在项目中使用spring。我建议使用TX-UsingSpringAOP,因为您只需要为事务指定切入点。Spring AOP TX将根据您的切入点开始并提交事务,并且在发生异常时也可以回滚TX。请浏览示例的链接-

  • 您可以很好地使用JDK代理来实现自己的AOP。 参考:
  • 具有服务层以与DAO框架(如Hibernate等)兼容。因此,您的控制器只是控制流程,您的服务可以实现业务
  • 让SeviceLocator/FactoryPattern获得您的服务实例(换句话说,返回代理而不是实际实例)
  • 定义自己的注释,并确定是否需要事务处理的方法。如果需要,在代理处理程序中围绕方法调用处理事务
  • 这样,您不需要依赖除JDK之外的任何库。您可以通过添加注释来关闭或打开事务。
    如果您开始管理实例(服务),您可以通过FactoryPattern+JDK代理(实际接口)+AOP概念的组合来实现许多魔术

    我使用了这种技术

    我的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" />
    
            Session session = sessionFactory.openSession();
            Transaction transaction = session.beginTransaction();
            session.save(userAccount);
            transaction.commit();
            session.close();
    

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

        <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" />
    
            Session session = sessionFactory.openSession();
            Transaction transaction = session.beginTransaction();
            session.save(userAccount);
            transaction.commit();
            session.close();
    

    我想这会有帮助的

    为什么不使用Spring或CDI等提供的声明性事务和AOP?如何实例化控制器?我可以为
    服务
    之类的方法调用想出一个解决方案,但不确定控制器。您尝试过TransactionManager和LocalSessionFactoryBean吗?这正是我要问的如何避免的。Apache不是java ee服务器。因此,您需要外部ORM(如hibernate)和外部事务管理框架(如spring)。用手做事务很痛苦。“会话将被关闭。”-不必要,这是使用DAO模式的实现。