项目是数据处理项目,不需要集群处理,所以项目初期没考虑集群的问题,但是甲方的服务器是集群,所以,需要考虑集群中重复插入数据的问题。
解决思路:
1、在项目启动的时候,通过Spring的内置事件的listener,获取当前服务器的IP地址以及端口号,存入到数据库中,完成注册。
2、图中为存入到数据库中的服务器信息
param_code1: 服务器ip
param_code2: 服务器端口号
param_value1: 该服务器的排序编号(序列或自增数均可)
param_value3: 项目名称
通过上面的几个参数就可以完成指定服务器完成指定数据的插入功能,而且不用担心重复插入;
3、当对数据处理的时候,首先从数据库中获取所有注册的服务器信息,获取时 要用 order by param_value1 asc 或者 desc,保证获取出来的注册服务器信息顺序一致,然后就可以按照约定的规则让指定的服务器去处理指定的数据,互不干扰,从而解决集群中重复插入数据的问题。
下面附上大致代码:
//注册的代码
public class RegisterServerLisener implements
ApplicationListener<ContextRefreshedEvent> {
/* ContextRefreshedEvent为初始化完毕事件,spring还有很多事件可以利用 */
@Resource
private IDfSystemCommParamService iDfSystemCommParamService;
/* 静态实例 */
private static String host = "";
public static String getHost() {
return host;
}
public static void setHost(String host) {
RegisterServerLisener.host = host;
}
private static String port = "";
public static String getPort() {
return port;
}
public static void setPort(String port) {
RegisterServerLisener.port = port;
}
/**
* 当一个ApplicationContext被初始化或刷新触发
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
//这里是linux系统下获取weblogic服务器的端口号 的方法
Context ctx = new InitialContext();
MBeanServer tMBeanServer = (MBeanServer) ctx.lookup("java:comp/env/jmx/runtime");
ObjectName tObjectName = new ObjectName("com.bea:Name=RuntimeService,Type=weblogic.management.mbeanservers.runtime.RuntimeServiceMBean");
ObjectName serverrt = (ObjectName) tMBeanServer.getAttribute(tObjectName, "ServerRuntime");
port = String.valueOf(tMBeanServer.getAttribute(serverrt, "ListenPort"));
//System.out.println(port);
//获取IP
String ss = System.getProperty("weblogic.management.server");
if (!"".equals(ss)&&ss!=null) {
String[] split = ss.split("//");
String[] split2 = split[1].split(":");
host = split2[0];
}
//获取项目名称
ApplicationContext applicationContext = event.getApplicationContext();
WebApplicationContext webApplicationContext = (WebApplicationContext)applicationContext;
ServletContext servletContext = webApplicationContext.getServletContext();
String path0 = servletContext.getContextPath();
DfSystemCommParam param = new DfSystemCommParam();
param.setParamCode(TradeMapping.SERVER_IP_PORT);
param.setParamCode1(host);
param.setParamCode2(port);
//存入数据库中,完成注册
List<DfSystemCommParam> sysParam = iDfSystemCommParamService.getSystemCommParamByParam(param);
if (sysParam.size() == 0) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String string = sdf.format(new Date().getTime());
param.setParamInfo(string);
param.setUseFlag(0);
param.setParamValue3(path0);
iDfSystemCommParamService.createParamByParam(param);
}else{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String string = sdf.format(new Date().getTime());
param.setParamInfo(string);
iDfSystemCommParamService.updateParamAttrByParam(param);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//数据处理的代码
public void run() throws Exception {
//这个是个hashmap容器,根据自己项目情况而定,可有可无
ParamInfoMap paramInfoMap = new ParamInfoMap();
//获取IP地址
String host = RegisterServerLisener.getHost();
//获取端口号
String port = RegisterServerLisener.getPort();
paramInfoMap.put(TradeMapping.SERVER_IPADDRESS, host);
paramInfoMap.put(TradeMapping.SERVER_PORT, port);
DfSystemCommParam param = new DfSystemCommParam();
param.setParamCode(TradeMapping.SERVER_IP_PORT);
//获取所有注册服务器,(这里的sql是根据param_value1排序的,确保取出服务器的顺序一致)
List<DfSystemCommParam> paramList = dfSystemCommParamMapper.getServerIpPort(TradeMapping.SERVER_IP_PORT);
//余数(指定服务器的参数)
Integer modNumber = 0;
//注册服务器总数
Integer paramListSize = paramList.size();
if (paramList != null && paramListSize>0) {
for (DfSystemCommParam dfSystemCommParam : paramList) {
//这里可以确定这台服务器处理哪些城市的数据
if (host.equals(dfSystemCommParam.getParamCode1()) && port.equals(dfSystemCommParam.getParamCode2())) {
paramInfoMap.put(TradeMapping.PROJECT_NAME, dfSystemCommParam.getParamValue3());
//获取相应余数的城市
//mod(t.dict_detail_id,#{paramListSize}) = #{modNumber}数据库中城市的ID对服务器总数取余,执行对应于数的城市数据;如果想要用数据分,可以用数据的ID对服务器的总数取余,效果是一样的
List<SysDictDetail> dictDetailByType=systemDictionaryMapper.getServerCity(paramListSize,modNumber);
for (SysDictDetail sysDictDetail : dictDetailByType) {
reloadApi.fresh(paramInfoMap);
paramInfoMap.put(TradeMapping.CITY_CODE_LIST, sysDictDetail.getDictDetailValue());
this.doExecute(this, paramInfoMap);
}
}
modNumber++;
}
}
//List<SysDictDetail> dictDetailByType = dictParam.getDictDetailByType("CITY_DATA");
}