2016-04-20 59 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.. 
} 
} 

,然後從代碼執行安慰

在我看來,一切看起來不錯。它按預期工作。我在你的代碼中做了一些評論,但是控制檯輸出應該是清楚的。