前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >《Object Serialization Stream Protocol/对象序列化流协议》总结

《Object Serialization Stream Protocol/对象序列化流协议》总结

作者头像
p4nda
发布于 2023-01-03 06:21:49
发布于 2023-01-03 06:21:49
67800
代码可运行
举报
文章被收录于专栏:技术猫屋技术猫屋
运行总次数:0
代码可运行

0、写在前面

本文主要是《Object Serialization Stream Protocol》一文的翻译,然后对序列化格式进行了一些总结

1、概述

​stream 格式满足以下设计目标:

  • 结构紧凑,便于高效阅读;
  • 允许仅使用流的结构和格式而不需要深入了解 stream,这种情况不需要调用调用任何类的代码;
  • 只允许 stream 对数据进行访问和操作;

2、stream元素

​表示 stream 中的对象需要的基本结构。对象的每个属性都需要表示:它的类和类中的字段,这些数据会被写入而且之后会被类中特定的方法读取。stream 中对象的表示可以用语法来描述。null objects, new objects, classes, arrays, strings以及对stream 中已有的任何对象的反向引用,都有特殊的表示。写入 stream 的每个对象都分配了一个Handle,用于引用回该对象。从0x7E0000开始按顺序分配Handle。当 stream 被重置时,句柄在0x7E0000处重新启动。

类对象由以下对象表示:

  • 它的ObjectStreamClass对象

非动态代理类的ObjectStreamClass对象由以下表达式表示:

  • 可兼容类的SUID
  • 一组指示类的各种属性的标志,例如该类是否定义了 writeObject 方法,以及该类是否可序列化、是否是可外部或者是否是枚举类型
  • 可序列化字段的数量
  • 默认情况下,对于类的字段数组和对象字段来说,字段的类型要作为字符串被包含,并且必须按照 Java 虚拟机规范中的规定,采用“字段描述符”格式(例如,Ljava/lang/Object;
  • annotateClass 方法写入的可选块数据(Data-Block)记录或对象
  • 其超类型的 ObjectStreamClass(如果超类不可序列化,则为 null)

动态代理类的ObjectStreamClass对象由以下表达式表示:

  • 动态代理类实现的接口数
  • 动态代理类实现的所有接口的名称,这些接口通过调用Class的getInterfaces方法的返回结果进行排序列出;
  • 可选的块数据(Data-Block)记录或由AnnotationProxyClass方法编写的对象
  • 超类对应的java.lang.reflect.ProxyObjectStreamClass

​ 字符串对象的表示由长度信息和MUTF-8编码的字符串内容组成。MUTF-8编码与Java虚拟机和Java.io.DataInput以及DataOutput接口中使用的编码相同;它在表示补充字符空字符方面与标准UTF-8不同。长度信息的形式取决于MUTF-8编码中字符串的长度。如果给定字符串的MUTF-8编码长度小于65536字节,则该长度将写入表示无符号16位整数的2字节。从Java2平台标准版v1.3开始,如果MUTF-8编码中的字符串长度为65536字节或更多,那么该长度将以表示有符号64位整数的8字节表示。序列化 stream 中字符串前面的类型码用于表明写入字符串的格式。

数组由以下内容表示:

  • 他们的ObjectStreamClass对象
  • 元素的数量。
  • 值的顺序。值的类型在数组的类型中是隐式的。例如,字节数组的值是byte类型的。

枚举常量由以下表达式表示:

  • 常量的基本枚举类型的 ObjectStreamClass 对象
  • 常量的名称字符串

stream 中的新对象New objects)由以下表示:

  • 所有对象类的派生类信息;
  • 对象的每一个可序列化类的数据,从它的顶级父类开始写入。针对 Stream 中的每一个类的信息包含以下内容: -- 一个类中的可序列化字段信息;

-- 如果这个类包含writeObject/readObject方法,有可能出现通过writeObject方法写入的可选对象或者基础类型的数据块(Data-Block)记录,跟着使用endDataBlock的代码;

