2023年7月13日发(作者:)
javaID⽣成策略个⼈总结先研究⼀下hibernate的⼏个主键⽣成策略1、uuid⽣成策略uuid⽣成策略采⽤128位的UUID算法来⽣成⼀个字符串类型的主键值,这个算法使⽤IP地址、JVM的启动时间(精确到1/4秒)、系统时间 和⼀个计数器值(在当前的JVM中唯⼀)经过计算来产⽣标识符属性值,可以⽤于分布式的Hibernate应⽤中。产⽣的标识符属性是⼀个32位长度的字 符串。使⽤这种⽣成策略,对应持久化类中标识符属性的类型应该设置为String类型,其⽰例配置信息如下所⽰。
或者需要利⽤索引来满⾜⾼并发下的性能的话,GUID会是⼀个性能瓶颈。
⼀致性哈希能够来解决GUID和分⽚问题,在多写少读下⽐较好,但是mysql确实⽤来优化为快速的随机读。
怎么避免单点故障问题还没有有效的⽅案,只是通过这两台机器做主备和负载均衡。
3、native⽣成策略由Hibernate根据所使⽤的数据库⽀持能⼒从identity、sequence或者hilo⽣成策略中选择⼀种,其⽰例配置信息如下:
使⽤这种标识符属性⽣成策略可以根据不同的数据库采⽤不同的⽣成策略,如Oracle中使⽤sequence,在MySQL中使⽤identity便于Hibernate应⽤在不同的数据库之间移植。这个做的挺好,可以根据数据库的不同,选择不同的⽣成策略,但是核⼼的⽣成不在这⾥,在数据库的⽣成策略,到分布式的时候依旧会出现问题。4、assigned⽣成策略assigned⽣成策略由Hibernate应⽤⾃定义标识符属性的数值,即在调⽤Session对象的save()⽅法持久化对象时,需要⾸先为持久化对象的标识符属性赋值。如果
2. 每个⽣成ID的程序的唯⼀编号(确保同⼀服务器上的不同服务之间不冲突)
3. 程序每次启动的唯⼀编号(确保程序的每次启停之间不冲突)
4. 启动后内存⾥的序列号/系统当前时间(确保程序的⼀次运⾏期内不冲突)以及其他的参数,混合⽣成id,保证多台服务器、多个线程⽣成的id不冲突。例如:UUID().toString() ⽣成的是length=32的16进制格式的字符串,如果回退为byte数组共16个byte元素,即UUID是⼀个128bit长的数字,⼀般⽤16进制表⽰。算法的核⼼思想是结合机器的⽹卡、当地时间、⼀个随即数来⽣成UUID。从理论上讲,如果⼀台机器每秒产⽣10000000个GUID,则可以保证(概率意义上)3240年不重复市⾯上流⾏的⽅式个⼈觉得⽐较好的就是利⽤zookeeper了,⽐如Twitter的Snowflake,是由(时间+应⽤的workId+应⽤的内存的sequence)⽣成来段代码看看吧,废话不说:package er;public class IdWorker { private final long workerId; private final static long twepoch = 57L; private long sequence = 0L; private final static long workerIdBits = 4L; public final static long maxWorkerId = -1L ^ -1L << workerIdBits; private final static long sequenceBits = 10L; private final static long workerIdShift = sequenceBits; private final static long timestampLeftShift = sequenceBits + workerIdBits; public final static long sequenceMask = -1L ^ -1L << sequenceBits; private long lastTimestamp = -1L; public IdWorker(final long workerId) { super(); if (workerId > kerId || workerId < 0) { throw new IllegalArgumentException(( "worker Id can't be greater than %d or less than 0", kerId)); kerId)); } Id = workerId; } public synchronized long nextId() { long timestamp = n(); if (mestamp == timestamp) { ce = (ce + 1) & ceMask; if (ce == 0) { n("###########" + sequenceMask); timestamp = tMillis(mestamp); } } else { ce = 0; } if (timestamp < mestamp) { try { throw new Exception( ( "Clock moved backwards. Refusing to generate id for %d milliseconds", mestamp - timestamp)); } catch (Exception e) { tackTrace(); } } mestamp = timestamp; long nextId = ((timestamp - twepoch << timestampLeftShift)) | (Id << IdShift) | (ce); n("timestamp:" + timestamp + ",timestampLeftShift:" + timestampLeftShift + ",nextId:" + nextId + ",workerId:" + workerId + ",sequence:" + sequence); return nextId; } private long tilNextMillis(final long lastTimestamp) { long timestamp = n(); while (timestamp <= lastTimestamp) { timestamp = n(); } return timestamp; } private long timeGen() { return tTimeMillis(); }
public static void main(String[] args){ IdWorker worker2 = new IdWorker(2); n(()); }}这样是不是就能唯⼀的确定⼀个值了,? 我们项⽬中正好是⽤的是springboot,⾥⾯有workid,也有⾃⼰的zookeeper,是⽤起来应该还可以,模仿⼀个:构成为1. 进程起始时间戳,或者进程启动ID(由指定⽂件加载并写⼊)2. ⾃增序列3. 节点ID
package ;import me;import .$;import .E;import ;import .S;import ;import s;import Long;/** * Generate unique ID in a cluster */public class IdGenerator { /** * Implementation of { StartIdProvider} shall return a * unique id per each system start */ public static interface StartIdProvider { /** * Returns the system start ID. The start ID shall be different * between System starts, but it shall remaining the same value * within one system life time */ long startId(); /** * Generate system start ID based on timestamp */ public static class Timestamp implements StartIdProvider { private final long id; public Timestamp() { long origin = ("2016-05-10").getMillis(); // let's assume the system cannot be restart within 10 seconds long l = ($.ms() - origin) / 1000 / 10; id = l; } @Override public long startId() { return id; } } /** * Generate system start ID based on incremental sequence. The newly generated ID * will be write to a File */ public static class FileBasedStartCounter implements StartIdProvider { private final long id; public FileBasedStartCounter() { this(".-not-delete"); } public FileBasedStartCounter(String path) { File file = new File(path); if (()) { String s = ntentAsString(file); long seq = ong(s); seq = seq + 1; ontent((seq), file); id = (seq); } else { id = 0; ontent(ng(id), file); } } @Override public long startId() { return id; } } /** * Default start ID provider will try to use the { sedStartCounter}. In case * File IO is not allowed (e.g. in GAE), then it will use { amp} */ public static class DefaultStartIdProvider implements StartIdProvider { private StartIdProvider delegate; public DefaultStartIdProvider() { this(".-not-delete"); } public DefaultStartIdProvider(String path) { try { delegate = new FileBasedStartCounter(path); d(); } catch (Exception e) { delegate = new Timestamp(); } } @Override public long startId() { return d(); } } } /** * {@code SequenceProvider} shall generate unique ID within * one JVM per each call */ public static interface SequenceProvider { long seqId(); public static class AtomicLongSeq implements SequenceProvider { private final AtomicLong seq = new AtomicLong(0); @Override public long seqId() { return (entAndGet()); } } } public static interface NodeIdProvider { long nodeId(); public static class IpProvider implements NodeIdProvider { private static enum EffectiveBytes { ONE(1), TWO(2), THREE(3), FOUR(4); private int value; private EffectiveBytes(int value) { = value; } public static EffectiveBytes valueOf(int n) { switch (n) { case 1: return ONE; case 2: return TWO; case 3: return THREE; case 4: return FOUR; default : throw cted("Invalid EffectiveByte value: %s", n); } } } private final EffectiveBytes effectiveBytes; private final long id; public IpProvider() { this(4); } public IpProvider(int effectBytes) { iveBytes = f(effectBytes); String ip = (); String[] sa = ("."); int n = ; long l = 0; for (int i = 0; i < n; ++i) { String b = sa[3 - i]; long factor = 1; for (int j = 0; j < i; ++j) { factor = factor * 256; } l += f(b) * factor; } id = (l); } public long nodeId() { return id; } } } public static interface LongEncoder { String longToStr(long l); public abstract static class LongEncoderBase implements LongEncoder { private final char[] digits; private final int MAX_RADIX; public LongEncoderBase(char[] digits) { = digits; _RADIX = ; } /** * Code copied from JDK ng(long, String) */ public String longToStr(long l) { int radix = MAX_RADIX; char[] buf = new char[65]; int charPos = 64; boolean negative = (l < 0); if (!negative) { l = -l; } while (l <= -radix) { buf[charPos--] = digits[(int)(-(l % radix))]; l = l / radix; } buf[charPos] = digits[(int)(-l)]; if (negative) { buf[--charPos] = '-'; } return new String(buf, charPos, (65 - charPos)); } } } public static class UnsafeLongEncoder extends coderBase { /** * Extended char table for representing a number as a String */ private final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '$', '%', '&', '.', ',', ';', ':', '=', '?', '+', '-', '*', '/', '<', '>', '_', '~', '#', '^', '@', '|', '(', ')', '[', ']', '{', '}' }; public UnsafeLongEncoder() { super(digits); } } public static class SafeLongEncoder extends coderBase { /** * Extended char table for representing a number as a String */ private final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '.', '-', '_', '~', }; public SafeLongEncoder() { super(digits); } public static void main(String[] args) { n(new SafeLongEncoder().longToStr(_VALUE)); n(new UnsafeLongEncoder().longToStr(_VALUE)); n(_VALUE); } } public static final LongEncoder SAFE_ENCODER = new SafeLongEncoder(); public static final LongEncoder UNSAFE_ENCODER = new UnsafeLongEncoder(); private final NodeIdProvider nodeIdProvider; private final StartIdProvider startIdProvider; private final SequenceProvider sequenceProvider; private LongEncoder longEncoder; /** * Create a default IdGenerator with following configuration: *
- *
- Node ID provider: four byte IP address *
- Start ID provider: stored in
.-not-delete
file * - Sequence ID provider: Atomic Long sequence *
- Long Encoder: {@link SafeLongEncoder} *
- *
- Node ID provider: four byte IP address *
- Start ID provider: stored in
.-not-delete
file * - Sequence ID provider: Atomic Long sequence *
- * Long Encoder: {@link UnsafeLongEncoder} when `useUnsafeLongEncoder` is set to * `true` or {@link SafeLongEncoder} otherwise * *
- *
- Node ID provider: N byte IP address, where N is specified by effectiveIpBytes argument *
- Start ID provider: stored in
.-not-delete
file * - Sequnce ID provider: Atomic Long sequence *
- *
- Node ID provider: N byte IP address, where N is specified by effectiveIpBytes argument *
- Start ID provider: use start ID file specified by startIdFile argument *
- Sequnce ID provider: Atomic Long sequence *
- *
- Node ID provider: 4 byte IP address *
- Start ID provider: use start ID file specified by startIdFile argument *
- Sequnce ID provider: Atomic Long sequence *
再说⼀下集中存放(分布式环境), 集中存放不⼀定影响性能,最重要的是看你的需求和设计了,如果说你的项⽬并发量不是很⾼的时候,单独启动⼀个服务不同步读取即可,你可以当这些信息存⼊数据库中,或者直接初始化⼀个序列也⾏。如果说你的量级⾼了,你也只需要稍加修改i即可,使⽤批量分配的机制,每次请求分配很多个值,使⽤双缓冲,当1个 ⽤完可以使⽤另⼀个,同时将那个已经使⽤的刷新。这样就可以解决这种问题,中等级别的并发使⽤这种⽅式完全能满⾜。如果说你的i/o超过了⼀台电脑的i/o速度,那这种⽅法就不太实⽤了。个⼈认为集中存放还有另外⼀种⽅法,就是说给每个⽤户去分⽚,每个⼈相关的id从从⼀个⽚中去读区,这个量要满⾜他多久的时间需求就需要你设计为多⼤的区域,当然可以再次跟这个⽤户分配另⼀个区域(即下⼀跳),结合前⾯说的,你也可以⼀次多读取⼀些,读2个,还可以增加缓存,这样能将并发提供更多。
转载于:/onedreamer/blog/703179
发布者:admin,转转请注明出处:http://www.yc00.com/news/1689245776a225588.html
评论列表(0条)