处理Hibernate事务

目前,我在每个 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 } }); .... 

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

您必须在每次事务后关闭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将根据您的切入点开始并提交事务,并且还可以在发生exception时回滚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 Instantiation和使用创建了一个单独的JavaClass。 你可以从这里获得会议,这可能满足你的需要。 希望能帮助到你 :)

我用过这种技术。

我的Servlet上下文是这样的:

      classpath:hibernate.cfg.xml   org.hibernate.cfg.AnnotationConfiguration    ${jdbc.dialect} true        

然后你可以简单地使用

  @Autowired private SessionFactory sessionFactory; 

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

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

我认为这会有所帮助。

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