​ 类写入的所有原始数据都被缓冲并包装在数据块记录中,无论数据是在 writeObject 方法内写入 stream 还是从 writeObject 方法外部直接写入 Stream。 此数据只能通过相应的 readObject 方法读取或直接从 stream 中读取。writeObject方法写入的对象终止任何以前的数据块记录,并视情况作为常规对象或空引用或反向引用写入。数据块记录允许错误恢复丢弃任何可选数据。当从类内调用时,stream 可以丢弃任何数据或对象,直到endBlockData

3、Stream 协议版本

​ 有必要对JDK1.2中的序列化 Stream 格式进行更改,该格式与JDK1.1的所有次要版本都不向后兼容。为了提供需要向后兼容的情况,Oracle 添加了一个功能,这个功能用来指示在编写序列化流时要使用哪个协议版本。ObjectOutputStream中的useProtocolVersion方法会接收一个参数以表示写入的可序列化字节流的协议版本。

流协议版本如下:

  • ObjectStreamConstants.PROTOCOL_VERSION_1:表示初始流格式。
  • ObjectStreamConstants.PROTOCOL_VERSION_2:表示新的外部数据格式。基本数据以块数据模式写入,并以TC_ENDBLOCKDATA终止。

数据块边界已标准化。以数据块模式写入的基元数据被规范化为不超过1024字节块。此更改的好处是加强了 Stream 中序列化数据格式的规范。这种变化是完全前后兼容的。

JDK1.2默认为写入PROTOCOL_VERSION_2 JDK1.1默认为写入PROTOCOL_VERSION_1 JDK1.1.7及更高版本可以读取这两个版本 JDK1.1.7之前的版本只能读取PROTOCOL_VERSION_1

4、Stream 格式的语法

下表包含流格式的语法。非终结符号以斜体显示。终结符号拥有固定的宽度。非终结符号的定义之后带了一个。这个定义之后每一行会有一个或者多个替代符号。下表描述了符号:

Notation

Meaning

(datatype)

此令牌具有指定的数据类型,例如 byte

token[n]

令牌的预定义出现次数,即数组

x0001

用十六进制表示的文字值,十六进制数字的数量反映了值的大小

<xxx>

从 Stream 中读取的值,用于指示数组的长度。

注意,符号(utf)用于指定使用2字节长度信息写入的字符串,而(long utf)用于指定使用8字节长度信息写入的字符串。

a. 语法规则

序列化 Stream 由满足 Stream 规则的任何 Stream 表示【官方文档仅有字段值分类而无具体含义,这里的具体含义来自参考中的序列化草案】

stream:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
             **` magic` `version` `contents`**

  整个数据流的格式,直接分成三部分,magic 表示魔数STREAM_MAGIC标记,version 表示序列化的版本STREAM_VERSIONcontents表示最终生成的序列的内容;

contents:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`content`**
             **` contents content`**

  这一部分表示生成的二进制序列的内容部分,这些内容有可能是独立的内容【content】,也可能是多个内容的一个集合【contents】;

content:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
             **`object`**
             **` blockdata`**

  二进制序列独立的内容【content】有可能包含对象定义的数据【object】,也有可能包含数据块格式的数据【blockdata】,上边格式也有能blockdata在前,object在后;

object:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
             **` newObject`**
             **` newClass`**
             **`  newArray`**
             **` newString`**
             **`  newEnum`**
             **`  newClassDesc`**
             **`  prevObject`**
             **`  nullReference`**
             **`  exception`**
             ==`  TC_RESET`==

​ 该部分内容表示对象中包含的字节流数据,这部分数据中的元素相互间没有顺序,仅仅表示该对象中可能存在标记表示的数据;newObject表示新对象类型, newClass表示Class类型的对象,newArray表示数组对象,newString表示字符串对象,newEnum表示枚举常量,newClassDesc表示对象的类描述信息,preObject表示前边出现过的对象,nullReference表示空引用,exception表示异常对象,==TC_RESET==表示重置标记【固定值】。

