2017-11-26 4 views
0

데이터베이스의 레코드를 주기적으로 업데이트해야하는 방법이 있습니다.봄 : TimerTask를 사용할 때 Autowired 리포지토리에 쓸 수 없습니다.

@Service 
public class MyService { 

    @Autowired 
    private MyRepository myRepository; 

    private Boolean flag = false; 

    @Transactional 
    public int method1(Args args) { 
     // do something 
     if (!flag) { 
      method2() 
     } 
     return x; 
    } 

    @Transactional 
    public int method2(Args args) { 
     polling = true; 
     Timer t = new Timer(); 
     t.scheduleAtFixedRate(new TimerTask() { 
      @Override 
      public void run() { 
       List<Records> records = myRepository.getRecords() 

       for (Record record : records) { 

        // prints the Id of each record. Now, they are all have Id=1 
        System.out.println(record.getId()); 

        // setting the record's Id to 5 
        record.setId(5); 

        // prints '5' 
        System.out.println(record.getId()); 
       } 

      } 
     }, 10, 1000*60*4 
    } 
} 

Method1은 Method2를 호출합니다. Method2는 run() 함수 내에서 4 분마다 코드를 실행합니다. run() 내의 코드는 스케줄없이 제대로 작동합니다 (각 레코드의 ID를 가져 와서 인쇄하고 ID를 5로 설정하여 db를 업데이트합니다). 그러나 이제는 TimerTask를 사용하여 Id를 검색하고 인쇄하며 각 레코드의 Id를 5로 설정하고 심지어 database.get (Id)에 '5'를 인쇄하여 데이터베이스가 있다고 믿게합니다 새로운 ID로 업데이트되었습니다. 실제로 데이터베이스를 검사 할 때 Id가 실제로 5로 업데이트되지 않았 음을 알았습니다. 원래 ID는 그대로 유지됩니다. ID가 업데이트되는 것 같아서 왜 이런 일이 발생하는지 잘 모르겠습니다. 이것은 새로운 스레드를 만드는 TimerTask와 관련이 있습니까?

+1

당신은'@ Transactional' 메소드에서'TimerTask'를 돌리고 있습니다 만, 당신의 작업 메소드는 트랜잭션 자체가 아닙니다. 대신 @ @ Scheduled를 사용하십시오. – chrylis

+0

@Scheduled를 사용하고 작동하도록했습니다. 감사! – 78t66

답변

0

@Transational은 DB에 대해 하나의 TRANSACTION을 감싸는 것으로 가정하므로 @Transactional 함수가 한 가지 일을하고 즉각 내보내고 나갈 수 있어야합니다. DB가 커밋되거나 롤백 될 것입니다. 트랜잭션 고립 레벨 (당신이 연구하고 싶지만 아마도 필요하지 않은 또 다른 토픽)에 따라 @Transactional 내부에서 진행되는 thnigs는 그 함수가 실제로 반환 할 때까지 db에 쓰여지지 않습니다. 아마 당신이 놓친 것이 전부입니다. Chrylis는 '반복되는 일'을 위해 @Scheduled를 사용하는 것이 옳았지 만, 실제 문제는 내가 진술 한 것인데, 그에 대한 모든 존경심을 가지고 있습니다.

요약 : @Scheduled 함수 호출을 @Transactional 함수 (수행하려는 각 DB 트랜잭션마다)로 만든 다음 작동합니다.

관련 문제