库表设计基本字段

postgresql
DROP TABLE IF EXISTS base;
CREATE TABLE base(
    id SERIAL NOT NULL,
    data_id VARCHAR(32) NOT NULL,
    created_by VARCHAR(255),
    revision INTEGER,
    state INTEGER NOT NULL,
    status INTEGER NOT NULL,
    create_time TIMESTAMP NOT NULL,
    update_time TIMESTAMP NOT NULL,
    remark VARCHAR(255),
    deleted INTEGER,
    tenant_id INTEGER NOT NULL,
    PRIMARY KEY (id)
);

COMMENT ON TABLE base IS '表基础格式';
COMMENT ON COLUMN base.data_id IS '数据id';
COMMENT ON COLUMN base.created_by IS '创建人';
COMMENT ON COLUMN base.revision IS '乐观锁';
COMMENT ON COLUMN base.state IS '(隐藏、显示)、(是、否)、(可用、不可用)、(启用、禁用)';
COMMENT ON COLUMN base.status IS '状态';
COMMENT ON COLUMN base.create_time IS '创建时间';
COMMENT ON COLUMN base.update_time IS '更新时间';
COMMENT ON COLUMN base.remark IS '备注';
COMMENT ON COLUMN base.deleted IS '逻辑删除标记';
COMMENT ON COLUMN base.tenant_id IS '租户id';
mysql
DROP TABLE IF EXISTS base;
CREATE TABLE base(
    `id` bigint unsigned  AUTO_INCREMENT COMMENT 'id' ,
    `data_id` bigint unsigned NOT NULL  COMMENT '数据id' ,
    `created_by` VARCHAR(32)   COMMENT '创建人' ,
    `revision` INT(1)  unsigned  COMMENT '乐观锁' ,
    `state` INT(1) unsigned NOT NULL DEFAULT '0'   COMMENT '(隐藏、显示)、(是、否)、(可用、不可用)、(启用、禁用)' ,
    `status` INT(1) unsigned NOT NULL  DEFAULT '0'   COMMENT '状态' ,
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    `remark` VARCHAR(32)   COMMENT '备注' ,
    `deleted` INT(1) unsigned NOT NULL DEFAULT '0'   COMMENT '逻辑删除标记' ,
    `tenant_id` INT(11) unsigned  zerofill NOT NULL COMMENT '租户id' ,
    PRIMARY KEY (id)
)  COMMENT = '表基础格式';

【强制】必须显式指定主键, 勿用复合主键. 主键的命名统一为:id

【强制】bigint id 无意义主键id

【强制】bigint unsigned data_id 数据id,有的业务需要进行先插入再根据id进行操作

【强制】varchar(32) created_by 操作人

【强制】int(1) unsign deleted 逻辑删除标记.默认值0,删除值1

【强制】datetime create_time 默认值 CURRENT_TIMESTAMP 额外值 DEFAULT_GENERATED

【强制】datetime update_time 默认值 CURRENT_TIMESTAMP 额外值 DEFAULT_GENERATED on update CURRENT_TIMESTAMP

【强制】关于状态字段根据业务含义命名为: state、status

【强制】界面上要显示成树形结构的表,至少需要3个字段: id、parent_id、sort_value

【强制】POJO 类的布尔属性不能加 is,而数据库字段必须加 is_,要求在 resultMap 中进行字段与属性之间的映射。

【强制】主键索引名为 pk_字段名

【强制】唯一索引名为 uk_字段名

【强制】普通索引名则为 idx_字段名。

【强制】不得使用外键与级联,一切外键概念必须在应用层解决

【强制】不用存储过程

【强制】数据库名、表名、字段名统一使用小写字母, _ 分割

【强制】表和字段必须加注释!

【强制】当字段为外键时,字段名为:关联表_id, 注释需要在字段注释基础上,换行加上 #关联表表名来说明关联的哪张表。
【建议】租户字段以及机构字段用zerofill ,这样数据表尽可能美观
【建议】枚举字段直接用enum。注释模板: 注释内容;#枚举类名{枚举值英文名:“枚举值英文注释”; …}

