java如何使用预分配法生成唯一ID

小编给大家分享一下java如何使用预分配法生成唯一ID,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

创新互联建站致力于互联网品牌建设与网络营销,包括做网站、成都做网站、SEO优化、网络推广、整站优化营销策划推广、电子商务、移动互联网营销等。创新互联建站为不同类型的客户提供良好的互联网应用定制及解决方案,创新互联建站核心团队十多年专注互联网开发,积累了丰富的网站经验,为广大企业客户提供一站式企业网站建设服务,在网站建设行业内树立了良好口碑。

在项目中经常有生成唯一ID的业务需求。作为唯一标识方便后续查找和追踪。网上也有很多实现方案。比如:数据库自增主键,数据库批量生成ID,UUID,时间戳方法,zookeeper生成ID,redis生成唯一ID,snowflake算法等等。这些解决方案各有优缺点。我在游戏项目常用的解决方案是:预分配法生成唯一ID。其原理简单,利于扩展,具有较强的适用性。

预分配法生成唯一ID原理:数据库中存储每种类型最后的预分配dbUniqueId值。数据库实体对象上增加当前分配的
useDbUniqueId。预分配步长DBUNIQUEID_M可根据类型和业务量自定义。当useDbUniqueId大于等于dbUniqueId时就预分配出DBUNIQUEID_M个唯一ID。

角色ID生成:要求7位连续的唯一ID。则DBUNIQUEID_M=1。1000000+dbUniqueId格式化成7位数字。

本服唯一ID:则DBUNIQUEID_M=10000。(1000000+dbUniqueId)*10000+serverId格式化而成。其中serverId游戏服ID定义为4位

