分布式下规则生成主键

首先,建一张用于存储自增序列的表,相当于所有的按此规则生成主键的表在此都会有对应一条记录。

建表语句:

CREATE TABLE PUB_SEQUENCE_NUMBER(
  prefix VARCHAR(10) NOT NULL PRIMARY KEY COMMENT '前缀(主键)',
  NAME  VARCHAR(30) NOT NULL COMMENT '描述',
  today char(8) NOT NULL COMMENT '当天日期',
  minNum INTEGER NOT NULL DEFAULT 0 COMMENT '序列号最小号码',
  currentNum INTEGER NOT NULL DEFAULT 0 COMMENT '当前序列号',
  numLength INTEGER NOT NULL DEFAULT 8 COMMENT '序列号长度'
);

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.suning.primarykey</groupId>
    <artifactId>tigbs-primarykey</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.3</version>
        </dependency>

        <!-- test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <scope>test</scope>
            <version>4.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.12</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.7</version>
        </dependency>
        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.2.3.RELEASE</version>
        </dependency>
        <!-- aop -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.8</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.8.8</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.8</version>
        </dependency>
        <!--spring mybatis 整合-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.13</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.13</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <scope>runtime</scope>
            <version>1.7.13</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <nonFilteredFileExtensions>
                        <nonFilteredFileExtension>tbl</nonFilteredFileExtension>
                    </nonFilteredFileExtensions>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

对应实体类:

package com.cn.tigbs.bean;

/**
 * 报表主键生成策略bean
 */
public class SequenceNumber {
    //序列前缀
    private String prefix;
    //
    private String name;
    //当前日期转换为字符串形式
    private String today;

    private int minNum;
    private int currentNum;
    private int numLength;

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getToday() {
        return today;
    }

    public void setToday(String today) {
        this.today = today;
    }

    public int getMinNum() {
        return minNum;
    }

    public void setMinNum(int minNum) {
        this.minNum = minNum;
    }

    public int getCurrentNum() {
        return currentNum;
    }

    public void setCurrentNum(int currentNum) {
        this.currentNum = currentNum;
    }

    public int getNumLength() {
        return numLength;
    }

    public void setNumLength(int numLength) {
        this.numLength = numLength;
    }

    public SequenceNumber() {
    }

    public SequenceNumber(String prefix, String name, int minNum, int currentNum, int numLength) {
        this.prefix = prefix;

        this.name = name;
        this.minNum = minNum;
        this.currentNum = currentNum;
        this.numLength = numLength;
    }

    @Override
    public String toString() {
        return "SequenceNumber{" +
                "prefix='" + prefix + '\'' +
                ", name='" + name + '\'' +
                ", today='" + today + '\'' +
                ", minNum=" + minNum +
                ", currentNum=" + currentNum +
                ", numLength=" + numLength +
                '}';
    }
}

对应dao层:

import com.cn.tigbs.bean.SequenceNumber;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface SequenceNumberDao {

    /**
     * 根据前缀生成一个序列号信息
     * @param prefix 前缀
     * @return
     */
    SequenceNumber newSequenceNumber(@Param("prefix") String prefix);

    /**
     * 将生成的序列号更新到数据库
     * @param sequnceNumber 需要更新信息
     */
    void updateSequenceNumber(@Param("bean") SequenceNumber sequnceNumber);

    /**
     * 获取数据库当天日期
     * @return
     */
    String getToday();
}

用于存储要生成对应主键的表的枚举类:

package com.cn.tigbs.Enum;

import com.cn.tigbs.bean.SequenceNumber;

public enum SequenceNumberEnum {
    SEA(new SequenceNumber("SEA","海洋",1,1,8)),
    COD(new SequenceNumber("CLOUD","云",1,1,8))
    ;

    private SequenceNumber sequenceNumber;

    public SequenceNumber getSequenceNumber() {
        return sequenceNumber;
    }

    public void setSequenceNumber(SequenceNumber sequenceNumber) {
        this.sequenceNumber = sequenceNumber;
    }

    SequenceNumberEnum(SequenceNumber sequenceNumber) {
        this.sequenceNumber = sequenceNumber;
    }
}

service:

package com.cn.tigbs.service;

import com.cn.tigbs.Enum.SequenceNumberEnum;

public interface SequenceNumberService {
    /**
     * 生成一个主键
     * @param sequenceNumberEnum 主键生成类型
     * @return 返回一个生成的主键
     */
    String newSequenceNumberEnum(SequenceNumberEnum sequenceNumberEnum);
}

实现类:

package com.cn.tigbs.impl;

import com.cn.tigbs.Enum.SequenceNumberEnum;
import com.cn.tigbs.bean.SequenceNumber;
import com.cn.tigbs.dao.SequenceNumberDao;
import com.cn.tigbs.service.SequenceNumberService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class SequenceNumberServiceImpl implements SequenceNumberService {

    @Resource
    private SequenceNumberDao sequenceNumberDao;

    @Override
    public synchronized String newSequenceNumberEnum(SequenceNumberEnum sequenceNumberEnum) {
        if (sequenceNumberEnum == null) {
            return null;
        }
        SequenceNumber sequenceNumber = sequenceNumberDao.newSequenceNumber(sequenceNumberEnum.getSequenceNumber().getPrefix());

        if (sequenceNumber == null) {
            sequenceNumber = sequenceNumberEnum.getSequenceNumber();
            sequenceNumber.setToday(sequenceNumberDao.getToday());
        }

        sequenceNumberDao.updateSequenceNumber(sequenceNumber);
        return String.format("%s%6s%08d", sequenceNumber.getPrefix(), sequenceNumber.getToday(), sequenceNumber.getCurrentNum());
    }
}