newClass:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_CLASS`==  **`classDesc` `newHandle`**

  该部分内容表示一个新的Class类型的对象,==TC_CLASS==表示类型标记,classDesc表示类描述信息,newHandle表示新的引用;

classDesc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
             `  newClassDesc`
             ` nullReference`
             `  (ClassDesc)prevObject`      // 要求为ClassDesc类型的对象

  该部分表示一个对象的类描述符,newClassDesc表示新出现一个类描述符,nullReference表示空引用,prevObject表示前边出现过的对象;

superClassDesc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`classDesc`**    

  这部分表示父类的描述符信息,它的内容是一个classDesc,也就是上边类描述信息;

newClassDesc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_CLASSDESC`== **`className` `serialVersionUID` `newHandle` `classDescInfo`**
              ==`TC_PROXYCLASSDESC`== **`newHandle` `proxyClassDescInfo`**

​ 这个部分演示了类描述符中描述的两种类描述符信息:一般类描述信息,动态代理类描述信息,clsssName表示类名,serialVersionUID表示该类中定义的serialVersionUID对应的值,newHandle表示一个新的引用,classDescInfo表示类描述符本身的相关信息,proxyClassDescInfo表示动态代理类描述符本身相关的信息;

classDescInfo:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **` classDescFlags` `fields` `classAnnotation` `superClassDesc `**

​ 这一部分内容是详细的类描述信息,classDescFlags为类描述信息标记,fields表示类中所有字段的描述信息,classAnnotation表示和类相关的Annotation的描述信息,superClassDesc表示该类的父类的描述信息。

className:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        *(utf)*

  类全名,以UTF-8的格式保存的字符串对应的二进制序列,描述了当前对象的类全名;

serialVersionUID:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
         *(long)*

​ 对应类定义中的字段serialVersionUID的信息;

classDescFlags:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
          *(byte)*                  // 在终端符号和常量中的定义

​ 类描述符标记,一个字节的数据,用于定义终止符和常量;

proxyClassDescInfo:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
          *(int)<count> proxyInterfaceName[count] classAnnotation superClassDesc*

  动态代理类的相关描述信息,<count>表示该动态代理类实现的接口总数,类型为int类型。proxyInterfaceName[count]表示所有当前动态代理类实现的接口信息,classAnnotation表示该动态代理类对应的Annotation的描述信息,superClassDesc表示当前动态代理类的父类的类描述信息;

proxyInterfaceName:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
         *(utf)*

​ 动态代理类的代理接口的名称,一个UTF-8格式的字符串对应的二进制序列;

fields:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
         *(short)<count>  fieldDesc[count]*

<count>表示该类中的字段【成员属性】的总数,数据类型为short类型。fieldDesc[count]表示一个类中所有字段的详细描述信息,字段的数量和前边的count是一致的;

fieldDesc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`primitiveDesc`**

objectDesc

  这个标记表示字段的描述信息,字段描述信息包括部分信息内容,primitiveDesc表示基础类型数据的描述信息,objectDesc表示对象类型数据的描述信息;

primitiveDesc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`prim_typecode fieldName`**

  基础类型的字段的相关描述信息,prim_typecode表示字段的类型标识,字段类型标识表示当前字段的类型,fieldName表示字段的名称,为一个字段名称组成的字符串的二进制序列;

objectDesc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`obj_typecode` `fieldName` `className1`**

​ 对象类型的字段的描述信息,obj_typecode表示字段的类型标识,该标识描述了对象字段对应的类信息,fieldName表示字段的名称,为一个字段名称组成的字符串的二进制序列,className1表示该成员属性的类型签名;

fieldName:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
          *(utf)*