说明:data_id可以用varchart类型,uuid去生成分布式id
也可以用redis的方式生成long类型id。但是需要注意redis开启事务之后和没有开启事务的区别。注意批量id生成的测试。


package com.pms.regist.id;

import com.pms.common.core.utils.SequenceUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.StringJoiner;

/**
 * {@docRoot}
 * {@inheritDoc}
 *
 * @author miaoyi
 * <p>描述: [分布式id生成服务] </p>
 * 如果存在多redis实例:请考虑以下三点
 * ①时钟同步:时间不同步可能会导致不同节点生成具有相同时间戳的ID,尤其是在接近“秒级”精度的时间戳使用时。
 * ②数据一致性:实例之间需要有某种形式的数据共享或一致性协议,以确保自增计数器(count)的唯一性和正确性。常见的做法是使用Redis的集群模式(如Redis Cluster)或哨兵模式(Sentinel),并确保incr操作在集群中是原子性的。
 * ③键的分区策略:代码中通过"icr:" + keyPrefix + ":" + date来生成Redis的键名,这一步需要确保在多Redis实例的架构中,相同keyPrefix和date的键总是路由到同一个Redis实例上。
 * 如果使用了哈希槽(hash slot)分区的Redis Cluster,这一点尤为重要,因为键的哈希值决定了它归属的槽和实例。设计不当可能导致不同实例上的键冲突或重复。
 */
@Service
public class RedisIdUtils {

    /**
     * 预生成开始时间戳:这个可以自己定义一个时间
     */
    private static final long BEGIN_TIMESTAMP = 1640995200L;

    /**
     * 序列号的位数
     */
    private static final int COUNT_BITS = 32;

    /**
     * redis提供的字符串
     */
    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 有参构造函数
     *
     * @param stringRedisTemplate stringRedisTemplate
     */
    public RedisIdUtils(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }


    /**
     * 功能描述:根据keyPrefix前缀生成对应业务的全局唯一ID
     * keyPrefix:使用前缀来区分不同的业务
     *
     * @return long ID
     */
    public long nextId(String keyPrefix) {
        // 1.生成时间戳
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSecond - BEGIN_TIMESTAMP;
        // 2.生成序列号
        // 2.1.获取当前日期,精确到天
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        // 2.2.自增长 icr:order:2023:08:13
        long count = this.incr("icr:" + keyPrefix + ":" + date);
        // 3.拼接并返回  timestamp << COUNT_BITS :向左移动32位
        //原本时间戳在低位上,通过向左移动32位,变位到高位存储,低32位都是0,然后与自增序列按位操作
        //形成低32位为序列号。
        return timestamp << COUNT_BITS | count;
    }


    /**
     * 功能描述:生产dataId  !!注意:这个id返回给前端时候需要注意精度问题。如果用Long类型返回给前端就会损失精度
     */
    public long generateDataId() {
        return nextId("data:id");
    }

    /**
     * 生成自增ID-用来生成订单号
     * keyPrefix:使用前缀来区分不同的业务
     *
     * @return 自增ID
     */
    public String autoId(String keyPrefix) {
        LocalDateTime now = LocalDateTime.now();
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        String currentDate = SequenceUtil.getCurrentDate();
        long sequence = this.incr("icr:" + keyPrefix + ":" + date);
        String seq = SequenceUtil.getSequence(sequence);
        StringJoiner sj = new StringJoiner("");
        sj.add(currentDate).add(seq);
        return sj.toString();
    }

    /**
     * 获取递增---注意这里不要开启redis事务。开启事务事务传递特性会包NEP异常
     * 注意这里只返回递增id,只要返回了就计算已经用掉了
     *
     * @param key key
     * @return long 递增id
     */
    public long incr(String key) {
        return stringRedisTemplate.opsForValue().increment(key, 1);
    }

}


  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值