mybatis 配置文件:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <properties>
        <property name="dialect" value="mysql"/>
        <property name="pageSqlId" value=".*Page$"/>
    </properties>
    <settings>
        <setting name="cacheEnabled" value="false"/>
        <setting name="lazyLoadingEnabled" value="false"/>
    </settings>
    <!--<plugins>-->
    <!--<plugin interceptor="com.cmbchina.common.interceptor.PageInterceptor"/>-->
    <!--</plugins>-->

</configuration>

spring 配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.suning.tigbs" />


    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/demo?useUnicode=yes&amp;characterEncoding=utf8&amp;allowMultiQueries=true"/>
        <property name="username" value="root"/>
        <property name="password" value="xmtx"/>
        <property name="minIdle" value="10"/>
        <property name="maxIdle" value="10"/>
        <property name="maxWaitMillis" value="-1"/>
        <property name="maxTotal" value="10"/>
    </bean>
    <!-- spring和MyBatis整合-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation"
                  value="classpath:META-INF/mybatis/sql-map-config.xml" />
        <property name="mapperLocations" value="classpath*:META-INF/mybatis/mapper/*Dao.xml" />
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer">
        <property name="annotationClass" value="org.springframework.stereotype.Repository"/>
        <property name="basePackage" value="com.suning.tigbs.dao"/>
    </bean>

    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="*"  propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* *..*ServiceImpl*.*(..))"/>
    </aop:config>
</beans>

测试类:

package com.cn.tigbs.impl;

import com.cn.tigbs.Enum.SequenceNumberEnum;
import com.cn.tigbs.service.SequenceNumberService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;

import static org.junit.Assert.*;

public class SequenceNumberServiceImplTest {
    @Test
    public void newSequeceNumberEnum() throws Exception {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/spring/spring-base-jdbc.xml");
        SequenceNumberService sequenceNumberService = applicationContext.getBean(SequenceNumberService.class);
        Queue<String> queue = new ArrayBlockingQueue<String>(2000);
        List<Thread> list = new ArrayList<>();
        for (int i = 0;i < 2000; i ++){
            list.add(new Thread(()->{
                String key = sequenceNumberService.newSequenceNumberEnum(SequenceNumberEnum.SEA);

                queue.add(key);
            }));
        }
        for (Thread thread : list){
            thread.start();
        }

        while (queue.size() != 2000);
        System.out.println(queue);
    }


    public static void main(String[] args) {



            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/spring/spring-base-jdbc.xml");
            SequenceNumberService sequenceNumberService = applicationContext.getBean(SequenceNumberService.class);
            Queue<String> queue = new ArrayBlockingQueue<String>(50);
            List<Thread> list = new ArrayList<>();
            for (int i = 0;i < 50; i ++){
                list.add(new Thread(()->{
                    String key = sequenceNumberService.newSequenceNumberEnum(SequenceNumberEnum.SEA);

                    queue.add(key);
                }));
            }
            for (Thread thread : list){
                thread.start();
            }

            while (queue.size() != 50);
            System.out.println(queue);
        }



}

码云地址:

https://gitee.com/xiaomingnevermind/primarykey

文件可能会是空的,有时间的时候上传github,和码云。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏算法修养

javaWeb项目(SSH框架+AJAX+百度地图API+Oracle数据库+MyEclipse+Tomcat)之二 基础Hibernate框架搭建篇

   我们在搭建完Struts框架之后,从前台想后端传送数据就显得非常简单了。Struts的功能不仅仅是一个拦截器,这只是它的核心功能,此外我们也可以自定义拦截...

3219
来自专栏你不就像风一样

SpringBoot整合Mybatis使用注解或XML的方式开发

[User{id=1, name='name', age=18}, User{id=2, name='name2', age=19}, User{id=3, n...

542
来自专栏王磊的博客

asp.net 操作ftp 通用代码[测试通过]

代码如下: // 建立目录 FtpWebRequest Request = (FtpWebRequest)WebRequest.Crea...

3214
来自专栏liulun

WEB项目后端跨域请求

using System; using System.Collections.Generic; using System.IO; using System.Li...

19310
来自专栏编程坑太多

springboot (11) mybatis

1143
来自专栏一个会写诗的程序员的博客

SpringBoot 集成Kotlin : org.hibernate.InstantiationException: No default constructor for entity: : com

892
来自专栏Android知识点总结

SpringBoot-16-之整合MyBatis-xml篇+单元测试

1003
来自专栏james大数据架构

Excel导入导出数据库02

excel导入时还要保存字体、其背景颜色等信息时读取方法就要改变: 1 using System; 2 using System.Collections...

1769
来自专栏Netkiller

Spring boot 将 Session 放入 Redis

本文节选自《Netkiller Java 手札》 Spring boot 将 Session 放入 Redis 11.19. Session 11.19.1. ...

4614
来自专栏扎心了老铁

springboot kafka集成(实现producer和consumer)

本文介绍如何在springboot项目中集成kafka收发message。 1、先解决依赖 springboot相关的依赖我们就不提了,和kafka相关的只依赖...

6435

扫码关注云+社区