​ 表字段名称字符串,该字符串由二进制序列组成且经过了 UTF-8 编码

className1:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
          *(String)object*             // 包含字段类型的字符串,字段描述符格式

  该对象对应的类的类全名,为一个String类型的对象描述信息;

classAnnotation:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`endBlockData`**
              **`contents endBlockData`**      // annotateClass 编写的内容

​ 该对象所属类中的Annotation的描述信息,endBlockData为存储对象的数据块【Data-Block】的结束标记,为终止符,contents表示该类中多个内容的一个集合【contents】;

prim_typecode:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
             `B`       // byte
             `C`       // char
             `D`       // double
             `F`       // float
             `I`       // integer
             `J`       // long
             `S`       // short
             `Z`       // boolean

  基础类型的字段的类型标识,标识了字段所属的基础数据类型,其代码表示的类型含义如定义中的注释部分的内容;

obj_typecode:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              `[`       // array
              `L`       // object

  对象类型的字段的类型标识,标识了字段所属的对象类型,其代码表示类型含义如注释部分的内容;

newArray:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_ARRAY`== **`classDesc` `newHandle (int)<size> values[size]`**

​ 创建一个新的数组的描述符,==TC_ARRAY==表示接下来的序列是一个数组,它是数组序列的开始标记,classDesc是当前这个数组的类描述符,newHandle表示针对当前数组对象的引用,<size>表示该数组的长度,长度数字为int类型,values[size]表示当前数组每一个元素的值部分的内容;

newObject:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_OBJECT`==**` classDesc newHandle classdata[]`**      // 每个类的数据

​ 创建一个新的对象的描述符信息,==TC_OBJECT==表示接下来的序列是一个新对象,它是对象的开始标记,classDesc是当前这个对象的类描述符,newHandle表示针对当前对象的引用,classdata[]这个对象对应的每一个Class的相关数据信息;

classdata:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        **`nowrclass`**                     // SC_SERIALIZABLE & classDescFlag && !(SC_WRITE_METHOD & classDescFlags)
        **`wrclass objectAnnotation`** // SC_SERIALIZABLE &classDescFlag&&SC_WRITE_METHOD&classDescFlags 
        **` externalContents`**          // SC_EXTERNALIZABLE & classDescFlag && !(SC_BLOCKDATA  & classDescFlags
        **`objectAnnotation`**          // SC_EXTERNALIZABLE & classDescFlag&& SC_BLOCKDATA & classDescFlags

​ 这一部分数据描述的是类数据中所有内容,下边有针对各种不同的类数据相关说明;

nowrclass:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`values`**                    //  类描述符顺序的字段

  一个类中可序列化的字段的数据值,这些数据值的顺序遵循类描述符中定义的顺序;

wrclass:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`nowrclass`**

  这部分数据的内容和上述的nowrclass部分的内容是一样的,表一个类中可序列化的字段的数据值;

objectAnnotation:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`endBlockData`**
              **`contents endBlockData`**     // 由`writeObject`或`writeExternal PROTOCOL_VERSION_2`编写的内容。

  这部分数据的内容和classAnnotation数据结构是一致的;表该对象所属类中的Annotation的描述信息,endBlockData为存储对象的数据块【Data-Block】的结束标记,为终止符,contents表示该类中多个内容的一个集合【contents】;

blockdata:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`blockdatashort`**
              **`blockdatalong`**

  在Java序列化中,数据块存储分为种:一种是长度为short的默认数据块方式,另外一种是长度为int的数据块方式,这种方式可存储容量大的数据;

blockdatashort:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_BLOCKDATA`== **`(unsigned byte)<size> (byte)[size]`**

​ 描述了长度为short的默认数据块的结构;

blockdatalong:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==` TC_BLOCKDATALONG`== **` (int)<size> (byte)[size]`**

  描述了长度为int类型的数据块的结构;

endBlockData :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_ENDBLOCKDATA`==

  表示数据块的结束标记,一般用于描述当前的数据块结束了或者这个对象类型的描述符已经结束了;

