SpringBoot Zookeeper 实现 分布式自增主键

内容摘自黑马

 

1. 加入依赖: zookeeper的java客户端

<!-- curator ZK 客户端 -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.2.0</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.2.0</version>
</dependency>

2. 配置文件

自己随便弄个位置, 可以放在application.yml, 也可以放在其它配置文件等

# zk host地址
zk.host=192.168.220.145:2181
# zk自增存储node
zk.sequence-path=/heima-leadnews/sequence/

3. 枚举类封装

public enum ZkSequenceEnum {
    AP_LIKES,AP_READ_BEHAVIOR,AP_COLLECTION,AP_USER_FOLLOW,AP_USER_FAN
}

4. 序列封装

public class ZkSequence {

    RetryPolicy retryPolicy = new ExponentialBackoffRetry(500, 3);

    DistributedAtomicLong distAtomicLong;

    public ZkSequence(String sequenceName, CuratorFramework client){
        distAtomicLong = new DistributedAtomicLong(client,sequenceName,retryPolicy);
    }

    /**
     * 生成序列
     * @return
     * @throws Exception
     */
    public Long sequence() throws Exception{
        AtomicValue<Long> sequence = this.distAtomicLong.increment();
        if(sequence.succeeded()){
            return sequence.postValue();
        }else{
            return null;
        }
    }

}

5. Client封装

@Setter
@Getter
public class ZookeeperClient  {
    private static Logger logger = LoggerFactory.getLogger(ZookeeperClient.class);
    private String host;
    private String sequencePath;

    // 重试休眠时间
    private final int SLEEP_TIME_MS = 1000;
    // 最大重试1000次
    private final int MAX_RETRIES = 1000;
    //会话超时时间
    private final int SESSION_TIMEOUT = 30 * 1000;
    //连接超时时间
    private final int CONNECTION_TIMEOUT = 3 * 1000;

    //创建连接实例
    private CuratorFramework client = null;
    // 序列化集合
    private Map<String, ZkSequence> zkSequence = Maps.newConcurrentMap();

    public ZookeeperClient(String host,String sequencePath){
        this.host = host;
        this.sequencePath = sequencePath;
    }

    @PostConstruct
    public void init() throws Exception{
        this.client = CuratorFrameworkFactory.builder()
                .connectString(this.getHost())
                .connectionTimeoutMs(CONNECTION_TIMEOUT)
                .sessionTimeoutMs(SESSION_TIMEOUT)
                .retryPolicy(new ExponentialBackoffRetry(SLEEP_TIME_MS, MAX_RETRIES)).build();
        this.client.start();
        this.initZkSequence();
    }

    public void initZkSequence(){
        ZkSequenceEnum[] list = ZkSequenceEnum.values();
        for (int i = 0; i < list.length; i++) {
            String name = list[i].name();
            String path = this.sequencePath+name;
            ZkSequence seq = new ZkSequence(path,this.client);
            zkSequence.put(name,seq);
        }
    }

    /**
     * 生成SEQ
     * @param name
     * @return
     * @throws Exception
     */
    public Long sequence(ZkSequenceEnum name){
        try {
            ZkSequence seq = zkSequence.get(name.name());
            if (seq != null) {
                return seq.sequence();
            }
        }catch (Exception e){
            logger.error("获取[{}]Sequence错误:{}",name,e);
        }
        return null;
    }
}

6. config封装

/**
 * 自动化配置核心数据库的连接配置
 */
@Setter
@Getter
@Configuration
@ConfigurationProperties(prefix="zk")
@PropertySource("classpath:zookeeper.properties")
public class ZkConfig {

    String host;
    String sequencePath;

    /**
     * 这是最快的数据库连接池
     * @return
     */
    @Bean
    public ZookeeperClient zookeeperClient(){
        return new ZookeeperClient(this.host,this.sequencePath);
    }

}

7. Sequences封装

@Component
public class Sequences {

    @Autowired
    private ZookeeperClient client;

    public Long sequenceApLikes(){
        return this.client.sequence(ZkSequenceEnum.AP_LIKES);
    }

    public Long sequenceApReadBehavior(){
        return this.client.sequence(ZkSequenceEnum.AP_READ_BEHAVIOR);
    }

    public Long sequenceApCollection(){
        return this.client.sequence(ZkSequenceEnum.AP_COLLECTION);
    }

    public Long sequenceApUserFollow(){return this.client.sequence(ZkSequenceEnum.AP_USER_FOLLOW);}

    public Long sequenceApUserFan(){return this.client.sequence(ZkSequenceEnum.AP_USER_FAN);}

}

8. 使用方法

// 第一步,注入Sequences
@Autowired
private Sequences sequences;

// 第二步,在方法中调用生成
alb.setId(sequences.sequenceApCollection());

9 扩展

如后期需要新增ZkSequence自增表,可参考以下操作步骤,快速实现:

  • 在ZkSequenceEnum中定义对应的枚举项,规范要求枚举项与物理表名一致且大写

  • 在Sequences中定义对应的调用方法,规范要求方法由sequence前缀+驼峰表名组成

上一篇:1152. Analyze User Website Visit Pattern


下一篇:Java学习实战教程之Hibernate使用Oracle数据库遇到的几个问题