使用 Spring 的 EmbeddedDatabaseBuilder 测试 Hibernate 与 SpringSessionContext 的问题

testing Hibernate with Spring's EmbeddedDatabaseBuilder issues with SpringSessionContext

我正在使用 Spring 框架的 EmbeddedDatabaseBuilder 作为数据源进行单元测试,并将其传递到我的 SessionFactory 的 Hibernate 配置中,使用 Spring 4 和 Hibernate 4 . 我没有以任何方式使用 Spring 上下文 - 我使用的唯一配置是程序化的(没有注释,没有 XML 除了 Hibernate 映射文件)。

我希望 Hibernate 会使用它的默认值 ThreadLocalSessionContext 并且我将能够在单元测试中启动和回滚事务。

然而不知何故 Hibernate 已将其 SessionFactory.currentSessionContext 设置为 Spring 的 SpringSessionContext 并且每当我尝试调用 SessionFactory.getCurrentSession():

时它都会抱怨
HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)

在下面的单元测试代码中,我将 hibernate.current_session_context_class 设置为 thread 但这被忽略或替换为 Spring 执行。

public abstract class HibernateTestBase {

    private static EmbeddedDatabase dataSource;
    private static SessionFactory sessionFactory;
    private Session session;

    @BeforeClass
    public static void setupClass() {
        dataSource = new EmbeddedDatabaseBuilder().
                setType(EmbeddedDatabaseType.H2).
                addScript("file:SQLResources/schema-1.1.sql").
                addScript("file:SQLResources/schema-1.2.sql").
                build();
        Configuration configuration = new Configuration();
        configuration.addResource("hibernate-mappings/HierarchyLevel.hbm.xml");
        configuration.addResource("hibernate-mappings/HierarchyFilter.hbm.xml");
        configuration.addResource("hibernate-mappings/AuditLog.hbm.xml");
        configuration.setProperty("hibernate.dialect",
                "org.hibernate.dialect.Oracle10gDialect");
        configuration.setProperty("hibernate.show_sql", "true");
        configuration.setProperty("hibernate.current_session_context_class",
                "thread");
        StandardServiceRegistryBuilder serviceRegistryBuilder =
                new StandardServiceRegistryBuilder();
        serviceRegistryBuilder.applySetting(Environment.DATASOURCE, dataSource);
        serviceRegistryBuilder.applySettings(configuration.getProperties());
        StandardServiceRegistry serviceRegistry =
                serviceRegistryBuilder.build();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        sessionFactory.openSession();
    }

    @AfterClass
    public static void tearDown() {
        if (sessionFactory != null) {
            sessionFactory.close();
        }
        if (dataSource != null) {
            dataSource.shutdown();
        }
    }

    @Before
    public final void startTransaction() {
        session = sessionFactory.getCurrentSession();
        session.beginTransaction();
    }

    @After
    public final void rollBack() {
        session.flush();
        Transaction transaction = session.getTransaction();
        transaction.rollback();
    }
}

我被迫改为调用 SessionFactory.openSession(),但之后我将无法将我的 DAO 与相同的 SessionFactory 一起使用,因为它们都调用 getCurrentSession()。所以我将无法从已经编码的数据处理功能中受益。

我能做什么?

使用传统的 hibernate.cfg.xml 设置 Configuration 对象时工作正常,使用 SpringSessionContext 作为生产像这样:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  "classpath://org/hibernate/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</property>
    <!-- property name="hibernate.current_session_context_class">thread</property-->
    <mapping resource="hibernate-mappings/AccessRight.hbm.xml" />
  </session-factory>
</hibernate-configuration>

并在测试中加载它,但像这样覆盖 session context

    Configuration configuration = new Configuration();
    configuration.configure(
            "hibernate-mappings/hibernate.cfg.xml");
    configuration.setProperty("hibernate.current_session_context_class",
            "thread");

因此,当 Hibernate 使用所需的 hibernate.cfg.xml 进行自我设置时,后台会发生一些事情。