【问题标题】:Is there any difference in using Hibernate with Spring as compared to Hibernate alone?与单独使用 Hibernate 相比,在 Spring 中使用 Hibernate 有什么不同吗?
【发布时间】:2014-02-15 02:02:18
【问题描述】:

到目前为止,我们一直在单独使用 Hibernate——我正在转向 JPA。 Spring 在我们的项目中用于 MVC。它们完全分开使用。

我使用 Hibernate JPA 实现检查了新的 Spring 4.0 Petclinic 项目 (https://github.com/SpringSource/spring-petclinic.git)。同样,我没有看到 Spring 对 Hibernate 代码的影响。例如 JpaPetRepositoryImpl 除了 @Repository 注释外,不使用 Spring。我错过了什么吗?

【问题讨论】:

    标签: java spring hibernate jpa


    【解决方案1】:

    Spring 的重点是尽可能不干扰您的代码,您应该在代码中尽可能少地看到 Spring。基本上,这就是 Spring 的重点和目标。

    当你通常在没有 spring 的情况下使用 hibernate 时,你会有某种构造 hibernate SessionFactory 的单例。

    public class HibernateUtil {
    
        private static SessionFactory sf;
    
        static {
                sf = ew Configuration().configure().buildSessionFactory();
        }
    
        public static getSessionFactory() {
            return sf;
        }
    
    } 
    

    接下来您会看到代码中充满了对HibernateUtils.getSesionFactory() 的调用。您需要手动创建 Session 并启动/提交事务。

    public void save(Entity e) {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();
        Transaction tx = session.beginTransaction();
        try {
             session.save(e);
             tx.commit();
        } catch (HIbernateException he) {
            tx.rollback();
        } finally {
            session.close();
        }
    }
    

    但是,由于两个原因,这段代码很糟糕。首先,您手动管理事务,一段时间后变得很痛苦,您想使用声明性事务管理。第二个你在错误的层管理事务,事务应该在服务层管理。现在要实现这一点,您必须在服务层中获取SessionFactory,这会突然将数据访问层变成一个泄漏的抽象。

    Spring 可以在这两件事上为您提供帮助,它可以进行声明式 tx 管理并隐藏您正在使用 Hibernate 的事实,而不是使其成为泄漏的抽象。

    @Inject
    private SessionFactory sf;
    
    public void save(Entity e) {
        sf.getCurrentSession().save(e);
    } 
    

    这在 Spring 方式中是相同的。事务将在服务级别启动(带有@Transactional@TransactionAttributes 注释)。

    对于 JPA,这或多或少是相同的,但是由于 JPA 是标准 Spring 尝试尽可能地遵循这些。所以 Spring 中的普通 JPA 代码和 JPA 代码没有太大区别(除非您在独立应用程序中使用 JPA 而不是 JEE 容器,否则 JPA 代码就像休眠代码一样)。

    【讨论】:

      【解决方案2】:

      其中一大优势是使用 @Transactional 注释的声明式事务管理,其中 Spring 管理事务提交/回滚,看看这个example

      【讨论】:

        【解决方案3】:

        我喜欢将 EntityManager 注入我的 Spring bean 的 @PersistenceContext 注释。如果您熟悉 SoC 意识形态,那么使用 Spring 会让一切变得更加清晰,但我猜有些人会觉得它令人困惑而且太神奇了。

        我肯定会完全建议您不要在没有任何 IoC 框架的情况下手动使用 hibernate/jpa/persistence。

        【讨论】:

        • 手动使用hibernate/jpa/persistence有什么问题?与 JPA 有什么不同?此外,注释 PersistenceContext 用于 JPA 实现内部的 PetClinic,它不用于 Spring bean。什么更好?
        • 我说的手动就是不用注入。刚开始,不久前,我以为我比 Spring 更聪明,我自己创建了所有东西,entityManager、服务、DAO 通过构造函数。然后我需要事务,所以我将我的每一段代码都包装在 tx.begin 和 tx.commit 之间。经过几十次服务后,我的代码获得了不可读的混乱奖章:D 当我开始需要将我的服务层放入 Web 应用程序时,一切都变得更糟了……那是我抢购并接受 Spring 及其方法的时候。但也许这不完全是你的问题,我不确定了。
        【解决方案4】:

        带有声明式事务的 Spring 需要代理或字节码转换。它使调试复杂化并减慢应用程序启动时间。有很多方法可以避免这种复杂性,其中一种方法是命令设计模式:

        public class Transaction { public void execute(Command command) { SessionFactory sf = HibernateUtil.getSessionFactory(); Session session = sf.openSession(); try{ Transaction tx = session.beginTransaction(); try { command.execute(session); tx.commit(); } catch (HIbernateException he) { tx.rollback(); } }finally{ session.close(); } } }

        在实践中,您可能需要“command.execute(context)”的“Context”参数而不是“Session”来抽象这种设计,但例如,有“Session”参数会更清楚。 使用复合命令包装器可以在同一个事务中执行多个命令。此设计模式可用于添加命令验证、安全性:“command.isValid(context)”、“command.checkPermissions(context)”。许多其他方面可以通过这种简单但强大的设计模式来实现,而不依赖于任何重量级的框架。您也可以将这种设计与 Spring 一起使用,Spring 可以很好地在 XML 中配置工厂,但我认为 Spring 太重了,对于其他用例来说太复杂了。

        【讨论】:

          猜你喜欢
          • 2016-08-28
          • 1970-01-01
          • 2015-09-29
          • 1970-01-01
          • 2016-05-20
          • 1970-01-01
          • 1970-01-01
          • 2017-05-10
          • 1970-01-01
          相关资源
          最近更新 更多