externalContent: // 只能由readExternal解析

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
          *( bytes)*                // 原始数据
                `object`

  这个部分描述的是外部化的相关内容,(bytes)部分的数据只能被readExternal方法读取,而且里面一般包含的数据类型是基础类型数据,object表示对象数据类型;

externalContents: // 在PROTOCOL_VERSION_1中由writeExternal编写的外部内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
               **`externalContent`**        

externalContents externalContent

  这部分内容是上述的外部化内容的一个集合,一般这一部分只包含了使用writeExternal方法以PROTOCOL_VERSION_1的版本写入字节流的数据;

newString:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_STRING`== **`newHandle`** *(utf)*
              ==`TC_LONGSTRING`== **`newHandle`** *(long-utf)*

  表示一个字符串类型的数据,而字符串数据同样有种类型:STRINGLONGSTRING

newEnum:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_ENUM`== **`classDesc` `newHandle` `enumConstantName`**

​ 表示一个Enum类型的数据,==TC_ENUM==为枚举类型的标识,表示接下来的序列类型是枚举类型,classDesc为一个枚举类型的类描述符,newHandle为该枚举对象的引用,enumConstantName的值为调用枚举类型中的name()方法返回的枚举类型的值对应的字符串字面量;

enumConstantName:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              `(String)object`
    枚举常量的字符串名称字面量,本身为一个字符串;

prevObject

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_REFERENCE`== `(int)handle`

​ 表示已经写入到字节流中的对象的一个对象的引用,==TC_REFERENCE==是引用标识,表接下来的数据类型是Java引用类型。

nullReference

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_NULL`==

  就一个字节长度的数据,就表示null值,一般这个值表示的是对象的空引用;

exception:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              ==`TC_EXCEPTION`== **`reset` `(Throwable)object` ` reset `**

  针对异常信息的描述,==TC_EXCEPTION==为异常信息的标记,标识接下来的序列是一个异常对象;

magic:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              **`STREAM_MAGIC`**

​ 魔数;

version

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
              `STREAM_VERSION`

​ 序列化的版本信息,本文中使用的默认值是05

values: // 当前对象的ClassDec描述了大小和类型

  针对当前对象的classDesc对应的类描述信息提供描述类型的大小;

newHandle: // 序列中的下一个数字分配给被序列化或反序列化的对象

  序列中的下一个数值将赋值给一个可序列化或者可执行反序列化的对象引用;

reset: // 将丢弃已知对象集,以便异常的对象不会与以前发送的对象或异常之后可能发送的对象重叠

  一个已知对象的集合将会被放弃,重置该字节流;

b.终端符号和常数

java.io.ObjectStreamConstants中的以下符号定义了 stream 中预期的终端值和常量值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    final static short STREAM_MAGIC = (short)0xaced;
    final static short STREAM_VERSION = 5;
    final static byte TC_NULL = (byte)0x70;
    final static byte TC_REFERENCE = (byte)0x71;
    final static byte TC_CLASSDESC = (byte)0x72;
    final static byte TC_OBJECT = (byte)0x73;
    final static byte TC_STRING = (byte)0x74;
    final static byte TC_ARRAY = (byte)0x75;
    final static byte TC_CLASS = (byte)0x76;
    final static byte TC_BLOCKDATA = (byte)0x77;
    final static byte TC_ENDBLOCKDATA = (byte)0x78;
    final static byte TC_RESET = (byte)0x79;
    final static byte TC_BLOCKDATALONG = (byte)0x7A;
    final static byte TC_EXCEPTION = (byte)0x7B;
    final static byte TC_LONGSTRING = (byte) 0x7C;
    final static byte TC_PROXYCLASSDESC = (byte) 0x7D;
    final static byte TC_ENUM = (byte) 0x7E;
    final static  int   baseWireHandle = 0x7E0000;

