2016-06-08 46 views
1

我的春天啓動的應用程序進行更新有以下類別:現有實體不能使用Spring引導

(JPA實體)

@Entity 
@Table(name = "board") 
public class Board { 
    public static final int IN_PROGRESS = 1; 
    public static final int AFK   = 2; 
    public static final int COMPLETED = 3; 

    @Column(name = "id") 
    @Generated(GenerationTime.INSERT) 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Id 
    private Long id; 

    @Column(name = "status", nullable = false) 
    private int status = IN_PROGRESS; 
} 

BoardRepository(JPA庫)

public interface BoardRepository extends JpaRepository<Board, Long> {} 

CommonBoardService(基本服務)

public interface CommonBoardService { 
    Board save(Board board); 
    Board update(Board board, int status); 
} 

CommonBoardServiceImpl(基本服務實現)

@Service 
@Transactional 
public class CommonBoardServiceImpl implements CommonBoardService { 
    @Autowired 
    private BoardRepository boardRepository; 

    public Board save(final Board board) { 
    return boardRepository.save(board); 
    } 

    @Transactional(propagation = Propagation.REQUIRES_NEW) 
    public Board update(final Board board, final int status) { 
    board.setStatus(status); 

    return save(board); 
    } 
} 

BoardService(特定服務接口)

public interface BoardService { 
    Board startBoard(); 
    void synchronizeBoardState(Board board); 
} 

BoardServiceImpl(特定服務實現)

@Service 
@Transactional 
public class BoardServiceImpl implements BoardService { 
    @Autowired 
    private CommonBoardService commonBoardService; 

    public Board startBoard() { return new Board(); } 

    public void synchronizeBoardState(final Board board) { 
    if (board != null && inProgress(board)) { 
     if (!canPlayWithCurrentBoard(board)) { 
     commonBoardService.update(board, Board.AFK); 
     } 
     else { 
     commonBoardService.update(board, Board.COMPLETED); 
     } 
    } 
    } 

    private boolean canPlayWithCurrentBoard(final Board board) { 
    return !inProgress(board); 
    } 

    private boolean inProgress(final Board board) { 
    return board != null && board.getStatus() == Board.IN_PROGRESS; 
    } 
} 

BoardServiceTest(單元測試)

1. @RunWith(SpringJUnit4ClassRunner.class) 
2. @Transactional 
3. public class BoardServiceTest { 
4. @Autowired 
5. private BoardRepository boardRepository; 
6. 
7. @Autowired 
8. private BoardService  boardService; 
9. @Autowired 
10. private CommonBoardService commonBoardService; 
11. 
12. @Test 
13. public void testSynchronizeBoardStatus() { 
14.  Board board = boardService.startBoard(); 
15. 
16.  board = commonBoardService.save(board); 
17. 
18.  assertEquals(1, boardRepository.count()); 
19. 
20.  boardService.synchronizeBoardState(board); 
21. 
22.  assertEquals(1, boardRepository.count()); 
23. } 
24. } 

該測試線路22上失敗,錯誤java.lang.AssertionError: Expected :1 Actual:2。 Hibernate SQL日誌顯示INSERT在第20行而不是UPDATE被觸發。由於我在整個測試中使用了相同的Board對象,因此我預計第20行將觸發UPDATE而不是INSERT

任何人都可以解釋爲什麼會發生這種情況,以及如何獲得預期的行爲(第20行的UPDATE)?

+0

你的TestDataSourceConfiguration.class指向哪個數據庫?它是否有您要更新的主板實體? – koder23

+0

BoardServiceTest中的boardService和commonBoardService是什麼? 'boardService.startBoard(admin)'和'commonBoardService.save(板)'是什麼樣的?據推測,第一個是創建一個新的「板」,第二個保存它?此外,「Board」和「User」類的代碼是什麼樣的?如果您可以創建一個小樣本來演示問題,那可能會更好,因爲需要覆蓋很多代碼。 – manish

+0

@ koder23,謝謝你的回覆。我正在使用postgres。是的,它應該有'board board = boardService.startBoard(admin);' - 創建新的電路板,並且實體的ID等於1. –

回答

1

罪魁禍首是這條線:@Transactional(propagation = Propagation.REQUIRES_NEW)。讓我們看看測試用例執行時會發生什麼。

  • 因爲BoardServiceTest@Transactional註解一個新的事務開始時BoardServiceTest.testSynchronizeBoardStatus開始執行。
  • 第14行創建一個新的Board實例。
  • 第16行嘗試保存第14行創建的Board實例並觸發數據庫INSERT
  • 第20行間接調用CommonBoardServiceImpl.update,其中注有@Transactional(propagation = Propagation.REQUIRES_NEW)。這會暫停正在進行的交易(請參閱JavaDocs for Propagation),該交易目前尚未提交或回滾。
  • CommonBoardServiceImpl.update依次嘗試保存傳遞給它的Board實例。
  • 給定實例未被識別爲現有實例,因爲將其保存到數據庫的事務當前處於掛起狀態。因此,它被假定爲一個新實例並導致第二個INSERT
  • 第20行現在完成,它提交了內部交易,開始時間爲CommonBoardServiceImpl.update。外部交易恢復。
  • 第22行發現一個髒會話並在觸發SELECT查詢之前將其刷新。這意味着數據庫中現在有兩個實例,因此測試失敗。

刪除@Transactional(propagation = Propagation.REQUIRES_NEW)確保整個測試在同一個事務中執行並因此通過。

相關問題