是否可以使用Spring Data JPA(由Hibernate作为JPA提供程序支持)并同时直接使用Hibernate?
问题是当我使用JpaTransactionManager时,我无法使用org.hibernate.HibernateException: No Session found for current thread
检索当前会话。当我切换到HibernateTransaction管理器时,JPA存储库无法提交更改。
这是我的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"/>
hibernate存储库示例:
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();
}
Spring数据存储库定义示例:
public interface BitrateRepository extends PagingAndSortingRepository<Bitrate, Long> { }
软件版本:
<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>
所以,问题是 - 是否可以在同一个事务中使用(由@Transactional注释指定)Spring JPA存储库和直接Hibernate调用以及如何实现它?
答案 0 :(得分:25)
您需要一种配置方式,现在正在配置Hibernate和JPA。您应该使用JPA进行配置,因此请删除hibernate设置。
您正在使用Hibernate4,因此您可以利用Spring的HibernateJpaSessionFactoryBean
,而不是那么着名。如果您需要访问SessionFactory
(我认为您需要)。
应用后,您的配置就会像这样。
<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>
我建议您只使用此作为中间解决方案,同时重构您的应用程序以使用普通的JPA api。我不建议混合两种策略。
答案 1 :(得分:19)
使用EntityManager.unwrap(Session.class)
来获取Hibernate会话并从Session对象中检索会话工厂,而不是创建SessionFactory。
您也可以使用EntityManagerFactory.unwrap(SessionFactory.class)
直接获取Hibernate SessionFactory。
答案 2 :(得分:1)
这就是我所做的,并且效果很好:
一个数据源,两个事务管理器。
数据源bean:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- bulabula... -->
</bean>
对于基于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>
对于基于java的spring-data-jpa配置:
@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;
}
}
请注意,transactionManagerRef = "jpaTransactionManager"
设置要与存储库一起使用的JpaTransactionManager。
Spring Data JPA namespace attributes