数据库主键设计
文章目录
- 前言
- 1. 自增ID(Auto-Increment)
- 2. GUID (Globally Unique Identifier)
- 3. 雪花算法(Snowflake)
- 处理时钟回拨的方法
- 1. 简单等待
- 2. 配置时钟回拨安全窗口
- 3. 使用不同的机器 ID
- 小结
- 稳定的雪花算法实现方案
- 示例实现
- 1. 定义雪花算法类
- 2. 使用 Redis 或数据库实现分布式唯一 ID
- 解释
- 小结
- 其他方法
- 总结
前言
数据库主键的设计是数据库架构中的一个重要环节,不同的主键生成策略适用于不同的场景和需求
以下是几种常见的主键设计方法及其优缺点比较:
1. 自增ID(Auto-Increment)
优点:
- 实现简单,数据库自动管理,无需开发者介入。
- 递增的特性使得数据插入速度快,因为插入总是发生在索引的末尾。
- 易于理解和使用,便于查询和排序。
缺点:
- 分布式系统中难以保证全局唯一,因为每个节点的计数器独立增长。
- 数据泄露风险,自增ID容易暴露数据库的规模和增长速度。
- 如果发生大量删除操作,可能导致主键ID不连续,影响美观但不影响功能。
2. GUID (Globally Unique Identifier)
优点:
- 全球唯一,无论在任何系统、任何地点生成,都能保证唯一性。
- 无需依赖数据库,可以在客户端生成,适合分布式系统。
- 支持提前生成ID,有利于并行处理和离线操作。
缺点:
- 长度较大(通常为32字符),占用更多的存储空间和索引空间。
- 无序的特性可能导致索引碎片,降低插入性能。
- 不易读,不便于人工识别和调试。
3. 雪花算法(Snowflake)
雪花算法(Snowflake Algorithm)是一种用于生成唯一ID的算法,最初由Twitter公司开发。它是为了解决分布式系统中生成全局唯一ID的需求而设计的。在分布式系统中,如果不同节点生成的ID可能会发生冲突,这就需要一种机制来保证生成的ID在整个系统中唯一。
雪花算法的设计考虑了以下几个因素:
- 时间戳(Timestamp):使用当前时间来确保生成的ID是递增的,这样可以保证生成的ID是有序的。
- 机器ID(Machine ID):将机器的唯一标识(比如机器的MAC地址)作为一部分ID,确保不同机器生成的ID不会冲突。
- 序列号(Sequence Number):用来解决同一毫秒内生成多个ID时的冲突问题。
Java中如何使用雪花算法来设计数据库主键呢?下面是一个简单的示例:
public class SnowflakeIdGenerator {// 定义机器ID,可以通过配置文件或其他方式设置private long machineId;// 定义序列号private long sequence = 0L;// 定义初始时间戳private long twepoch = 1622874000000L; // 2021-06-05 00:00:00// 定义各部分占位数private long machineIdBits = 5L;private long maxMachineId = -1L ^ (-1L << machineIdBits);private long sequenceBits = 12L;private long sequenceMask = -1L ^ (-1L << sequenceBits);// 定义机器ID左移位数private long machineIdShift = sequenceBits;// 定义时间戳左移位数private long timestampLeftShift = sequenceBits + machineIdBits;// 上次生成ID的时间戳private long lastTimestamp = -1L;public SnowflakeIdGenerator(long machineId) {if (machineId > maxMachineId || machineId < 0) {throw new IllegalArgumentException("Machine ID can't be greater than " + maxMachineId + " or less than 0");}this.machineId = machineId;}public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");}if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {// 当同一毫秒内的序列号超过上限时,等待下一毫秒timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - twepoch) << timestampLeftShift) | (machineId << machineIdShift) | sequence;}private long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}public static void main(String[] args) {SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1); // 传入机器IDfor (int i = 0; i < 10; i++) {System.out.println(idGenerator.nextId());}}
}
在这个示例中,我们通过nextId()
方法来生成雪花算法生成的唯一ID。首先,我们需要设置一个机器ID,确保不同的机器有不同的ID。然后,调用nextId()
方法即可生成一个唯一的ID,这个ID包含了时间戳、机器ID和序列号三部分。最后,我们可以将生成的ID作为数据库表的主键。
值得注意的是,雪花算法生成的ID是趋势递增的,因此在数据库中使用时可能会带来一定的优势,比如辅助索引的性能优化。但也要注意在高并发情况下可能出现的一些问题,比如时钟回拨等。
优点:
- 结合了自增ID和GUID的优点,生成的ID是趋势递增的,且全局唯一。
- 高性能,适用于分布式环境,能够按需分配workerId和数据中心id,保证唯一性。
- ID较短(一般为64位),相比GUID节省存储空间。
- 有序性有助于索引优化。
缺点:
- 需要一个中心节点(或者多个,但需要协调)来生成ID,有一定的运维成本。
- 时钟回拨问题可能会影响ID的生成,需要特殊处理。
然而,雪花算法依赖于时间戳,因此时钟回拨(clock rollback)会对其造成问题。
处理时钟回拨的方法
1. 简单等待
当检测到时钟回拨时,直接等待直到时间回到正确的时间。这是最简单的处理方式,但会导致 ID 生成暂停一段时间。
public class SnowflakeIdGenerator {private long lastTimestamp = -1L;public synchronized long nextId() {long timestamp = timeGen();// 如果当前时间小于上一次生成ID的时间戳,说明系统时钟回拨if (timestamp < lastTimestamp) {// 等待直到时钟追上while (timestamp < lastTimestamp) {timestamp = timeGen();}}lastTimestamp = timestamp;return generateId(timestamp);}private long timeGen() {return System.currentTimeMillis();}private long generateId(long timestamp) {// 生成ID的逻辑return timestamp;}
}
2. 配置时钟回拨安全窗口
允许一定范围内的时钟回拨,在这个范围内继续生成 ID,但如果超出这个范围则抛出异常或采取其他措施。
public class SnowflakeIdGenerator {private long lastTimestamp = -1L;private static final long MAX_BACKWARD_MS = 5L; // 允许的最大时钟回拨时间public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {long offset = lastTimestamp - timestamp;if (offset <= MAX_BACKWARD_MS) {// 等待,直到时钟追上try {Thread.sleep(offset + 1);} catch (InterruptedException e) {throw new RuntimeException(e);}timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException("Clock moved backwards. Refusing to generate id");}} else {throw new RuntimeException("Clock moved backwards. Refusing to generate id");}}lastTimestamp = timestamp;return generateId(timestamp);}private long timeGen() {return System.currentTimeMillis();}private long generateId(long timestamp) {// 生成ID的逻辑return timestamp;}
}
3. 使用不同的机器 ID
在分布式系统中,每台机器有唯一的机器 ID。当检测到时钟回拨时,改变机器 ID 来避免冲突。这种方法需要协调机器 ID 的分配。
public class SnowflakeIdGenerator {private long lastTimestamp = -1L;private long machineId;private static final long MAX_MACHINE_ID = 1023L;public SnowflakeIdGenerator(long machineId) {if (machineId < 0 || machineId > MAX_MACHINE_ID) {throw new IllegalArgumentException("Machine ID out of range");}this.machineId = machineId;}public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {machineId = (machineId + 1) & MAX_MACHINE_ID;if (machineId == 0) {// 如果机器ID回到0,说明时钟回拨过大,拒绝生成IDthrow new RuntimeException("Clock moved backwards. Refusing to generate id");}timestamp = timeGen();}lastTimestamp = timestamp;return generateId(timestamp, machineId);}private long timeGen() {return System.currentTimeMillis();}private long generateId(long timestamp, long machineId) {// 生成ID的逻辑,包含时间戳和机器IDreturn (timestamp << 22) | (machineId << 12);}
}
小结
- 简单等待:当检测到时钟回拨时,等待直到时钟恢复到正确时间。这种方法简单但会导致 ID 生成暂停。
- 时钟回拨安全窗口:允许一定范围内的时钟回拨,如果超出这个范围则抛出异常或采取其他措施。
- 不同的机器 ID:当检测到时钟回拨时,改变机器 ID 来避免冲突。这种方法需要协调机器 ID 的分配。
稳定的雪花算法实现方案
以下是一个经过优化的方案,涵盖时钟回拨问题、分布式系统中的唯一性问题和高可用性问题
- 机器 ID 和数据中心 ID:通过配置不同的机器 ID 和数据中心 ID 来确保分布式系统中的唯一性。
- 时钟回拨处理:使用递增序列和缓存的时间戳来处理时钟回拨问题。
- 高可用性:结合 Redis 或数据库来生成分布式唯一 ID。
示例实现
1. 定义雪花算法类
public class SnowflakeIdGenerator {private static final long EPOCH = 1609459200000L; // 自定义纪元时间(2021-01-01)private static final long DATA_CENTER_ID_BITS = 5L;private static final long MACHINE_ID_BITS = 5L;private static final long SEQUENCE_BITS = 12L;private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS);private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);private static final long MACHINE_ID_SHIFT = SEQUENCE_BITS;private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATA_CENTER_ID_BITS;private final long dataCenterId;private final long machineId;private long sequence = 0L;private long lastTimestamp = -1L;public SnowflakeIdGenerator(long dataCenterId, long machineId) {if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {throw new IllegalArgumentException(String.format("DataCenter ID can't be greater than %d or less than 0", MAX_DATA_CENTER_ID));}if (machineId > MAX_MACHINE_ID || machineId < 0) {throw new IllegalArgumentException(String.format("Machine ID can't be greater than %d or less than 0", MAX_MACHINE_ID));}this.dataCenterId = dataCenterId;this.machineId = machineId;}public synchronized long nextId() {long timestamp = timeGen();if (timestamp < lastTimestamp) {throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");}if (timestamp == lastTimestamp) {sequence = (sequence + 1) & MAX_SEQUENCE;if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - EPOCH) << TIMESTAMP_SHIFT)| (dataCenterId << DATA_CENTER_ID_SHIFT)| (machineId << MACHINE_ID_SHIFT)| sequence;}private long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}private long timeGen() {return System.currentTimeMillis();}
}
2. 使用 Redis 或数据库实现分布式唯一 ID
为了进一步提高高可用性和唯一性,可以结合 Redis 或数据库实现分布式唯一 ID 生成。这里是一个使用 Redis 的示例:
import redis.clients.jedis.Jedis;public class DistributedIdGenerator {private final SnowflakeIdGenerator snowflakeIdGenerator;private final Jedis jedis;public DistributedIdGenerator(long dataCenterId, long machineId, String redisHost, int redisPort) {this.snowflakeIdGenerator = new SnowflakeIdGenerator(dataCenterId, machineId);this.jedis = new Jedis(redisHost, redisPort);}public long nextId() {long id = snowflakeIdGenerator.nextId();String key = "snowflake:" + id;while (jedis.exists(key)) {id = snowflakeIdGenerator.nextId();key = "snowflake:" + id;}jedis.setex(key, 3600, "1"); // 设置过期时间,避免长期存储return id;}
}
解释
-
基本雪花算法:
EPOCH
:自定义的纪元时间。DATA_CENTER_ID_BITS
、MACHINE_ID_BITS
和SEQUENCE_BITS
:数据中心 ID、机器 ID 和序列号的位数。nextId
方法:生成唯一 ID,并处理时钟回拨问题。
-
分布式唯一 ID:
- 使用 Redis 确保 ID 唯一性:在生成 ID 后,将其存储在 Redis 中,检查是否重复。
jedis.setex(key, 3600, "1")
:使用带过期时间的键来避免长期存储。
-
时钟回拨处理:
- 当检测到时钟回拨时,抛出异常或等待时间前进。
- 使用
tilNextMillis
方法等待直到时间前进。
小结
这种方案结合了雪花算法的高性能和 Redis 的分布式存储能力,解决了时钟回拨问题,并确保在分布式环境下生成唯一 ID。通过这些措施,可以实现一个稳定、高效的分布式唯一 ID 生成系统。
其他方法
- 复合主键:结合多个字段作为主键,适用于表中没有自然唯一标识符的场景。但增加了查询和维护的复杂性。
- 业务相关ID:如订单号,易于理解且与业务紧密相关,但可能需要额外的逻辑来保证唯一性,且扩展性较差。
总结
选择哪种主键生成策略取决于具体的应用场景:
- 对于单体应用或简单的分布式系统,自增ID可能是最简单高效的选择。
- 在分布式系统中,尤其是跨多个数据中心时,雪花算法因其高性能和全局唯一性成为优选。
- 当全局唯一性是首要考虑因素,且对存储空间不太敏感时,GUID是合适的选择。
- 具体场景下,也可以根据业务需求考虑复合主键或业务相关ID的方案。
相关文章:
数据库主键设计
文章目录 前言1. 自增ID(Auto-Increment)2. GUID (Globally Unique Identifier)3. 雪花算法(Snowflake)处理时钟回拨的方法1. 简单等待2. 配置时钟回拨安全窗口3. 使用不同的机器 ID 小结稳定的雪花算法实现方案示例实现1. 定义雪…...
小熊家务帮day13-day14 门户管理(ES搜索,Canal+MQ同步,索引同步)
目录 1 服务搜索1.1 需求分析1.2 技术方案1.2.1 使用Elasticsearch进行全文检索(为什么数据没有那么多还要用ES?)1.2.2 索引同步方案1.2.2.1 Canal介绍1.2.2.1 Canal工作原理 1 服务搜索 1.1 需求分析 服务搜索的入口有两处: 在…...
Android8.1高通平台修改默认输入法
需求 安卓8.1 SDK原生的输入法只能打英文, 需要替换成中文输入法. 以高通平台为例, 其它平台也适用. 查看设备当前默认输入法 adb shell settings list secure | grep input 可以看到当前默认是LatinIME这个安卓原生输入法. default_input_methodcom.android.inputmethod.l…...
49. 字母异位词分组
思路:题目的意思是,将所有字母相同的字符串放到一个数组中 解题思路是:使用map,使用排序好的字符串作为key,源字符串作为value,就可以实现所有字母相同的字符串对应一个key vector<vector<string>> groupAnagrams(ve…...
负压实验室设计建设方案
随着全球公共卫生事件的频发,负压实验室的设计和建设在医疗机构中的重要性日益凸显。负压实验室,特别是负压隔离病房,主要用于控制传染性疾病的扩散,保护医护人员和周围环境的安全。广州实验室装修公司中壹联凭借丰富的实验室装修…...
作文笔记10 复述故事
一、梳理内容(用表格,示意图) 救白蛇 得宝石 救相亲 变石头 人们纪念海力布 二、按顺序,不遗漏主要情节 (猎人海力布热心救人)救白蛇 得宝石(白蛇强调宝石禁忌)(海力…...
业务安全蓝军测评标准解读—业务安全体系化
目录 1.前言 2.业务蓝军测评标准 2.1 业务安全脆弱性评分(ISVS) 2.2 ISVS评分的参考意义<...
关于焊点检测SJ-BIST)模块实现
关于焊点检测SJ-BIST)模块实现 语言 :Verilg HDL 、VHDL EDA工具:ISE、Vivado、Quartus II 关于焊点检测SJ-BIST)模块实现一、引言二、焊点检测功能的实现方法(1) 输入接口(2) 输出接…...
使用 Logback.xml 配置文件输出日志信息
官方链接:Chapter 3: Configurationhttps://logback.qos.ch/manual/configuration.html 配置使用 logback 的方式有很多种,而使用配置文件是较为简单的一种方式,下述就是简单描述一个 logback 配置文件基本的配置项: 由于 logba…...
Allegro-开店指南
开店指南 Allegro企业账户注册流程 Allegro注册流程分成两个主要阶段: 第一创建您的账户,第二激活您账户的销售功能。完成两个阶段,才能在Allegro进行销售。 中国企业应该入驻Business account(企业账户)。 第二阶段ÿ…...
Spring AI 第二讲 之 Chat Model API 第二节Ollama Chat
通过 Ollama,您可以在本地运行各种大型语言模型 (LLM),并从中生成文本。Spring AI 通过 OllamaChatModel 支持 Ollama 文本生成。 先决条件 首先需要在本地计算机上运行 Ollama。请参阅官方 Ollama 项目 README,开始在本地计算机上运行模型…...
服务器环境搭建
服务器的使用。 本地服务器 虚拟机服务器 云服务器。 服务器配置内容 如何实现部署到云服务器? 环境部署是一件费劲的事。 自己一个人坚持慢慢弄,也能行。 但是要是一个组的人,问你怎么弄环境。 可就难了,不同的人部署的环境不同&…...
数仓建模—指标体系指标拆解和选取
数仓建模—指标拆解和选取 第一节指标体系初识介绍了什么是指标体系 第二节指标体系分类分级和评价管理介绍了指标体系管理相关的,也就是指标体系的分级分类 这一节我们看一下指标体系的拆解和指标选取,这里我们先说指标选取,其实在整个企业的数字化建设过程中我们其实最…...
微信小程序如何在公共组件中改变某一个页面的属性值
需求 公共组件A改变页面B的属性isShow的值。 思路 首先目前我不了解可以直接在组件中改变页面的值的方法,所以我通过监听的方式在B页面监听app.js的某一属性值的改变从而改变B页面的值,众所周知app.js的某一属性值是很容易就能更改的。 app.js globa…...
TCP/UDP的区别
首先来介绍一下什么是TCP和UDP TCP(传输控制协议)和UDP(用户数据报协议)是互联网协议套件中两个重要的传输层协议。它们在数据传输的方式、可靠性、连接性等方面有显著的区别。 总之他们两个就是个协议,协议也就是数…...
JavaWeb1 Json+BOM+DOM+事件监听
JS对象-Json //Json 字符串转JS对象 var jsObject Json.parse(userStr); //JS对象转JSON字符串 var jsonStr JSON.stringify(jsObject);JS对象-BOM BOM是浏览器对象模型,允许JS与浏览器对话 它包括5个对象:window、document、navigator、screen、hi…...
DSP6657 GPIO中断学习(只支持GPIO0-15)
1 简介 使用创龙板卡的KEY2按键通过中断的方式控制LED3的亮灭 2 中断学习 在C665x设备上,CPU中断是通过C66x CorePac中断控制器进行配置的。该中断控制器允许最多128个系统事件被编程到任意12个CPU可屏蔽中断输入(CPUINT4至CPUINT15)、CPU…...
vue数字翻盘,翻转效果
数字翻转的效果 实现数字翻转的效果上面为出来的样子 下面为代码,使用的时候直接引入,还有就是把图片的路径自己换成自己或者先用颜色替代,传入num和numlength即可 <template><div v-for"(item, index) in processedNums&quo…...
【简单讲解TalkingData的数据统计】
🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…...
JMeter的基本使用
JMeter的基本使用三步骤:1.添加线程、2.添加请求、3.添加查询结果的内容 如果需要添加token请求头来验证,则需要再加上一步骤:添加请求头 1.线程 添加线程的方式 主要修改者三个属性值 Number of Threads:并发线程数 Ramp-up…...
Oracle和Random Oracle
Oracle和Random Oracle 在计算机理论里面经常可以看到oracle,这个oracle可以是一个程序 一片代码 一个算法 一个机器 也可以是一个函数 甚至是一个关系。但我们只能知道这个oracle能做什么,不清楚他是怎么做的。所以经常讲其称为黑箱。推广一点…...
word 无法自动检测拼写
word 有时候不能分辨是哪种语言,比如把英语错认为法语 。 例如:Interlaayer spacace,发现误认为是法语。 1、选中Interlaayer spacace 2、点击语言下拉按钮 选择设置校对语言 发现校对语言为法语 3、手动修改校对语言为英语,并点击确认。 4、发现现…...
docker和docker-compose的安装
docker的安装 1.安装 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun2.设置开机自启动 systemctl start docker #启动docker systemctl enable docker3.配置阿里云镜像 不配置镜像的话,进行 docker pull 等操作会比较慢。进入阿里云&…...
python的一种集成开发工具:PyCharm开发工具
一. 简介 本文简单了解两种 python语言所使用的 集成开发环境: PyCharm、vscode。 python语言学习中,可以任意选中这两个集成开发环境的一种就可以。本文先来简单学习 PyCharm开发工具安装与使用。 二. python的一种集成开发工具:PyChar…...
【匹配线段问题】
问题: 如下图所示。图中有两行正整数,每行中有若干个正整数。如果第一行的某个数r与第二行的某个数相同,这样就可以在这两个正整数之间划一条线,并称之为r-匹配线段。下图中存在3-匹配线段和2-匹配线段。 请编写完整程序…...
vue中$bus.$emit和$bus.$on的用法温故
$bus. $emit、 $bus. $on 用于非父子组件之间通信 1、在main.js中注册 Vue.prototype.$bus new Vue();new Vue({render: h > h(App),router,store }).$mount(#app)2、在需要发送信息的组件中,发送事件 this.$bus.$emit("method",params);…...
【JavaScript脚本宇宙】优化你的React项目:探索表单库的世界
React表单库解析:特性,使用方法和使用场景 前言 在现代的web开发中,表单是Web应用程序的核心组成部分之一。为了助力开发者更快捷、高效地处理表单状态和验证等问题,本文将介绍六种不同的React表单库,包括它们的特性…...
kvm虚拟化
虚拟化是一种资源管理技术,是将计算机的各种资源,如服务器,网络,内存及存储等,以抽象,转换后呈现出来,打破物理设备结构见的不可切割的障碍,使用户可以比原来的架构更好的方式来应用…...
算法训练营第五十天 | LeetCode 198 打家劫舍、LeetCode 213 打家劫舍II、LeetCode 337 打家劫舍III
LeetCode 198 打家劫舍 代码如下: class Solution { public:int rob(vector<int>& nums) {vector<int> dp(nums.size() 1, 0);dp[1] nums[0];for (int i 2; i < nums.size(); i) {dp[i] max(dp[i - 1] ,dp[i - 2] nums[i - 1]);}return dp…...
linux学习:进程通信 管道
目录 例子1 父进程向子进程发送一条消息,子进程读取这条消息 例子2 mkfifo 函数创建一个命名管道 例子3 mkfifo 函数创建一个命名管道处理可能出现的错误 例子4 管道文件是否已存在 例子5 除了“文件已存在”进行处理 例子6 创建一个命名管道&…...
大网站建设/企业软文营销发布平台
解析语法查询就是调用方法查询的原始查询 例如: 查询所有的查询器的语法为:*:*,因为lucene查询是根据term来做的,既是:key:value类型。*:*表示所有域中的所有值。 api调用语法解析 pom.xml 必须…...
有没有免费的网站服务器/优化关键词具体要怎么做
使用 ASP Request 对象,您可以创建一个简单而功能强大的脚本来收集和处理 HTML 表格数据。在本主题中,您将不仅学会如何创建基本的表格处理脚本,而且还将获得用于验证 Web 服务器和用户浏览器上的表格信息的一些有用技术。关于 HTML 表格HTML…...
贵州省建设厅报名网站/seo外包顾问
目录 1、?. (可选链运算符) 2、??(空值合并运算符) 1、?. (可选链运算符) 在javascript中如果一个值为null、undefined,直接访问下面的属性,会报 Uncaught TypeError: Cannot …...
党办网站建设/免费html网站模板
1. 适配器状态查询 发送: 01 04 00 00 00 01 31 CA 响应: 01 04 02 00 00 B9 30 2. 室内机连接状态 发送: 01 04 00 01 00 04 A0 09 响应: 01 04 08 00 00 00 00 00 00 00 00 24 0D 3. 室内机通信状态 发送: 01 04 00 05 00 04 E1 C8 响应: 01 04 08 00 00 00 00 00 00 00 00 2…...
转载到wordpress/站长工具百度
向我提问律图巴音郭楞律师解答问题:4233条一、纳税额确定:合伙企业的投资者按照合伙企业的全部生产经营所得和合伙协议约定的分配比例确定应纳税所得额,合伙协议没有约定分配比例的,以全部生产经营所得和合伙人数量平均计算每个投…...
公司做网站让拍照备案/宁波seo托管公司
安装docker 【Docker】简单介绍与安装 拉取镜像 docker search mysql(搜索MySQL版本)docker pull mysql(拉取MySQL镜像)查看镜像 docker images指定自定义网络 docker network create --subnet172.10.0.0/16 mynetwork查看自定义网络 docker network ls删除自定义网络 …...