温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-12-29 09:25:02 来源:亿速云 阅读:176 作者:小新 栏目:软件技术

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

在项目中经常有生成唯一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<IdWorkerEnum> 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”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI