我有一个使用Hibernate 4和Spring Transactions的Spring 3.2应用程序.所有方法都运行良好,我可以正确访问数据库以保存或检索实体.然后,我介绍了一些多线程,并且由于每个线程都访问了db,我从Hibernate收到以下错误:
org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
Run Code Online (Sandbox Code Playgroud)
我从网上读到我要添加<prop key="hibernate.current_session_context_class">thread</prop>到我的Hibernate配置中,但是现在每次我尝试访问db时都会得到:
org.hibernate.HibernateException: saveOrUpdate is not valid without active transaction
Run Code Online (Sandbox Code Playgroud)
但是我的服务方法是注释的@Transactional,并且在添加之前一切正常<prop key="hibernate.current_session_context_class">thread</prop>.
为什么没有交易,尽管方法是用@Transactional注释的?我怎么解决这个问题?
这是我的Hibernate配置(包括会话上下文属性):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<!-- Hibernate session factory -->
<bean
id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="dataSource" >
<ref bean="dataSource" />
</property>
<property name="hibernateProperties" >
<props>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.dialect" >org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
<property name="annotatedClasses" …Run Code Online (Sandbox Code Playgroud) 关于Spring JPA存储库事务性的1个快速问题.我有一个未标记为事务性的服务,并调用Spring JPA存储库方法
userRegistrationRepository.deleteByEmail(email);
Run Code Online (Sandbox Code Playgroud)
它被定义为
@Repository
public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> {
UserRegistration findByEmail(String email);
void deleteByEmail(String email);
}
Run Code Online (Sandbox Code Playgroud)
问题是它失败了" 没有实体事务可用于当前线程的EntityManager - 无法可靠地处理'删除'调用;嵌套异常是javax.persistence.TransactionRequiredException "异常.
好吧,我可以通过将服务或 deleteByEmail(..)方法标记为事务来解决它,但我无法理解为什么它现在崩溃.Spring文档明确声明" 默认情况下,存储库实例上的CRUD方法是事务性的. "(http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions),但显然这个不是......那么这个陈述只与成员有关CrudRepository吗?
ps:那是Spring Data JPA 1.9.4
我在SO上找到了关于这个问题的几个问题和答案,但它们似乎都涵盖了问题的一个主要原因:在事务之外或在另一个事务中获取集合.但在我的情况下,我在获取父对象和集合时在同一事务中获取.
@Service
@Transactional
public class IntegrationServiceImpl implements IntegrationService {
@Override
public Integration getIntegrationByIdFetchBackendParameters(Long integrationId) {
Integration integration = integrationDao.get(integrationId);
//not all integrations have to have backend.
if (integration.getBackend() != null) {
Hibernate.initialize(integration.getBackend().getBackendParameters());
}
return integration;
}
...
Run Code Online (Sandbox Code Playgroud)
但是当谈到Hibernate.initialize这个分支在org.hibernate.collection.internal.AbstractPersistentCollection中执行
if ( session == null ) {
throw new HibernateException( "collection is not associated with any session" );
}
Run Code Online (Sandbox Code Playgroud)
我不能明白为什么session是null.有人会解释这个并提出解决方案吗?
编辑1 - 完整堆栈跟踪
org.hibernate.HibernateException: collection is not associated with any session
at org.hibernate.collection.internal.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:676)
at org.hibernate.Hibernate.initialize(Hibernate.java:77)
at com.dhl.finFw.service.IntegrationServiceImpl.getIntegrationByIdFetchBackendParameters(IntegrationServiceImpl.java:169)
at …Run Code Online (Sandbox Code Playgroud) 因此,在最新版本的Spring中,我们可以使用@Configuration注释来设置Spring的配置.现在,在JavaConfig中,可以使用@AnnotationDrivenTx(@AnnotationDrivenTx Reference Link)批注在Config类中设置事务.但是由于JavaConfig已经退役,我想知道是否有人知道如何在没有JavaConfig的情况下设置类似的东西而不需要添加任何内容application-context.xml.这是我基本上用于Config类的内容
@Configuration
@ImportResource("config/application-context.xml")
public class Config {
public @Bean DataSource dataSource() {
//get and return datasource
}
public @Bean Service1 getService1() {
//return service1Impl
}
}
Run Code Online (Sandbox Code Playgroud)
而且我想做Service1交易.如果有人对如何做到这一点有任何想法,或者如果这是不可能的,请告诉我.
谢谢!
我们有一个微服务架构,其中Kafka用作服务之间的通信机制。一些服务具有自己的数据库。假设用户调用服务A,这将导致在该服务的数据库中创建一条记录(或一组记录)。此外,此事件应作为Kafka主题的一项报告给其他服务。确保仅在成功更新Kafka主题(实质上是围绕数据库更新和Kafka更新创建分布式事务)时才写入数据库记录的最佳方法是什么?
我们正在考虑使用spring-kafka(在Spring Boot WebFlux服务中),我可以看到它具有KafkaTransactionManager,但是据我了解,这更多地是关于Kafka交易本身(确保Kafka生产者和消费者之间的一致性),而不是在两个系统之间同步事务(请参见此处:“ Kafka不支持XA,您必须处理在Kafka tx回滚时DB tx可能提交的可能性。”)。另外,我认为此类依赖于Spring的事务框架,至少就我目前所知,该框架是线程绑定的,如果使用反应性方法(例如WebFlux)在操作的不同部分执行该方法,则该类将无法工作。不同的线程。(我们正在使用react-pg-client,因此是手动处理事务,而不是使用Spring的框架。)
我能想到的一些选择:
是否有人对以上内容有任何想法或建议,或者能够纠正上述假设中的任何错误?
提前致谢!
distributed-transactions spring-transactions apache-kafka spring-kafka
我正在使用Spring事务,因此当POJO到DTO转换发生时,事务仍处于活动状态.
我想阻止Dozer触发延迟加载,以便隐藏的sql查询永远不会发生:所有提取都必须通过HQL显式完成(以获得对性能的最佳控制).
这是一个好习惯(我无法在任何地方找到它)?
怎么安全地做?
我在DTO转换之前试过这个:
PlatformTransactionManager tm = (PlatformTransactionManager) SingletonFactoryProvider.getSingletonFactory().getSingleton("transactionManager");
tm.commit(tm.getTransaction(new DefaultTransactionDefinition()));
Run Code Online (Sandbox Code Playgroud)
我不知道事务发生了什么,但Hibernate会话没有关闭,延迟加载仍然发生.
我试过这个:
SessionFactory sf = (SessionFactory) SingletonFactoryProvider.getSingletonFactory().getSingleton("sessionFactory");
sf.getCurrentSession().clear();
sf.getCurrentSession().close();
Run Code Online (Sandbox Code Playgroud)
它可以防止延迟加载,但是直接在应用程序层(在我的项目中称为"facade")中操作会话是一种很好的做法吗?我应该担心哪些负面影响?(我已经看到涉及POJO - > DTO转换的测试无法通过AbstractTransactionnalDatasource Spring测试类启动,因为这些类尝试触发对不再链接到活动会话的事务的回滚).
我还尝试将传播设置为NOT_SUPPORTED或REQUIRES_NEW,但它重用当前的Hibernate会话,并不会阻止延迟加载.
在开始我的应用程序时,我会收到大量警告o.s.aop.framework.Cglib2AopProxy 'Unable to proxy method [public final void org.springframework.jdbc.core.support.JdbcDaoSupport.setDataSource(javax.sql.DataSource)] because it is final: All calls to this method via a proxy will be routed directly to the proxy.',大约有十几个功能.
现在我完全理解基于代理的方面不能应用于最终方法.但是,我没有(至少是故意的)尝试编织任何方面JdbcDaoSupport.我怀疑它来自<tx:annotation-driven />.我能做些什么来消除这些警告,或者更好的是,将这些类别排除在编织方面?
Context是Java - 带有Hibernate和Spring的JPA.
我们来看两阶段提交协议的场景(但只有一个资源):
查询从应用程序提交
投票是/否(在我们的案例中来自数据库)
3.1.如果是,来自数据库
3.1.1.(在代码中进行回调) - 不是协议的一部分
3.1.2.提交数据库
3.2如果没有
3.2.1回滚到数据库
我想要的是一种在代码中从3.1.1进行回调的方法,但只有当知道事务将被提交但在实际提交之前.此外,如果在此处抛出异常,则应回滚该事务.
使用TransactionSynchronizationSpring中的(*),允许您在事务提交/完成之前或提交/完成之后拦截事务.
beforeCommit() 回调说在调用方法后仍然可以发生回滚; beforeComplete() 即使交易失败也会被调用afterCommit/Complete() 在事务实际提交到数据库之后调用,并且无法回滚. 现在我看起来似乎我想要的是另一个完整的两阶段提交协议; 但我想知道Spring中是否有解决方法.区别在于回调中完成的调用无法回滚.
来自Spring 4.2的(*)非常简单,@TransactionalEventListener并且TransactionPhase很好地抽象TransactionSynchronization
我想使用spring测试框架测试hibernate session的save()方法.@Test方法是:
@Test
@Transactional
public void testSave() {
User expected = createUser();
getGenericDao().currentSession().save(expected);
User actual = getUser(generatedId);
assertUsersEqual(expected,actual);
}
Run Code Online (Sandbox Code Playgroud)
我想将用户刷新到数据库中.我想让我的用户在这个方法之后进入数据库
getGenericDao().currentSession().save(expected);
Run Code Online (Sandbox Code Playgroud)
然后我想使用spring数据框架转到数据库,并通过下一行获取此保存的用户:
User actual = getUser(generatedId);
Run Code Online (Sandbox Code Playgroud)
我尝试使用hibernate flush方法,如:
currentSession().setFlushMode(MANUAL);
//do saving here
currentSession().flush();
Run Code Online (Sandbox Code Playgroud)
它不会将我的用户刷新到数据库中!但是,如果我没有使用@Transactional spring注释并将我的用户保存在编程弹簧事务中,那么我实现了我想要的.不幸的是,由于没有spring @Transactional,因此保存到db的用户不会回滚.因此,我的测试方法会更改后续测试方法的db和行为.
所以我需要将我的用户刷新到db里面的测试方法(不是在最后),并在测试方法结束时回滚所有对db的更改.
UPDATE建议准备方法如下:
@Transactional
public void doSave(User user){
getGenericDao().currentSession().save(user);
}
Run Code Online (Sandbox Code Playgroud)
并且在testSave中调用doSave什么都不做.执行此方法后,我仍然没有db中的用户.我设置断点并从命令行检查我的数据库.
更新非常感谢您的回复.问题是方法flush()不会将我的用户放入数据库.我尝试了Isolation.READ_UNCOMMITTED并且它没有将我的用户放入数据库.我可以实现我想要的,但前提是我在@Test方法上关闭spring事务并在程序化事务中保存.然后@Test方法不回滚,为后续的@Test方法留下保存的用户.这里保存用户的@Test方法不像删除用户的@Test方法那样危险,因为它没有回滚.因此必须对@Test方法提供Spring事务支持,我无法将我的用户(或删除)放入db.实际上,只有在@Test方法结束并且@Test方法的事务被调用后,才会将用户放入(或删除)到db中.所以我想在@Test方法的中间将我的用户保存到db中,并在@Test方法结束时回滚它
谢谢!
java hibernate spring-test hibernate-session spring-transactions
在我的项目中,我目前在编译时使用AspectJ(由于某些限制而不仅仅是Spring AOP).为了加速Eclipse的开发,我想在加载时进行编织.我成功地做到了这一点,但有一个主要的约束:为我的服务使用包含一些事务方法的接口.如果我使用其实现而不是其接口声明服务,则在调用者类中,没有编织,因此不支持任何事务.
因此,如果AspectJ支持它,如何在没有接口的情况下使用加载时编织配置AspectJ?
我创建了一个重现问题的小项目:
以下测试失败.
以下测试成功:
注入的服务是通过其接口而不是其实现来声明的(即通过"@Inject MyService service"替换"@Inject MyServiceImpl服务"),测试成功.
在编译期间执行编织(在这种情况下,配置,POM和Spring应用程序上下文明显不同).但我的目标是在加载时进行编织,以避免每次保存Java文件时的编织阶段.
Spring AOP(tx:annotation-driven mode ="proxy"),即基于代理的解决方案,用于代替AspectJ.但在这种情况下,我们遇到了自调用问题,即目标对象中调用目标对象的其他方法的方法,即使被调用的方法用@Transactional标记,也不会在运行时导致实际的事务.
AspectJ的LTW/SRC /测试/ JAVA/myCompany的/ aspectj_ltw/MyServiceImplTest.java
package mycompany.aspectj_ltw;
import static junit.framework.Assert.assertTrue;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/META-INF/spring/applicationContext.xml" })
public class MyServiceImplTest {
@Inject
MyServiceImpl service;
@Test
public void shouldBeExecutedInTransaction() {
assertTrue(this.service.isExecutedInTransaction());
}
}
Run Code Online (Sandbox Code Playgroud)
AspectJ的LTW/SRC /主/爪哇/ myCompany的/ aspectj_ltw/MyService.java
package mycompany.aspectj_ltw;
public interface MyService {
boolean isExecutedInTransaction();
}
Run Code Online (Sandbox Code Playgroud)
AspectJ的LTW/SRC /主/爪哇/ myCompany的/ aspectj_ltw/MyServiceImpl.java
package mycompany.aspectj_ltw;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; …Run Code Online (Sandbox Code Playgroud) spring ×7
java ×6
hibernate ×4
jpa ×2
transactions ×2
aop ×1
apache-kafka ×1
aspectj ×1
dozer ×1
spring-aop ×1
spring-data ×1
spring-kafka ×1
spring-test ×1