Java 同时使用Hibernate和Spring数据jpa?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21671731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:00:47  来源:igfitidea点击:

Simultaneous use of Hibernate and Spring data jpa?

javaspringhibernatejpaspring-data

提问by akashihi

Is it possible to use Spring Data JPA (backed by Hibernate as JPA provider) and directly use Hibernate at the same time?

是否可以同时使用 Spring Data JPA(由 Hibernate 作为 JPA 提供者支持)并直接使用 Hibernate?

The problem is that when i use JpaTransactionManager, i'm not able to retrieve current session with org.hibernate.HibernateException: No Session found for current thread. When i switch to HibernateTransaction manager, JPA repositories are not able to commit changes.

问题是,当我使用 JpaTransactionManager 时,我无法使用org.hibernate.HibernateException: No Session found for current thread. 当我切换到 HibernateTransaction 管理器时,JPA 存储库无法提交更改。

Here is the part of my Spring context (with that context i'm not able to use direct Hibernate calls):

这是我的 Spring 上下文的一部分(在该上下文中,我无法直接使用 Hibernate 调用):

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/IPGCONF"/>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
      p:dataSource-ref="dataSource">
    <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="entityManagerFactory"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

<jpa:repositories base-package="com.satgate"/>

Example of hibernate repository:

休眠存储库示例:

public Collection<Layer> listCurrent(Carrier carrier) {
    Criteria query = sessionFactory.getCurrentSession()
                    .createCriteria(Layer.class)
                    .add(Restrictions.eq("carrier", carrier));
    query.createCriteria("bitrate")
            .addOrder(Order.desc("bitrate"))
            .add(Restrictions.eq("symbolrate", carrier.getSymbolrate()));
    return query.list();
}

Example of Spring data repository definition:

Spring 数据存储库定义示例:

public interface BitrateRepository extends PagingAndSortingRepository<Bitrate, Long> { }

Software versions:

软件版本:

<org.springframework.version>4.0.0.RELEASE</org.springframework.version>
<org.springframework.data.version>1.4.3.RELEASE</org.springframework.data.version>
<hibernate.version>4.3.0.Final</hibernate.version>

So, the question is - is it possible to use in the same transaction (specified by @Transactional annotation) both Spring JPA repositories and direct Hibernate calls and how to achieve that?

所以,问题是 - 是否可以在同一个事务(由@Transactional 注释指定)中同时使用 Spring JPA 存储库和直接 Hibernate 调用以及如何实现这一点?

采纳答案by neildo

Instead of creating a SessionFactory, use EntityManager.unwrap(Session.class)to get a Hibernate Session and retrieve the session factory from the Session object.

不是创建 SessionFactory,而是EntityManager.unwrap(Session.class)用于获取 Hibernate Session 并从 Session 对象中检索会话工厂。

You can also use EntityManagerFactory.unwrap(SessionFactory.class)to get the Hibernate SessionFactory directly.

您也可以使用EntityManagerFactory.unwrap(SessionFactory.class)来直接获取 Hibernate SessionFactory。

回答by M. Deinum

You need a single way of configuration you are now configuring both Hibernate and JPA. You should be using JPA for configuration so remove the hibernate setup.

您现在需要一种配置 Hibernate 和 JPA 的单一方式。您应该使用 JPA 进行配置,因此删除休眠设置。

You are using Hibernate4 so you can take advantage of the, not so well known, HibernateJpaSessionFactoryBeanof Spring. If you need access to the SessionFactory(which I assume you need).

您正在使用 Hibernate4,因此您可以利用HibernateJpaSessionFactoryBeanSpring 的鲜为人知的优势。如果您需要访问SessionFactory(我认为您需要)。

When applied your configuration will like something like this.

应用后,您的配置会像这样。

<bean id="sessionFactory" class="org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="entityManagerFactory"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
</bean>

I would suggest to only use this as an intermediate solution while you are refactoring your applicaiton to use the plain JPA api. I wouldn't suggest mixing both strategies.

我建议在重构应用程序以使用普通 JPA api 时仅将其用作中间解决方案。我不建议混合使用这两种策略。

回答by CloudSen

This is what I did, and it worked well: one data source, two transaction manager.
Data source bean:

这就是我所做的,而且效果很好: 一个数据源,两个事务管理器。
数据源 bean:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <!-- bulabula... -->
</bean>

For Hibernate XML based configuration:

对于基于 Hibernate XML 的配置:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingLocations" value="#{propertyUtils.getList('hibernate.hbm')}"/>
    <property name="hibernateProperties">
        <value>
            <!-- bulabulabula... -->
        </value>
    </property>
</bean>

<bean id="transactionManager" primary="true" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

And for spring-data-jpa java based configuration:

对于基于 spring-data-jpa java 的配置:

@Configuration
@EnableJpaRepositories(basePackages = {"org.sharder.core.repository"}, 
transactionManagerRef = "jpaTransactionManager")
@EnableTransactionManagement
public class JpaConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(ComboPooledDataSource comboPooledDataSource) {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    vendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("org.sharder.core.entity");
    factory.setDataSource(comboPooledDataSource);
    factory.setJpaProperties(getHibernateProperties());
    return factory;
}

@Bean(name = "jpaTransactionManager")
public PlatformTransactionManager jpaTransactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(entityManagerFactory);
    return txManager;
}

private Properties getHibernateProperties() {
    Properties properties = new Properties();
    properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
    properties.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory");
    properties.setProperty("hibernate.cache.use_query_cache", "true");
    properties.setProperty("hibernate.cache.use_second_level_cache", "true");
    properties.setProperty("hibernate.cache.use_structured_entries", "true");
    properties.setProperty("hibernate.format_sql", "true");
    properties.setProperty("hibernate.show_sql", "true");
    properties.setProperty("hibernate.use_sql_comments", "true");
    properties.setProperty("hibernate.query.substitutions", "true 1, false 0");
    properties.setProperty("hibernate.jdbc.fetch_size", "20");
    properties.setProperty("hibernate.connection.autocommit", "false");
    properties.setProperty("hibernate.connection.release_mode", "auto");
    return properties;
}

}

}

Notice that, transactionManagerRef = "jpaTransactionManager"set the JpaTransactionManager to be used with the repositories. Spring Data JPA namespace attributes

请注意,transactionManagerRef = "jpaTransactionManager"将 JpaTransactionManager 设置为与存储库一起使用。 Spring Data JPA 命名空间属性