Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/goodsstock/service/GoodsStockManager.java =================================================================== diff -u -r17149 -r17162 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/goodsstock/service/GoodsStockManager.java (.../GoodsStockManager.java) (revision 17149) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/goodsstock/service/GoodsStockManager.java (.../GoodsStockManager.java) (revision 17162) @@ -66,6 +66,16 @@ public List getGoodsStock(Collection wareHouseIds, Collection goodsDefId,boolean toussedefIdOrMaterialDefId); /** + * 获取对应仓库下对应物品的库存。如果其中一个物品没有库存记录,则新开一个事务,插入新记录,并将数量设置为0,再返回。 + * 返回的记录是带锁的 + * @param wareHouseIds + * @param goodsDefId + * @param toussedefIdOrMaterialDefId + * @return + */ + public void getGoodsStockSynchronized(Collection goodsStocks, + List tousseGoodsStocksInDB,List materialGoodsStocksInDB); + /** * 获取对应仓库下,器械包或者材料的库存 * @param wareHouseId 仓库id * @param goodsDefId 器械包定义或者是材料定义的id Index: forgon-tools/src/main/java/com/forgon/tools/hibernate/ObjectDaoImpl.java =================================================================== diff -u -r16953 -r17162 --- forgon-tools/src/main/java/com/forgon/tools/hibernate/ObjectDaoImpl.java (.../ObjectDaoImpl.java) (revision 16953) +++ forgon-tools/src/main/java/com/forgon/tools/hibernate/ObjectDaoImpl.java (.../ObjectDaoImpl.java) (revision 17162) @@ -15,6 +15,7 @@ import java.util.Map; import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.hibernate.CacheMode; @@ -131,6 +132,9 @@ } public List getCollection_ForUpdate(String objectPOName,String propertyName,Collection values){ + if(CollectionUtils.isEmpty(values)){ + return null; + } final String queryString = "from " + objectPOName + " po where po." + propertyName + " in (:value_list)"; @SuppressWarnings("unchecked") List list = (List)getHibernateTemplate().executeWithNativeSession( Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/goodsstock/service/GoodsStockManagerImpl.java =================================================================== diff -u -r17149 -r17162 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/goodsstock/service/GoodsStockManagerImpl.java (.../GoodsStockManagerImpl.java) (revision 17149) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/basedatamanager/goodsstock/service/GoodsStockManagerImpl.java (.../GoodsStockManagerImpl.java) (revision 17162) @@ -19,6 +19,8 @@ import com.forgon.disinfectsystem.entity.basedatamanager.warehouse.WareHouse; import com.forgon.disinfectsystem.entity.goodsstock.GoodsStock; import com.forgon.disinfectsystem.entity.materialmanager.MaterialEntryItem; +import com.forgon.runwithtrans.model.RunWithTransNewTask; +import com.forgon.runwithtrans.service.RunWithTransNewManager; import com.forgon.tools.MathTools; import com.forgon.tools.db.DatabaseUtil; import com.forgon.tools.hibernate.BasePoManagerImpl; @@ -31,12 +33,13 @@ * @since 2016-03-21 */ public class GoodsStockManagerImpl extends BasePoManagerImpl implements GoodsStockManager { + + private RunWithTransNewManager runWithTransNewManager; - public GoodsStockManagerImpl() { - super(GoodsStock.class); - // TODO Auto-generated constructor stub + public void setRunWithTransNewManager( + RunWithTransNewManager runWithTransNewManager) { + this.runWithTransNewManager = runWithTransNewManager; } - /** * 获取包定义的id跟包定义的实例之间的对应Map * @param goodsStockList @@ -79,7 +82,7 @@ return objectDao.findBySql_ForUpdate(GoodsStock.class.getSimpleName(), sql); } - public synchronized List saveOrUpdateGoodsStock(List goodsStockList, String mode){ + public List saveOrUpdateGoodsStock(List goodsStockList, String mode){ List retInfo = goodsStockList; if(!MODE_INSTOCK.equals(mode) && !MODE_OUTSTOCK.equals(mode)){ throw new RuntimeException("参数mode="+mode+"值非法"); @@ -106,17 +109,18 @@ } private void doInStock(List goodsStockList) { GoodsStock goodsStock = null; - Set wareHouseIds = new HashSet(); - Set tousseDefIds = new HashSet(); - for(GoodsStock gs : goodsStockList){ - if(DatabaseUtil.isPoIdValid(gs.getWareHouseId())){ - wareHouseIds.add(gs.getWareHouseId()); - } - if(DatabaseUtil.isPoIdValid(gs.getTousseDefinitionId())){ - tousseDefIds.add(gs.getTousseDefinitionId()); - } - } - List goodsStockInDB = getGoodsStock(wareHouseIds, tousseDefIds, true); +// Set wareHouseIds = new HashSet(); +// Set tousseDefIds = new HashSet(); +// for(GoodsStock gs : goodsStockList){ +//// if(DatabaseUtil.isPoIdValid(gs.getWareHouseId())){ +//// wareHouseIds.add(gs.getWareHouseId()); +//// } +//// if(DatabaseUtil.isPoIdValid(gs.getTousseDefinitionId())){ +//// tousseDefIds.add(gs.getTousseDefinitionId()); +//// } +// } + List goodsStockInDB = new ArrayList<>(); + getGoodsStockSynchronized(goodsStockList,goodsStockInDB,null); for(GoodsStock goodsStockTemp : goodsStockList){ if(goodsStockTemp.getAmount() == null || goodsStockTemp.getAmount() == 0){ @@ -142,6 +146,7 @@ // } if(goodsStock == null){ goodsStock = new GoodsStock(); + goodsStock.setGoodsType(GoodsStock.TYPE_TOUSSE); goodsStock.setWareHouseId(goodsStockTemp.getWareHouseId()); goodsStock.setWareHouseName(goodsStockTemp.getWareHouseName()); goodsStock.setMaterialDefinitionId(goodsStockTemp.getMaterialDefinitionId()); @@ -184,27 +189,11 @@ } Map idTousseDefinitionMap = getIDTousseDefinitionMap(goodsStockList); - Set wareHouseIds = new HashSet(); - Set tousseDefIds = new HashSet(); - Set goodsNames = new HashSet(); - Set materialDefIds = new HashSet(); - for(GoodsStock gs : goodsStockList){ - if(DatabaseUtil.isPoIdValid(gs.getWareHouseId())){ - wareHouseIds.add(gs.getWareHouseId()); - } - if(StringUtils.isNotBlank(gs.getName())){ - goodsNames.add(gs.getName()); - } - - if(DatabaseUtil.isPoIdValid(gs.getTousseDefinitionId())){ - tousseDefIds.add(gs.getTousseDefinitionId()); - } - if(DatabaseUtil.isPoIdValid(gs.getMaterialDefinitionId())){ - materialDefIds.add(gs.getMaterialDefinitionId()); - } - } - List toussedefGoodsStockListInDb = getGoodsStock(wareHouseIds, tousseDefIds, true); - List materialDefGoodsStockListInDb = getGoodsStock(wareHouseIds,materialDefIds,false); + List toussedefGoodsStockListInDb = new ArrayList<>(); + List materialDefGoodsStockListInDb = new ArrayList<>(); + + getGoodsStockSynchronized(goodsStockList,toussedefGoodsStockListInDb,materialDefGoodsStockListInDb); + List toUpdateGoodsStock = new ArrayList(); //需要更新库存数量的库存记录 for(GoodsStock goodsStockTemp : goodsStockList){ if(goodsStockTemp.getAmount() == null || goodsStockTemp.getAmount() == 0){ @@ -226,6 +215,7 @@ }}); //判断库存数量是否大于退/出库数量 if(goodsStock == null){ + //这里应该是不可能再进入了,除非参数中,包定义id或者仓库id值非法 int amount = getTousseInstanceStock(goodsStockTemp.getWareHouseId(),goodsStockTemp.getTousseDefinitionId()); goodsStock = saveTousseStock(goodsStockTemp.getWareHouseId(),td, amount); toussedefGoodsStockListInDb.add(goodsStock); @@ -289,6 +279,7 @@ }}); if(find == null){ find = new GoodsStock(); + find.setGoodsType(GoodsStock.TYPE_MATERIAL); find.setMaterialDefinitionId(materialDefId); find.setPrice(price); outStockInfo.add(find); @@ -314,15 +305,17 @@ if(CollectionUtils.isEmpty(goodsStockList)){ return goodsStockList; } - Set wareHouseIds = new HashSet(); - Set materialDefIds = new HashSet(); - for(GoodsStock gs : goodsStockList){ - wareHouseIds.add(gs.getWareHouseId()); - if(DatabaseUtil.isPoIdValid(gs.getMaterialDefinitionId())){ - materialDefIds.add(gs.getMaterialDefinitionId()); - } - } - List materialDefGoodsStockListInDb = getGoodsStock(wareHouseIds,materialDefIds,false); +// Set wareHouseIds = new HashSet(); +// Set materialDefIds = new HashSet(); +// for(GoodsStock gs : goodsStockList){ +//// wareHouseIds.add(gs.getWareHouseId()); +// if(DatabaseUtil.isPoIdValid(gs.getMaterialDefinitionId())){ +// materialDefIds.add(gs.getMaterialDefinitionId()); +// } +// } + List materialDefGoodsStockListInDb = new ArrayList<>(); + getGoodsStockSynchronized(goodsStockList, null, materialDefGoodsStockListInDb); + //List materialDefGoodsStockListInDb = getGoodsStock(wareHouseIds,materialDefIds,false); List toUpdateGoodsStock = new ArrayList(); //需要更新库存数量的库存记录 for(GoodsStock goodsStockTemp : goodsStockList){ if(goodsStockTemp.getAmount() == null || goodsStockTemp.getAmount() == 0){ @@ -586,4 +579,84 @@ addToList(goodsStockList, ti); } } + + @Override + public synchronized void getGoodsStockSynchronized(Collection goodsStockList, + List tousseGoodsStocksInDB, + List materialGoodsStocksInDB) { + Set wareHouseIds = new HashSet(); + Set tousseDefIds = new HashSet(); + Set materialDefIds = new HashSet(); + for(GoodsStock gs : goodsStockList){ + if(DatabaseUtil.isPoIdValid(gs.getWareHouseId())){ + wareHouseIds.add(gs.getWareHouseId()); + } + + if(DatabaseUtil.isPoIdValid(gs.getTousseDefinitionId())){ + tousseDefIds.add(gs.getTousseDefinitionId()); + } + if(DatabaseUtil.isPoIdValid(gs.getMaterialDefinitionId())){ + materialDefIds.add(gs.getMaterialDefinitionId()); + } + } + List toussedefGoodsStockListInDb = getGoodsStock(wareHouseIds, tousseDefIds, true); + List materialDefGoodsStockListInDb = getGoodsStock(wareHouseIds,materialDefIds,false); + if(materialGoodsStocksInDB != null && CollectionUtils.isNotEmpty(materialDefGoodsStockListInDb)){ + materialGoodsStocksInDB.addAll(materialDefGoodsStockListInDb); + } + if(tousseGoodsStocksInDB != null){ + tousseGoodsStocksInDB.addAll(toussedefGoodsStockListInDb);//先插入已有的库存 + List gsToInsert = new ArrayList<>(); + //针对器械包,如果有没有查到的数据,则插入新数据,新入的数据,数量为0 + for(GoodsStock gs : goodsStockList){ + if(gs.tousseType()){ + GoodsStock find = findTousseGoodsStock(toussedefGoodsStockListInDb, + gs.getWareHouseId(), gs.getTousseDefinitionId()); + if(find == null){ + //还没有对应的库存记录,需要重新创建 + find = findTousseGoodsStock(gsToInsert, + gs.getWareHouseId(), gs.getTousseDefinitionId()); + if(find == null){ + //也还没有添加到待插入的集合中,这下真的要插入了 + //如果仓库id和包定义id有效,才插入,否则插入了,也没有用 + if(DatabaseUtil.isPoIdValid(gs.getTousseDefinitionId()) + &&DatabaseUtil.isPoIdValid(gs.getWareHouseId())){ + find = new GoodsStock(); + find.setGoodsType(GoodsStock.TYPE_TOUSSE); + find.setWareHouseId(gs.getWareHouseId()); + find.setWareHouseName(gs.getWareHouseName()); + find.setMaterialDefinitionId(gs.getMaterialDefinitionId()); + find.setTousseDefinitionId(gs.getTousseDefinitionId()); + find.setName(gs.getName()); + find.setGoodsType(gs.getGoodsType()); + find.setOrgUnitCode(gs.getOrgUnitCode()); + find.setOrgUnitName(gs.getOrgUnitName()); + find.setAmount(0); //新添加的记录,数量为0 + gsToInsert.add(find); + } + } + } + } + + } + List newIds = new ArrayList(); + //新开一个事务,执行插入操作,操作完成,事务结束,立马提交到数据库 + runWithTransNewManager.runWith_TRANS_NEW(new RunWithTransNewTask() { + @Override + public void runTask() { + for(GoodsStock gs : gsToInsert){ + save(gs); + newIds.add(gs.getId()); + } + } + }); + /** + * 获取新插入的对象,并锁定,加入到器械包的返回集合中 + */ + List newItems = getCollectionForUpdate("id", newIds); + if(CollectionUtils.isNotEmpty(newItems)){ + tousseGoodsStocksInDB.addAll(newItems); + } + } + } } Index: ssts-web/src/test/java/test/forgon/disinfectsystem/goodsstock/service/GoodsStockManagerTests.java =================================================================== diff -u -r17148 -r17162 --- ssts-web/src/test/java/test/forgon/disinfectsystem/goodsstock/service/GoodsStockManagerTests.java (.../GoodsStockManagerTests.java) (revision 17148) +++ ssts-web/src/test/java/test/forgon/disinfectsystem/goodsstock/service/GoodsStockManagerTests.java (.../GoodsStockManagerTests.java) (revision 17162) @@ -76,6 +76,7 @@ private GoodsStock newGoodsStock(int amount) { GoodsStock gs = new GoodsStock(); gs.setAmount(amount); + gs.setGoodsType(GoodsStock.TYPE_TOUSSE); gs.setWareHouseId(wareHouseId); gs.setTousseDefinitionId(tousseDefinitionId); return gs; @@ -205,6 +206,14 @@ @Override public void runTask() { goodsStockManager.saveOrUpdateGoodsStock(list, GoodsStockManager.MODE_INSTOCK); + try {//延迟事务 + Thread.sleep(10); + Thread.sleep(10); + Thread.sleep(10); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } }); Index: forgon-tools/src/main/java/com/forgon/tools/hibernate/BasePoManager.java =================================================================== diff -u -r16654 -r17162 --- forgon-tools/src/main/java/com/forgon/tools/hibernate/BasePoManager.java (.../BasePoManager.java) (revision 16654) +++ forgon-tools/src/main/java/com/forgon/tools/hibernate/BasePoManager.java (.../BasePoManager.java) (revision 17162) @@ -76,7 +76,7 @@ * 获取属性值属于对应集合的所有对象,并加锁,以便可以更新 * @param property * @param values - * @return + * @return 成功返回对应对象的集合,否则返回null */ public List getCollectionForUpdate(String property,Collection values); /** Index: ssts-web/src/test/java/test/forgon/disinfectsystem/AbstractCSSDTest.java =================================================================== diff -u -r17149 -r17162 --- ssts-web/src/test/java/test/forgon/disinfectsystem/AbstractCSSDTest.java (.../AbstractCSSDTest.java) (revision 17149) +++ ssts-web/src/test/java/test/forgon/disinfectsystem/AbstractCSSDTest.java (.../AbstractCSSDTest.java) (revision 17162) @@ -739,63 +739,73 @@ String jsonParam = stringer.toString(); return jsonParam; } - /** + * + */ + private void initCSSDDataWithTrans(){ + runWithTransNewManager.runWith_TRANS_NEW(new RunWithTransNewTask() { + @Override + public void runTask() { + /** + * 清空基础数据、业务数据等表 + */ + cleanAll(); + /** + * 初始化角色、权限、人员(基础信息及条码)、科室(基础信息及条码)以及各表间的关联数据 + */ + initDirectoryInfo(); + + /** + * 初始化任务组、一次性物品类型、仓库、篮筐、科室供应室配置、灭菌炉等 + */ + initBaseData(); + + /** + * 初始化供应室服务临床科室配置 + */ + initCssdServiceDepts(); + + /** + * 初始化材料与器械包定义(器械包定义数量:11) + */ + initMaterialAndTousseData(); + + /** + * 初始化消毒物品定义(器械包定义数量:3) + */ + initDisinfectToussesData(); + + /** + * 初始化供应室处理器械包配置 + */ + initCssdHandleTousses(); + + /** + * 初始化一次性物品定义 + */ + initDiposableGoodsData(); + + /** + * 初始化聚合包定义(器械包定义数量:1) + */ + bulidComboTousseDefinition(); + + /** + * 初始化失效期 + */ + initExpirationDateInfo(); + + ForgonThreadLocalResourceManager.afterRequest(); + +// createDiposableGoods(); + } + }); + } + /** * 测试数据初始化 */ public void initCSSDData() { - /** - * 清空基础数据、业务数据等表 - */ - cleanAll(); - /** - * 初始化角色、权限、人员(基础信息及条码)、科室(基础信息及条码)以及各表间的关联数据 - */ - initDirectoryInfo(); - - /** - * 初始化任务组、一次性物品类型、仓库、篮筐、科室供应室配置、灭菌炉等 - */ - initBaseData(); - - /** - * 初始化供应室服务临床科室配置 - */ - initCssdServiceDepts(); - - /** - * 初始化材料与器械包定义(器械包定义数量:11) - */ - initMaterialAndTousseData(); - - /** - * 初始化消毒物品定义(器械包定义数量:3) - */ - initDisinfectToussesData(); - - /** - * 初始化供应室处理器械包配置 - */ - initCssdHandleTousses(); - - /** - * 初始化一次性物品定义 - */ - initDiposableGoodsData(); - - /** - * 初始化聚合包定义(器械包定义数量:1) - */ - bulidComboTousseDefinition(); - - /** - * 初始化失效期 - */ - initExpirationDateInfo(); - - ForgonThreadLocalResourceManager.afterRequest(); - -// createDiposableGoods(); + initCSSDDataWithTrans(); } private void initExpirationDateInfo(){ Index: ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/goodsstock/GoodsStock.java =================================================================== diff -u -r17152 -r17162 --- ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/goodsstock/GoodsStock.java (.../GoodsStock.java) (revision 17152) +++ ssts-basedata/src/main/java/com/forgon/disinfectsystem/entity/goodsstock/GoodsStock.java (.../GoodsStock.java) (revision 17162) @@ -12,6 +12,8 @@ import org.hibernate.annotations.CacheConcurrencyStrategy; import com.fasterxml.jackson.annotation.JsonFilter; +import com.forgon.tools.db.DatabaseUtil; +import com.forgon.tools.string.StringTools; /** * 器械包、材料库存表 @@ -202,5 +204,13 @@ public void setSupplier(String supplier) { this.supplier = supplier; } + /** + * 判断是否是器械包类型的库存.如果类型为器械包或者有包定义id有效(现在的逻辑是包定义id有效就是器械包),则是器械包的库存 + * @return + */ + public boolean tousseType(){ + return StringTools.equals(TYPE_TOUSSE, goodsType) + || DatabaseUtil.isPoIdValid(tousseDefinitionId); + } }