本文基于上篇《MongoDB 与关系型数据库(Oracle)关联统计实践方案 》的设计,采用数据冗余方案,通过增加更新MongoDB中文档状态和时间,来满足查询需求,提高查询开发效率和代码的执行效率。
在系统设计中,已经实现了更新流程实例状态为流程办结状态(系统中定义为“2”),由于初次使用MongoDB,设计中忽略了文档状态的标识。
为此,需要完善系统,以提高系统查询性能,避免不合理的关联查询。其解决方案如下:
- 利用现有更新流程实例状态的服务“updateStatus”;
- 避免改动代码,尽量使用现成的服务;
- 考虑SOA架构影响,减少服务间依赖
- 减少代码极其Jar包间的依赖。
如下图所示,利用流程配置中,“结束”节点Message Map调用更新流程实例状态的方法。(Cordys流程平台提供的功能)
输入参数为Java方法“updateStatus”:
com.unicom.bopm.workflow.BIZ_INFO_INSTANCE.updateStatus(string(instance:instanceProperties/instance:organization/text()),string(bpm:inputMsg/bpm:inputData/bpm:bizInstanceId/text()),'2')
为了兼容早期设计和流程部署成果,扩展使用源项目代码中方法:“com.unicom.bopm.workflow.BIZ_INFO_INSTANCE.updateStatus”。(此BIZ_INFO_INSTANCE类是关系型数据库的“表”实体对应)
public static boolean updateStatus(String orgDn, String bizInstanceId, String status) {
String[] paramNames = {"bizInstanceId", "status"};
Object[] paramValues = {bizInstanceId, status};
SOAPRequestObject sro = new SOAPRequestObject(orgDn, "http://unicom.com/workflow", "UpdateBizInstStatus", paramNames, paramValues);
sro.execute();
/* 在此处增加更新MongoDB文档状态代码 */
return true;
}
改造此updateStatus方法,引入对MongoDB的操作,设计UML如下:
Created with Raphaël 2.1.0
BIZ_INFO_INSTANCE
BIZ_INFO_INSTANCE
C_MONGODB
C_MONGODB
BIZ_INFO_INSTANCEBase
BIZ_INFO_INSTANCEBase
Oracle数据库
Oracle数据库
MongoDB数据库
MongoDB数据库
1.UpdateMongoByInstance
2.GetBizInfoInstanceObject
2.1.从Biz对象中获取文档ID
3.editMongoByJosn
4.修改文档数据
5.返回服务状态
通过测试“2.调用获取文档关键字服务”GetBizInfoInstanceObject,从返回值中,获取文档集合和_ID。其中,GetBizInfoInstanceObject是类BIZ_INFO_INSTANCEBase成员,在UpdateMongoByInstance服务中,需要通过SOAP服务可以调用使用。
如图所示,我们只需要:”MONGO_BO_ID”和”BIZ_RVSN_NUMBER”两个关键字就可以定位到文档。
这样,新增代码如下:
if (status.equals("2")){
Date newDate = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//设置文档完成时间
String jsonString = "{'completedtime':'"+dateFormat.format(newDate)+"','status':'2'}";
String[] pNames = {"collection", "instanceid", "jsonStr"};
Object[] pValues = {"ZFSP",bizInstanceId,jsonString};
//调用Webservice,通过业务实例修改文档——UpdateMongoByInstance
SOAPRequestObject sromongodb = new SOAPRequestObject(orgDn, "http://unicom.com/common/attachment", "UpdateMongoByInstance", pNames, pValues);
sromongodb.execute();
}
其中,在C_MONGODB类中,新建服务UpdateMongoByInstance,修改文档的服务代码如下:
// 修改MongoDB的内嵌文档
public static String updateMongoByInstance(String collection,String instanceid,String jsonStr,String oid){
//按文档id修改文档
if(oid != null && !"".equals(oid.trim())){
editMongoByJosn(oid, jsonStr, collection);
return "true";
}
else{
//按业务实例ID修改文档
if(instanceid != null && !"".equals(instanceid.trim())){
String namespace = "http://unicom.com/workflow";
//取流程实例Webservice
String methodName = "GetBizInfoInstanceObject";
String[] parasName = {"BIZ_INSTANCEID"};
Object[] parasValue = {instanceid};
SOAPRequestObject bizRequet = new SOAPRequestObject(namespace, methodName, parasName, parasValue);
BusObject bizBus = bizRequet.getObject();
String v_oid = bizBus.getStringProperty("MONGO_BO_ID");
String v_collection = bizBus.getStringProperty("BIZ_RVSN_NUMBER");
editMongoByJosn(v_oid, jsonStr, v_collection);
return "true";
}else{
return "false";
}
}
}
/**
* MongoDB修改的方法
*
* @param oid 主键ID
* @param json 要修改的JSON数据
* @param collection 集合名称
* @return 修改时返回主键ID
*/
public static String editMongoByJosn(String oid, String json, String collection) {
DBCollection coll = MongoDBUtil.getCollection(collection);
BasicDBObject a = new BasicDBObject();
DBObject dbo = (DBObject) JSON.parse(json);
BasicDBObject updateCondetion = new BasicDBObject();
updateCondetion.put("_id", new ObjectId(oid));
String iid = updateCondetion.get("_id").toString();
a.put("$set", dbo);
coll.update(updateCondetion, a);
return iid;
}
遇到的问题:
在实施中,还是出现了服务依赖Jar包的问题。在Cordys服务部署中,service group分配与所开发的服务对应关系不是很理想,例如:
- 涉及到MongoDB数据库基础服务,都应归集到一个Service Group中,并且不与关系型数据库业务操作服务纠缠;
- 关于事务也是很头痛的问题,这里Service Group分配不理想的原因,也是基于事务的要求,规避SOA在异步处理时不可控的问题。
参考:
《MongoDB 与关系型数据库(Oracle)关联统计实践方案》 肖永威 2016年3月