分布式下规则生成主键

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

建表语句:

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 条评论
登录 后参与评论

相关文章

来自专栏杨建荣的学习笔记

pl/sql中的参数模式(r4笔记第54天)

在平时的工作中,可能通过pl/sql传入参数来做一些特定的操作,参数模式一般有In,out.in out这几种 比如dbms_sqltune下的PREPARE_...

3104
来自专栏c#开发者

Oracle数据类型引起的性能问题(已经解决)!

为避免SQL-注入,所有的update,insert,delete,select全部使用带参数的形式编写 Update TableName Set FiledN...

4047
来自专栏信安之路

sqlmap自带的tamper你了解多少?

sqlmap 是一款注入神器广为人知,里面的 tamper 常常用来绕过 WAF ,很实用的模块,但是却常常被新手忽略(比如我),今天就整理总结一下 tampe...

890
来自专栏GreenLeaves

EF 通过DataAnnotations配置属性和类型

 一、通过Attribute配置约束 1、主键约束 通过KeyAttribute来配置主键约束,代码如下: [Key] public int PrimaryKe...

1805
来自专栏项勇

笔记30 | 数据存储之SQLite的介绍及使用

2548
来自专栏芋道源码1024

数据库分库分表中间件 Sharding-JDBC 源码分析 —— SQL 改写

本文主要基于 Sharding-JDBC 1.5.0 正式版 1. 概述 2. SQLToken 3.SQL 改写 3.4.1 分页补充 3.1 TableTo...

3996
来自专栏程序员的SOD蜜

ORM查询语言(OQL)简介--高级篇:脱胎换骨

相关文章内容索引: ORM查询语言(OQL)简介--概念篇 ORM查询语言(OQL)简介--实例篇 ORM查询语言(OQL)简介--高级篇:脱胎换骨 ORM查询...

2837
来自专栏Java 技术分享

WEB 小案例 -- 网上书城(一)

3545
来自专栏郭少华

Spring boot Mybatis-XML方式通用Mapper插件(七)

特别注意,如果使用了1.2.0以上版本 @MapperScan 注解,请使用 tk.mybatis.spring.annotation.MapperScan 注...

4821
来自专栏用户2442861的专栏

MyBatis学习总结(四)——解决字段名与实体类属性名不相同的冲突

  在平时的开发中,我们表中的字段名和表对应实体类的属性名称不一定都是完全相同的,下面来演示一下这种情况下的如何解决字段名与实体类属性名不相同的冲突。

711

扫码关注云+社区