标志字节 classDescFlags 可能包括以下值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    final static byte SC_WRITE_METHOD = 0x01; //if SC_SERIALIZABLE
    final static byte SC_BLOCK_DATA = 0x08;    //if SC_EXTERNALIZABLE
    final static byte SC_SERIALIZABLE = 0x02;
    final static byte SC_EXTERNALIZABLE = 0x04;
    final static byte SC_ENUM = 0x10;

如果写入流的可序列化类具有writeObject方法,并且若该方法已将其他数据写入 stream ,则会设置标志SC_WRITE_METHOD。在这种情况下,TC_ENDBLOCKDATA标记总是希望终止该类的数据。

如果使用SC_BLOCKDATAExternalizable类写入 stream,则设置标志SC_BLOCKDATA。默认情况下,在JDK 1.2中将Externalizable对象写入stream的协议。JDK1.1中写入STREAM_PROTOCOL_1

如果编写 stream 的类扩展了java.io.SERIALIZABLE而不是java.io.Externalizable,那么会设置标志 SC_SERIALIZABLE,读取 stream 的类也必须扩展java.io.SERIALIZABLE,并使用默认的序列化机制。

如果编写 stream 扩展java.io.EXTERNALIZABLE的类,读取数据的类也必须扩展EXTERNALIZABLE,并且如果使用其writeExternalreadExternal方法读取数据,那么会设置标记SC_EXTERNALIZABLE

如果写入 stream 的类是枚举类型,则会设置标志SC_ENUM。接收方的对应类也必须是枚举类型。

最后根据上述内容,可以总结得到下图:

5、参考

官方文档:https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html

Java序列化草案:https://blog.csdn.net/silentbalanceyh/article/details/8183849

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-06-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
【说站】mysql有哪些常见的约束
以上就是mysql常见约束的介绍,希望对大家有所帮助。更多mysql学习指路:MySQL
很酷的站长
2022/11/23
1.2K0
【说站】mysql有哪些常见的约束
MySQL基础之常见约束和标识列
-----: | :----------: | :------------------: | :----------: | | 主键 | √ | × | 至多有1个 | √,但不推荐 | | 唯一 | √ | √ | 可以有多个 | √,但不推荐 |
yuanshuai
2022/08/22
7060
SQL笔记(1)——MySQL创建数据库
其中,主键列指定了 PRIMARY KEY 约束,强制该列的值在表中唯一,并且使用 AUTO_INCREMENT 关键字,表示该列的值会自动递增生成。
MinChess
2023/04/22
3.3K0
SQL笔记(1)——MySQL创建数据库
MySQL 约束
为了保证数据的完整性,SQL 规范以约束的方式对表数据进行额外的条件限制。从以下四个方面考虑:
恋喵大鲤鱼
2023/10/12
5140
MySQL约束
约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性、唯一性。
阿年、嗯啊
2021/04/27
1.8K0
MySql基础之约束
给某个字段/某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默认值。
冬天vs不冷
2025/01/21
2070
MySql基础之约束
约束条件(constraint)「建议收藏」
约束条件也叫完整性约束条件,当对表中的数据做DML操作时会验证数据是否违反约束条件.如果违反了DML操作会失败.约束条件可以应用于表中的一列或几列,应用于整个表或几个表之间.
全栈程序员站长
2022/11/04
1.7K0
一篇文章带你彻底了解MySQL各种约束
MySQL约束 <1> 概念 是一种限制,它是对表的行和列的数据做出约束,确保表中数据的完整性和唯一性。 <2> 使用场景 创建表的时候,添加约束 <3> 分类 default: 默认约束, 域完整性 not null: 非空约束,域完整性 unique: 唯一约束,实体完整性 primary key: 主键约束,实体完整性 foreign key: 外键约束,参照完整性 check: 检查约束(MySQL不支持),域完整性 auto_increment: 自增长约束 unsigned: 无符号约束 zer
ruochen
2021/02/14
1K0
一篇文章带你彻底了解MySQL各种约束
不是吧,阿Sir,MySQL约束你竟然还不懂!
符号规定:下面展示一些定义的时候,为简便理解,使用中文配合符号表述(会有具体举例,不用担心理解不了)
BWH_Steven
2020/06/22
5880
不是吧,阿Sir,MySQL约束你竟然还不懂!
⑦【MySQL】什么是约束?如何使用约束条件?主键、自增、外键、非空....
NO ACTION:在父表进行更新/删除时,首先检查记录是否存在外键,存在则不允许删除/更新。(与RESTRICT行为一致)
.29.
2023/11/15
6700
⑦【MySQL】什么是约束?如何使用约束条件?主键、自增、外键、非空....
【MySQL】04_约束
为了保证数据的完整性,SQL规范以约束的方式对表数据进行额外的条件限制。从以下四个方面考虑:
鸡先生
2022/10/29
2.5K0
【MySQL】04_约束
MySQL约束
在数据库中对表中的数据进行限制,保证数据的正确性、有效性和完整性。一个表如果添加了约束,不正确的数据将无法插入到表中。约束在创建表的时候添加比较合适。
星哥玩云
2022/09/15
6.8K0
MySQL约束
MySQL 约束
  非空约束(NOT NULL)指字段的值不能为空。对于使用了非空约束的字段,用户在添加数据时没有指定值,数据库系统就会报错。可以通过 CREATE TABLE 或 ALTER TABLE 语句实现非空。在表中某个列的定义后加上关键字 NOT NULL 作为限定词,来约束该列的取值不能为空。
