标签: spring-transactions

Spring Transactions和hibernate.current_session_context_class

我有一个使用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 hibernate hibernate-session spring-transactions

21
推荐指数
1
解决办法
3万
查看次数

Spring JPA存储库事务性

关于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

java jpa spring-transactions spring-data

20
推荐指数
1
解决办法
1万
查看次数

Hibernate集合与任何会话无关

我在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)

我不能明白为什么sessionnull.有人会解释这个并提出解决方案吗?

编辑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)

java spring hibernate spring-transactions

18
推荐指数
3
解决办法
4万
查看次数

在@Configuration类中设置Spring中的注释驱动事务

因此,在最新版本的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交易.如果有人对如何做到这一点有任何想法,或者如果这是不可能的,请告诉我.

谢谢!

java configuration spring transactions spring-transactions

17
推荐指数
1
解决办法
3万
查看次数

在数据库和Kafka生产者之间同步事务

我们有一个微服务架构,其中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的框架。)

我能想到的一些选择:

  1. 不要将数据写入数据库:仅将其写入Kafka。然后使用使用者(在服务A中)更新数据库。看来这可能不是最有效的,并且会出现问题,因为用户调用的服务无法立即看到它应该刚刚创建的数据库更改。
  2. 不要直接写到Kafka:只写数据库,并使用Debezium之类的东西向Kafka报告更改。这里的问题是,更改是基于单个数据库记录的,而要存储在Kafka中的重要业务事件可能涉及多个表中数据的组合。
  3. 首先写入数据库(如果失败,则不执行任何操作,仅引发异常)。然后,在写入Kafka时,假设写入可能会失败。使用内置的自动重试功能可以使其保持尝试一段时间。如果最终完全失败,请尝试写入死信队列,并为管理员创建某种手动机制以将其解决。而且,如果写入DLQ失败(即Kafka完全关闭),只需以其他方式(例如,记录到数据库)进行记录,然后再次创建某种手动机制供管理员进行分类即可。

是否有人对以上内容有任何想法或建议,或者能够纠正上述假设中的任何错误?

提前致谢!

distributed-transactions spring-transactions apache-kafka spring-kafka

17
推荐指数
3
解决办法
3727
查看次数

防止Dozer触发Hibernate延迟加载

我正在使用Spring事务,因此当POJO到DTO转换发生时,事务仍处于活动状态.

我想阻止Dozer触发延迟加载,以便隐藏的sql查询永远不会发生:所有提取都必须通过HQL显式完成(以获得对性能的最佳控制).

  1. 这是一个好习惯(我无法在任何地方找到它)?

  2. 怎么安全地做?

我在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会话,并不会阻止延迟加载.

java spring hibernate dozer spring-transactions

16
推荐指数
3
解决办法
1万
查看次数

Spring应用程序有Cglib2AopProxy警告

在开始我的应用程序时,我会收到大量警告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 />.我能做些什么来消除这些警告,或者更好的是,将这些类别排除在编织方面?

spring spring-aop spring-transactions

16
推荐指数
2
解决办法
2万
查看次数

仅在确定提交但在提交之前拦截事务

Context是Java - 带有Hibernate和Spring的JPA.

我们来看两阶段提交协议的场景(但只有一个资源):

  1. 查询从应用程序提交

  2. 投票是/否(在我们的案例中来自数据库)

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

java spring jpa transactions spring-transactions

16
推荐指数
1
解决办法
933
查看次数

如何在活跃的spring事务中将数据刷新到db?

我想使用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

15
推荐指数
3
解决办法
3万
查看次数

如何使用无接口的加载时编织配置AspectJ

在我的项目中,我目前在编译时使用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)

aop spring aspectj spring-transactions load-time-weaving

14
推荐指数
1
解决办法
1万
查看次数