2016-04-20 5 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でDBから更新エンティティを読み取ることができません。これを達成する方法は? method1()の呼び出し後に値を更新するにはmethod2で必要なので、method1のトランザクションをコミットして結果を表示する必要があります。どうやってするか?

+0

@Transactionalがクラス・レベルであるため、method2とmethod1は同じトランザクションで実行されます。 method1の後にコミットはありませんが、method2のmethod1からのセーブ/アップデートの結果が表示されます。あなたがしなければ問題は他の場所にある... –

答えて

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 
} 

データベース内に1つのエンティティ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] 

今すぐあなたの例:その後、

@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.. 
} 
} 

そして、あなたのコードの実行からコンソール:

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"); 
} 

私の意見では、すべてがよく見えます。それは期待どおりに働いた。私はあなたのコードでいくつかのコメントをしましたが、とにかくコンソールの出力は明らかになります。

関連する問題