2016-04-20 23 views
3

我有以下类:java的弹簧4 @Transactional嵌套事务问题

@Transactional 
public class MyClass{ 
    @Transactional(propagation=Propagation.REQUIRES_NEW) 
    public void method1(){ 
     .... 
     myDao.update(entity); 
    } 

    public void method2(){ 
     method1();    
     //I need to be sure that data was persisted to DB and find the entity by id  

     MyEntity ent=myDao.find(entityId); 
     //entity is not updated here 
    } 

} 

但事实上我不能从方法2块中读取更新的实体。如何实现这一目标? 我需要在method2中调用method1()后更新的值,因此应该提交method1中的事务并且结果可见。怎么做?

+0

由于@Transactional在类级别method2和method1将在同一个事务中运行。在method1之后不会有提交,但您应该在method2中看到方法1的保存/更新结果。如果你不这样做,那么问题在别处...... –

回答

2

你将不得不在从另一个类中这样做,因为@Transactional在调用本地方法时不服从(这是Spring代理的工作方式,本地方法调用通过调用this绕过事务代理)。

该解决方案将可能看起来是这样的:

class Wrapper { 
    public void performAction() { 
     myClass.method1(); 
     myClass.find(entityId); 
    } 
} 
1

我已经重新创建你的情况一样(内嵌数据库): 首先,我添加任何东西到数据库,如:

public void initialize() { 
    Sample startEntity = new Sample(); 
    startEntity.setId(1); 
    startEntity.setName("Start name"); 
    sampleRepository.saveSample(startEntity); 
    sampleRepository.flush(); // <-- just to make sure scenario is recreated 
    sampleRepository.clear(); // same as above 
    LOGGER.info(sampleRepository.findSampleById(1)); 
    sampleRepository.clear(); // same as above above :D 
} 

之后,我们在数据库中获得了一个实体Sample(所有事务结束并且清除缓存);

控制台:

Hibernate: insert into sample (name, id) values (?, ?) 
Hibernate: select sample0_.id as id1_0_0_, sample0_.name as name2_0_0_ from sample sample0_ where sample0_.id=? 
2016-04-20 15:58:21.762 INFO 5764 --- [   main] com.patrykwoj.service.BasicServiceTest : Sample [id=1, name=Start name] 

现在你举的例子:

Hibernate: select sample0_.id as id1_0_0_, sample0_.name as name2_0_0_ from sample sample0_ where sample0_.id=? 
2016-04-20 16:02:17.903 INFO 5044 --- [   main] com.patrykwoj.service.SampleService  : Sample [id=1, name=TestSample before update but after create] 
Hibernate: update sample set name=? where id=? 
2016-04-20 16:02:17.903 INFO 5044 --- [   main] com.patrykwoj.StackOverfloApplication : Method2 is over 

主要类:

@Override 
public void run(String... strings) throws Exception { 
    basicServiceTest.initialize(); 
    sampleService.method2(); 
    LOGGER.info("Method2 is over"); 
} 

@Transactional 
@Component 
public class SampleService { 

private static final Logger LOGGER = Logger.getLogger(SampleService.class); 

@Autowired 
SampleRepository sampleRepository; 

@Transactional (propagation = Propagation.REQUIRES_NEW) 
public void method1() { 
    Sample someSample = new Sample(); 
    someSample.setId(1); 
    someSample.setName("TestSample before update but after create"); 
    sampleRepository.updateSample(someSample); 
} 

public void method2() { 
    method1(); 
    // I need to be sure that data was persisted to DB and find the entity by id 

    Sample someSampleAfterUpdate = sampleRepository.findSampleById(1); //I believe that at that point sample is found in L-1 cache not in db directry. 
    // entity is not updated here 
    LOGGER.info(someSampleAfterUpdate); //in this point, transaction is not over yet, so you wont notice change in database.. 
} 
} 

,然后从代码执行安慰

在我看来,一切看起来不错。它按预期工作。我在你的代码中做了一些评论,但是控制台输出应该是清楚的。