全局唯一ID:则DBUNIQUEID_M=10000。((100000000000L+dbUniqueId)100+gameCode10000+workerId;格式化而成。其中gameCode游戏编码定义为2位。

具体实现请参阅代码。非常方便的移植到项目工程中。

IdWorkerEnum.java

package com.game.common.db;
import java.util.List;
import com.core.enums.LLIndexedEnum;
/**
 * ID枚举类型
 * @author Thinker
 */
public enum IdWorkerEnum implements LLIndexedEnum
{
    /** 角色ID */
    IDWORKER_HUMANID(1,"角色ID"),
    /** 数据库ID */
    IDWORKER_DBID(2,"数据库ID"),
    /** 工会ID */
    IDWORKER_CLUBID(3,"工会ID"),
    /** 收集ID */
    IDWORKER_COLLECTID(4,"收集ID"),;
    /** 枚举的索引 */
    public final int index;
    /** 名称的key */
    private final String nameKey;
    /** 按索引顺序存放的枚举数组 */
    private static final List indexes=LLIndexedEnum.IndexedEnumUtil.toIndexes(IdWorkerEnum.values());
    private IdWorkerEnum(int index,String nameKey)
    {
        this.index=index;
        this.nameKey=nameKey;
    }
    /**
     * 获取索引
     */
    @Override
    public int getIndex()
    {
        return index;
    }
    /**
     * 取得名称key
     */
    public String getNameKey()
    {
        return this.nameKey;
    }
    /**
     * 根据指定的索引获取枚举的定义
     */
    public static IdWorkerEnum valueOf(final int index)
    {
        return LLIndexedEnum.IndexedEnumUtil.valueOf(indexes,index);
    }
}

DbUniqueIdEntity.java

package com.game.common.db;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.eclipse.persistence.annotations.HashPartitioning;
import org.eclipse.persistence.annotations.Partitioned;
import com.game.common.db.dao.BaseDbBean;
/**
 * 数据库唯一KEY实体类
 * @author Thinker
 */
@Entity(name="t_dbUniqueId")
@HashPartitioning(name="HashPartitionByDbUniqueCacheId",partitionColumn=@Column(name="dbUniqueCacheId"))
@Partitioned("HashPartitionByDbUniqueCacheId")
public class DbUniqueIdEntity extends BaseDbBean
{
    /** 数据库唯一缓存ID **/
    @Id
    @Column(length=20)
    private long dbUniqueCacheId;
    /** 数据库唯一ID **/
    @Column(length=20)
    private long dbUniqueId;
    /** 最后更新的时间 **/
    @Column(length=20)
    private long createTime;
    // ////////////////内部数据//////////////////
    /** 已经使用过的数据库唯一ID(唯一ID) */
    @Column(length=20)
    private long useDbUniqueId;
    @Override
    public long getId()
    {
        return dbUniqueCacheId;
    }
    @Override
    public void setId(long id)
    {
    }
    public long getDbUniqueCacheId()
    {
        return dbUniqueCacheId;
    }
    public void setDbUniqueCacheId(long dbUniqueCacheId)
    {
        this.dbUniqueCacheId=dbUniqueCacheId;
    }
    public long getDbUniqueId()
    {
        return dbUniqueId;
    }
    public void setDbUniqueId(long dbUniqueId)
    {
        this.dbUniqueId=dbUniqueId;
    }
    public long getCreateTime()
    {
        return createTime;
    }
    public void setCreateTime(long createTime)
    {
        this.createTime=createTime;
    }
    public long getUseDbUniqueId()
    {
        return useDbUniqueId;
    }
    public void setUseDbUniqueId(long useDbUniqueId)
    {
        this.useDbUniqueId=useDbUniqueId;
    }
}

IdWorker.java

package com.game.common.db;
import com.game.common.Globals;
import com.game.common.entityProxy.EntityProxy;
import com.game.core.appConfig.AppConfigServ;
import com.game.core.utils.LoggerUtils;
/**
 * 唯一ID生成器
 * 
 * @author Thinker
 */
public class IdWorker
{
    public final static IdWorker OBJ=new IdWorker(AppConfigServ.OBJ.getAppConfigBean().getServerNo());
    private int DBUNIQUEID_M=2000;
    private final long workerId;
    /** 数据库连接池 */
    private DbUniqueIdEntity[] szDbUniqueIdEntity=new DbUniqueIdEntity[5];
    public IdWorker(long workerId)
    {
        this.workerId=workerId;
    }
    /**
     * 生成系统唯一ID:采用隐性锁方式
     */
    public synchronized long nextId()
    {
        IdWorkerEnum idWorkerEnum=IdWorkerEnum.IDWORKER_DBID;
        int dbUniqueCacheId=idWorkerEnum.getIndex();
        loadDbUniqueId(idWorkerEnum);
        DbUniqueIdEntity dbUniqueIdEntity=szDbUniqueIdEntity[dbUniqueCacheId];
        long dbUniqueId=0;
        // 需要重新分配Id:每次分配 M个
        if(dbUniqueIdEntity.getUseDbUniqueId()>=dbUniqueIdEntity.getDbUniqueId())
        {
            dbUniqueIdEntity.setDbUniqueId(dbUniqueIdEntity.getDbUniqueId()+DBUNIQUEID_M);
            EntityProxy.OBJ.update((long) dbUniqueCacheId,dbUniqueIdEntity);
            LoggerUtils.serverLogger.info("IdWorker DbId:update dbUniqueId="+dbUniqueIdEntity.getDbUniqueId());
        }
        dbUniqueId=dbUniqueIdEntity.getUseDbUniqueId()+1;
        dbUniqueIdEntity.setUseDbUniqueId(dbUniqueId);
        // 11位UUID
        return (1000000+dbUniqueId)*10000+workerId;
    }
    /**
     * 生成系统唯一HumanID:采用隐性锁方式
     */
    public synchronized long nextHumanId()
    {
        IdWorkerEnum idWorkerEnum=IdWorkerEnum.IDWORKER_HUMANID;
        int dbUniqueCacheId=idWorkerEnum.getIndex();
        loadDbUniqueId(idWorkerEnum);
        DbUniqueIdEntity dbUniqueIdEntity=szDbUniqueIdEntity[dbUniqueCacheId];
        long dbUniqueId=0;
        // 需要重新分配Id:每次分配 M个
        if(dbUniqueIdEntity.getUseDbUniqueId()>=dbUniqueIdEntity.getDbUniqueId())
        {
            dbUniqueIdEntity.setDbUniqueId(dbUniqueIdEntity.getDbUniqueId()+1);
            EntityProxy.OBJ.update((long) dbUniqueCacheId,dbUniqueIdEntity);
            LoggerUtils.serverLogger.info("IdWorker HumanId:update dbUniqueId="+dbUniqueIdEntity.getDbUniqueId());
        }
        dbUniqueId=dbUniqueIdEntity.getUseDbUniqueId()+1;
        dbUniqueIdEntity.setUseDbUniqueId(dbUniqueId);
        // 7位UUID
        return (1000000+dbUniqueId);
    }
    /**
     * 生成系统唯一ClubID:采用隐性锁方式
     */
    public synchronized long nextClubId()
    {
        IdWorkerEnum idWorkerEnum=IdWorkerEnum.IDWORKER_CLUBID;
        int dbUniqueCacheId=idWorkerEnum.getIndex();
        loadDbUniqueId(idWorkerEnum);
        DbUniqueIdEntity dbUniqueIdEntity=szDbUniqueIdEntity[dbUniqueCacheId];
        long dbUniqueId=0;
        // 需要重新分配Id:每次分配 M个
        if(dbUniqueIdEntity.getUseDbUniqueId()>=dbUniqueIdEntity.getDbUniqueId())
        {
            dbUniqueIdEntity.setDbUniqueId(dbUniqueIdEntity.getDbUniqueId()+1);
            EntityProxy.OBJ.update((long) dbUniqueCacheId,dbUniqueIdEntity);
            LoggerUtils.serverLogger.info("IdWorker clubId:update dbUniqueId="+dbUniqueIdEntity.getDbUniqueId());
        }
        dbUniqueId=dbUniqueIdEntity.getUseDbUniqueId()+1;
        dbUniqueIdEntity.setUseDbUniqueId(dbUniqueId);
        // 5位UUID
        return (10000+dbUniqueId);
    }
    /**
     * 生成系统唯一ID:采用隐性锁方式
     */
    public synchronized long nextCollectId()
    {
        IdWorkerEnum idWorkerEnum=IdWorkerEnum.IDWORKER_COLLECTID;
        int dbUniqueCacheId=idWorkerEnum.getIndex();
        loadDbUniqueId(idWorkerEnum);
        DbUniqueIdEntity dbUniqueIdEntity=szDbUniqueIdEntity[dbUniqueCacheId];
        long dbUniqueId=0;
        // 需要重新分配Id:每次分配 M个
        if(dbUniqueIdEntity.getUseDbUniqueId()>=dbUniqueIdEntity.getDbUniqueId())
        {
            dbUniqueIdEntity.setDbUniqueId(dbUniqueIdEntity.getDbUniqueId()+DBUNIQUEID_M);
            EntityProxy.OBJ.update((long) dbUniqueCacheId,dbUniqueIdEntity);
            LoggerUtils.serverLogger.info("IdWorker DbId:update dbUniqueId="+dbUniqueIdEntity.getDbUniqueId());
        }
        dbUniqueId=dbUniqueIdEntity.getUseDbUniqueId()+1;
        dbUniqueIdEntity.setUseDbUniqueId(dbUniqueId);
        // 18位UUID:游戏ID+服务器ID。确保支持多游戏不重复的ID。便于兼容统计
        return ((100000000000L+dbUniqueId)*100+AppConfigServ.OBJ.getAppConfigBean().getGameCode())*10000+workerId;
    }
    /**
     * 加载唯一ID
     */
    public void loadDbUniqueId(IdWorkerEnum idWorkerEnum)
    {
        int dbUniqueCacheId=idWorkerEnum.getIndex();
        if(szDbUniqueIdEntity[dbUniqueCacheId]!=null) return;
        DbUniqueIdEntity dbUniqueIdEntity=EntityProxy.OBJ.get((long) dbUniqueCacheId,(long) dbUniqueCacheId,DbUniqueIdEntity.class);
        if(dbUniqueIdEntity==null)
        {
            dbUniqueIdEntity=new DbUniqueIdEntity();
            dbUniqueIdEntity.setDbUniqueCacheId(dbUniqueCacheId);
            dbUniqueIdEntity.setDbUniqueId(0);
            dbUniqueIdEntity.setCreateTime(Globals.getTimeService().now());
            dbUniqueIdEntity.setUseDbUniqueId(0);
            EntityProxy.OBJ.insert((long) dbUniqueCacheId,dbUniqueIdEntity);
        }
        dbUniqueIdEntity.setUseDbUniqueId(dbUniqueIdEntity.getDbUniqueId());
        szDbUniqueIdEntity[dbUniqueCacheId]=dbUniqueIdEntity;
        LoggerUtils.serverLogger.info("IdWorker:load dbUniqueId="+dbUniqueIdEntity.getDbUniqueId());
    }
}

以上是“java如何使用预分配法生成唯一ID”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!


标题名称:java如何使用预分配法生成唯一ID
网站地址:http://pwwzsj.com/article/ipshgg.html