Demo_Null
2020/09/28
3.2K0
MySQL 约束
MySQL 约束介绍
给某个字段/某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默 认值。
久绊A
2023/04/10
1.7K0
第13章_约束
数据完整性(Data Integrity)是指数据的精确性(Accuracy)和可靠性(Reliability)。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而提出的。
程序员Leo
2023/08/07
5190
第13章_约束
MySQL数据库,从入门到精通:第十三篇——MySQL数据表约束详解
在MySQL数据库中,约束是一种对数据表中数据进行限制和检查的方法,可以保证数据表中数据的完整性和一致性。本文将深入剖析MySQL中的各种约束,包括非空约束、唯一性约束、主键约束、自增列、外键约束、默认值约束以及CHECK约束等等,同时结合开发场景给出约束使用和实践的技巧和方法,帮助读者更好地掌握MySQL中数据表相关操作的技巧和方法。
默 语
2024/11/20
3790
MySQL数据库,从入门到精通:第十三篇——MySQL数据表约束详解
6-数据类型与常见约束
添加外键时在最后加上ON UPDATE CASCADE , ONDELETE CASCADE
Ywrby
2022/10/27
7300
【MySQL】008-表的约束
说明链接:https://blog.csdn.net/u014743697/article/details/54136092
訾博ZiBo
2025/01/06
1140
Mysql基础7-约束
  需求1:创建一个表id、name、age、address、stu_num五个字段。
Se7eN_HOU
2023/07/24
3940
Mysql基础7-约束
【MySql】表的约束
真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是email,要求是唯一的。表中一定要有各种约束,通过约束,让我们未来插入数据库表中的数据是符合预期的。约束的本质是通过技术收到逼迫程序员插入正确的数据,反过来,站在mysql的视角,凡是插入进来的数据,都是符合数据约束的。约束的最终目标:保证数据的完整性和可预期性所以需要更多的约束。 表的约束很多,这里主要介绍如下几个: null/not null,default, comment, zerofill,primarykey,auto_increment,unique key 。
平凡的人1
2023/10/15
4080
【MySql】表的约束
相关推荐
【说站】mysql有哪些常见的约束
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档