分布式部署应用时主从同步时候主键重复

原因:

解决方法: 用redis生成主键

/**
     *
     * @Title: getContractId
     * @user: zzx
     * @time: 2016年11月15日下午5:36:15
     * //DESC 获取订单ID
     * @param param step:步长
     * @return 当前分布式环境下最新ID
     * @return String  返回类型
     * @throws
     */
    public String getContractId(JSONObject param){
    	int step = param.getIntValue("step");
    	Long current = productContractIdAutomic.longValue();
    	Long newValue = current + step;
    	productContractIdAutomic.compareAndSet(current, newValue);
    	ResultInfo rs = new ResultInfo();
    	rs.setResult_code(0);
        rs.setResult_detail("success");
        rs.setResult_data(String.valueOf(current));
        return JSON.toJSONString(rs);
    }

全部代码:

package com.eshore.ismp.cache.processor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.eshore.ismp.cache.redis.RedisService;
import com.eshore.ismp.common.entity.ResultInfo;

/**
 * 订单模块缓存接口.
 * @author zhangjunyong
 * @version V1.0  2016/9/2 12:04
 */
@Service
public class ContractProcessor {
    private static final Logger logger = Logger.getLogger(ContractProcessor.class);

    private static final String KEY = "key";

    private static final String VALUE = "value";

    private static final String SIZE = "size";

    @Autowired
    RedisService redisService;

    @Resource(name="productContractIdAutomic")
	private RedisAtomicLong productContractIdAutomic;

    /**
     * 订单模块,用于存放数据进list.
     * @param param
     * @return String
     * @author zhangjunyong
     * @date 2016/9/2 12:05
     */
    public String putToList(JSONObject param) {
        ResultInfo rs = new ResultInfo();
        try {
            String key = param.getString(KEY);
            JSONArray array = param.getJSONArray(VALUE);
            if (array == null || array.isEmpty() || StringUtils.isEmpty(key)) {
                logger.error("参数错误");
                rs.setResult_code(4501);
                rs.setResult_detail("参数错误");
                return JSON.toJSONString(rs);
            }
            List<String> valueList = new ArrayList<String>();
            for (Object value : array) {
                valueList.add(String.valueOf(value));
            }
            long result = redisService.rpush(key, valueList);

            rs.setResult_code(0);
            rs.setResult_detail("success");
            rs.setResult_data(String.valueOf(result));
            return JSON.toJSONString(rs);
        } catch (Exception e) {
            rs.setResult_code(4502);
            rs.setResult_detail("系统错误!");
            logger.info("An error occur when invoke method putToList", e);
            return JSON.toJSONString(rs);
        }
    }

    /**
     * 批量弹出列表中数据.
     * @param param
     * @return String
     * @author zhangjunyong
     * @date 2016/9/2 12:06
     */
    @SuppressWarnings("rawtypes")
    public String getFromList(JSONObject param) {
        ResultInfo rs = new ResultInfo();
        try {
            String key = param.getString(KEY);
            int size = param.getInteger(SIZE);
            if (StringUtils.isEmpty(key) || size == 0) {
                logger.error("参数错误");
                rs.setResult_code(4501);
                rs.setResult_detail("参数错误");
                return JSON.toJSONString(rs);
            }

            List data = redisService.lpop(key, size);
            rs.setResult_code(0);
            rs.setResult_detail("success");
            rs.setResult_data(JSON.toJSONString(data));
            return JSON.toJSONString(rs);
        } catch (Exception e) {
            rs.setResult_code(4502);
            rs.setResult_detail("系统错误!");
            logger.info("An error occur when invoke method getFromList", e);
            return JSON.toJSONString(rs);
        }
    }

    /**
     * 批量存放hash对象到key中.
     * @param param
     * @return String
     * @author zhangjunyong
     * @date 2016/9/2 12:06
     */
    public String putToHash(JSONObject param) {
        String key = param.getString(KEY);
        JSONArray array = param.getJSONArray(VALUE);
        ResultInfo rs = new ResultInfo();
        if (array == null || array.isEmpty() || StringUtils.isEmpty(key)) {
            logger.error("参数错误");
            rs.setResult_code(4501);
            rs.setResult_detail("参数错误");
            return JSON.toJSONString(rs);
        }
        Map<String, String> valueMap = new HashMap<String, String>();
        for (Object value : array) {
            JSONObject jsObj = JSON.parseObject(String.valueOf(value));
            logger.info("jsonObj : = " + jsObj.toJSONString());
            logger.info("key=" + jsObj.getString("key") + " value=" + jsObj.getString("value"));
            valueMap.put(jsObj.getString("key"), jsObj.getString("value"));
        }
        int result = redisService.hmset(key, valueMap);

        rs.setResult_code(0);
        rs.setResult_detail("success");
        rs.setResult_data(String.valueOf(result));
        return JSON.toJSONString(rs);
    }

    /**
     *
     * @Title: getContractId
     * @user: zzx
     * @time: 2016年11月15日下午5:36:15
     * //DESC 获取订单ID
     * @param param step:步长
     * @return 当前分布式环境下最新ID
     * @return String  返回类型
     * @throws
     */
    public String getContractId(JSONObject param){
    	int step = param.getIntValue("step");
    	Long current = productContractIdAutomic.longValue();
    	Long newValue = current + step;
    	productContractIdAutomic.compareAndSet(current, newValue);
    	ResultInfo rs = new ResultInfo();
    	rs.setResult_code(0);
        rs.setResult_detail("success");
        rs.setResult_data(String.valueOf(current));
        return JSON.toJSONString(rs);
    }
}

调用方法

package com.eshore.ismp.contract.sql;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.eshore.ismp.common.entity.ResultInfo;
import com.eshore.ismp.common.thrift.CacheService.Iface;

