2017-02-21 78 views
2

首先看看下面的代碼,我有三個主要模型來管理StoreHouseStoreHouseInvetory的和其他模型命名爲StoreHouseInventoryLock臨時鎖定/解鎖一些金額StoreHouseInvetory的其他進程要使用這些模型:使用session.save保存對象時,Hibernate不刷新會話?

public class StoreHouse { 
    private String name; 
    private Double currentAmount; 
} 

public class StoreHouseInventory { 
    private StoreHouse storeHouse; 
    private Good  good; 
    private Double  amount; 
} 

public class StoreHouseInventoryLock { 
    private StoreHouseInventory  inventory; 
    private Double     amount; 
} 

@Service 
public class PermitService implements IPermitService { 

    @Autowired 
    private IStoreHouseInventoryLockService storeHouseInventoryLockService; 

    @Autowired 
    private IStoreHouseService storeHouseService; 

    @Override 
    @Transactional 
    public void addDetailToPermitFromStoreHouseInventory(long permitId, long storeHouseId, long inventoryId, double amount) { 

     // do some business logic here 

     /* save is simple method 
     * and uses Session.save(object) 
     */ 
     storeHouseInventoryLockService.add(inventoryId, +amount); 

     // do some business logic here 
     storeHouseService.syncCurrentInventory(storeHouseId); 
    } 
} 

@Service 
public class StoreHouseService implements IStoreHouseService { 

    @Autowired 
    private IStoreHouseInventoryService storeHouseInventoryService; 

    @Autowired 
    private IStoreHouseInventoryLockService storeHouseInventoryLockService; 

    @Transactional 
    public void syncCurrentInventory(storeHouseId) { 
     /* is a simeple method that use query like below 
     * select sum(e.amount) 
     * from StoreHouseInventory 
     * where e.storeHouse.id = :storeHouseId 
     */ 
     Double sumOfInventory = storeHouseInventoryService.sumOfInventory(storeHouseId); 
     /* is a simeple method that use query like below 
     * select sum(e.amount) 
     * from StoreHouseInventoryLock 
     * where e.storeHouseInventory.storeHouse.id = :storeHouseId 
     */ 
     Double sumOfLock = storeHouseInventoryService.sumOfLock(storeHouseId); 

     // load method is a simple method to load object by it's id 
     // and used from Session.get(String entityName, Serializable id) 
     StoreHouse storeHouse = this.load(storeHouseId); 
     storeHouse.setCurrentAmount(sumOfInventory - sumOfLock); 

     this.save(storeHouse); 
    } 
} 

的問題是,當storeHouseInventoryService.sumOfLock被稱爲StoreHouseService.syncCurrentInventory,它不會是storeHouseInventoryLockService.add方法的認識變化PermitService.addDetailToPermitFromStoreHouseInventory方法,並錯誤地calcuates鎖的總和。

我想這是因爲會話沒有被刷新,當我打電話storeHouseInventoryLockService.add。如果這是真的,爲什麼在這個變化期間hibernate沒有會話會話?如果不是,我該怎麼辦?

+0

對於初學者來說,你的代碼是有缺陷的,你不應該發現異常併吞下,你的代碼會打破適當的tx管理。數據在相同的事務中可見,並且hibernate在調度數據庫時自動刷新掛起的更改。如果這沒有發生,你可能會在冬眠的背後做些事情。添加同步方法(和相關對象)的代碼。 –

+0

對不起,這是我的錯,我刪除了'try,catch'塊 –

回答

0

由於IStoreHouseInventoryLockService.add是從一個已經有一個事務附加到它的方法中調用的,所以同一個事務傳播到add方法,因此直到外部addDetailToPermitFromStoreHouseInventory完成後才發生刷新。

爲你一個快速的解決辦法是,以紀念add方法與REQUIRES_NEW事務傳播類型:該方法完成

@Transactional(propagation=Propagation.REQUIRES_NEW) 
public void add(..){..} 

現在,即使有外部事務,所有的持久性變化將是在退出時刷新數據庫。

+0

在同一個事務中,數據已經可見,你不需要新的事務。如果數據不可見,還有其他事情正在進行。 –

+0

@ M.Deinum,你的意思是沒有必要使用@Transactional(propagation = Propagation.REQUIRES_NEW)'?我怎麼解決這個問題? –

+0

在sumOfLock方法中查詢期間..也許更改不會在調用之前刷新到數據庫。理論上是的,如果查詢使用當前事務中受影響的實體,則應該是。 –

0

如果當前正在執行的查詢與未刷新的表語句不重疊,則可以安全地忽略刷新。

+0

https://vladmihalcea.com/2014/08/13/the-dark-side-of-hibernate-auto-flush/ –