@Component
@Scope("prototype")
public class IDManager {
	private static final Logger logger = Logger.getLogger(IDManager.class);

	@Autowired
	private Iface cacheServer;
	private static final int STEP = 200;
	private static String GET_ID_METHOD = "contract.getContractId";
	private Long current = 0L;
	private Long end = 0L;

	/**
	 *
	 * @Title: getId
	 * @user: zzx
	 * @time: 2016年11月15日下午7:45:52
	 * //DESC 通过缓存获取ID
	 * @param type
	 * @return
	 * @return Long  返回类型
	 * @throws
	 */
	public synchronized Long getId(final int type) {
		if (this.end <= this.current) {
			JSONObject param = new JSONObject();
			param.put("step", STEP);
			try {
				String resultInfo =cacheServer.process(GET_ID_METHOD, param.toJSONString());
				ResultInfo ri = JSON.parseObject(resultInfo, ResultInfo.class);
				if(ri.getResult_code() ==0){
					current =Long.parseLong(ri.getResult_data())+1;
					end = current + STEP;
				}

			} catch (Exception e) {
				logger.error("get id error:",e);
				return null;
			}
		}

		return this.current++;
	}
}

如果表中存在历史数据,则需要开个定时器将id初始值设置大一点或者直接在数据库改掉redis的初始值然后重启服务

时间: 2024-08-01 02:01:59

分布式部署应用时主从同步时候主键重复的相关文章

mysql主键设置成auto_increment时,进行并发性能测试出现主键重复Duplicate entry &#39;xxx&#39; for key &#39;PRIMARY&#39;

mysql主键设置成auto_increment时,进行并发性能测试出现主键重复Duplicate entry 'xxx' for key 'PRIMARY' 解决方法: 在my.cnf的[mysqld]片段中添加设置innodb_autoinc_lock_mode=0 同时注意调大jdbc的活跃链接数,如设置 jdbc.maxActive=300,因为设置innodb_autoinc_lock_mode=0可能导致链接过多. 注意,这种方式只需要在并发性能测试时设置,因为这种方式在插入记录时需

mysql insert插入时实现如果数据表中主键重复则更新,没有重复则插入的四种方法

[CSDN下载] Powerdesigner 设计主键code不能重复等问题 [CSDN博客] Oracle中用一个序列给两个表创建主键自增功能的后果 [CSDN博客] MySQL自增主键删除后重复问题 [CSDN博客] mysql 主从复制 双主从复制原理 防止主键重复问题(必看) [CSDN博客] replace into导致mysql自增列导致主键重复问题分析 [CSDN博客] 一个循环更新某库所有表所有非主键列的值方法(sql 2005 & mysql) [CSDN博客] mysql i

mysql insert 主键 重复问题

转自:http://blog.163.com/[email protected]/blog/static/173131045201222122732435/ mysql中insert into和replace into以及insert ignore用法区别: mysql中常用的三种插入数据的语句: insert into表示插入数据,数据库会检查主键,如果出现重复会报错: replace into表示插入替换数据,需求表中有PrimaryKey,或者unique索引,如果数据库已经存在数据,则用

jfinal基本应用 --报主键重复

在使用jfinal 的Model过程中有一个很怪异的问题,发布到服务器上,只要是往表中添加字段,就报主键重复. 1.我添加表的时候调用了 public void create(Map map){ String assocName = (String) map.get("assocName"); String telephone = (String) map.get("telephone"); set(COLLUMNS.ASSOC_NAME, assocName);

mysql5.7.25主从同步图解(主:CentOS7.5,从win10)

环境说明: 主服务器:CentOS7.5 从服务器:Windows10(本地测试机) 1. 配置master(主服务器,CentOS7.5) 1.1 首先查看CentOS上面的MySQL是否启动 systemctl status mysqld 1.2 修改MySQL配置文件 vi /etc/my.cnf 添加以下内容: #服务器唯一id,默认是1(主从都必须不一样) server-id=1000 #启动二进制日志名称为mysql-bin log-bin=mysql-bin #binlog-do-

MySQL主从同步与主主同步

MySQL复制: MySQL内建的复制功能是构建大型,高性能应用程序的基础.将MySQL的数据分布到多个系统上去,这种分布的机制,是通过将mysql的某一台主机的数据复制到其它主机(slave)上,并重新执行一遍来实现. 复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器.主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循坏,这些日志可以记录发送到从服务器的更新.当一个从服务器 连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置.从服务器

DNS服务器主从同步Windows主+Linux从(三)

(一)简介由于公司DNS服务器是以windows为主,由于经常打补丁,造成几次故障,故需要迁移到Linux,由于添加的记录过多,故采用以windows为主负责添加,修改解析记录,而Linux同步后进行接受业务请求的访问. 序号 IP 功能 系统 1 10.128.105.171 Master Windows 2 172.20.66.132 Slave- Linux (二)具体的步骤(1),windows安装配置省略 (2)Linux的具体步骤如下: 2.1安装bind[[email protec

MyBatis 插入时返回自增主键

XML <insert id="insert" parameterType="com.stone.model.Person"> <!-- selectKey 是做主键返回的 keyProperty 接受返回主键的属性 order: insert语句和生成主键的sql执行顺序:mysql是AFTER,在oracle中是BEFORE resultType:返回主键的数据类型 生成主键的sql: select LAST_INSERT_ID() -->

通过mybatis添加数据记录时,如何返回主键

java private SqlSession session = null; @BeforeClass public void init() throws IOException { // SqlSession--->SqlSessionFatory----->SqlSessionFatoryBuilder SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder(); InputStream ins = Resources.ge