与 CHAR 相比,VARCHAR 值存储为 1 字节或 2 字节 长度前缀加数据。长度前缀表示的数量 值中的字节。如果值不需要,则列使用一个长度字节 超过 255 个字节,如果值可能需要超过两个长度字节 255 字节。
让我们在 EC 商店案例中考虑这个问题。 以下是如何定义产品(项目)实体(即使没有学习 TypeScript,很可能你也能理解这段代码):
import { FIXED_CHARACTERS_COUNT_IN_UNIVERSAL_UNIQUE_ID__VERSION_4 } from "fundamental-constants";
type Product = {
readonly ID: Product.ID;
label: string;
price__dollars__withoutTaxes: number;
};
namespace Product {
export type ID = string;
export namespace ID {
export const TYPE: StringConstructor = String;
export const REQUIRED: boolean = true;
export const FIXED_CHARACTERS_COUNT: number = FIXED_CHARACTERS_COUNT_IN_UNIVERSAL_UNIQUE_ID__VERSION_4;
}
export namespace Label {
export const TYPE: StringConstructor = String;
export const REQUIRED: boolean = true;
export const MINIMAL_CHARACTERS_COUNT: number = 2;
export const MAXIMAL_CHARACTERS_COUNT: number = 127;
}
export namespace Price__Dollars__WihtoutTaxes {
export const TYPE: NumberConstructor = Number;
export const REQUIRED: boolean = true;
export const MINIMAL_VALUE: number = 0;
}
}
无论是前端输入的数据验证还是后端请求数据验证(与数据库定义相同)都必须遵守上述业务规则。特别是,产品标签必须包含 2 至 127 个字符:
假设上述值从不在前端和后端直接输入两次 - 相反,它被引用:
<!-- BAD: the maximal characters count has been HARDCODED -->
<label for"PRODUCT_LABEL--INPUT">Please input 2-127 characters.</label>
<input type="text" maxlen="127" id="PRODUCT_LABEL--INPUT" />
<!-- GOOD: the maximal characters count has been referred (no matter what is the template engine)-->
<label for"PRODUCT_LABEL--INPUT">Please input {{ Product.Label.MINIMAL_CHARACTERS_COUNT }}-{{ Product.Label.MAXIMAL_CHARACTERS_COUNT }} characters.</label>
<input type="text" maxlen="{{ Product.Label.MAXIMAL_CHARACTERS_COUNT }}" id="PRODUCT_LABEL--INPUT" />
定义数据库时(现在重要的是,具体如何 - 通过原始 SQL 请求、GUI 工具或 ORM),我们还将为
label
表的 Products
列设置类似 VARCHAR 的类型,最大长度为 127 个字符(再次,参考 Product.Label.MAXIMAL_CHARACTERS_COUNT
而不是直接输入 127
值)。
然后,假设卖家输入的产品标签几乎包含127个字符,但包括2个字节的字符。前端的验证不会像后端请求数据的验证一样威胁到输入的值。但是,一旦服务器应用程序尝试将添加(或更新)的产品保存到表中,我们就会收到有关
label
的值超出最大长度的异常!
问题:
Product.Label.MAXIMAL_CHARACTERS_COUNT
中必须设置哪个值?
(让我重复一遍,这个值是从前端和后端referred)。
VARCHAR(L)
列的长度参数指定可以保存多少个字符。这不包括 MySQL 数据库在表中存储值所需的额外字节数。引用的文档仅指定在 VARCHAR
列中存储值还需要多少字节。请参阅以下示例:
mysql> CREATE TABLE Dummy (Label VARCHAR(10));
Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO Dummy(Label) VALUES('12345');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO Dummy(Label) VALUES('123456789');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO Dummy(Label) VALUES('1234567890');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO Dummy(Label) VALUES('12345678901');
ERROR 1406 (22001): Data too long for column 'Label' at row 1
如您所见,可以将字符串
123456789
(长度为 9)保存在 VARCHAR(10)
列中,因为 9<=10. It will however require additional 1 byte to save the data.
当您尝试将字符串
1234567890
(长度为 10)保存在 VARCHAR(10)
列中时,它从 10 开始也能正常工作<=10. Again, it needs additional 1 byte for the length of the string.
无法保存值
12345678901
,因为该字符串的长度为 11,并且太大而无法保存在 VARCHAR(10)
类型的列中。
因此,当您只想保存最大长度为127的标签时,请使用
VARCHAR(127)
。用户将能够使用长度不超过 127 的字符串来保存值,但不能使用更大的字符串。
请记住,数据存储为字符,而不是字节。这意味着值
äöüäöüäöü
(九个元音变音)可以保存在 VARCHAR(10)
列中,因为 9<=10, even though 18+1 bytes are needed to save the data in the table. See the following SELECT
语句:
mysql> SELECT Label, LENGTH(Label) FROM Dummy;
+--------------------+---------------+
| Label | LENGTH(Label) |
+--------------------+---------------+
| 12345 | 5 |
| 123456789 | 9 |
| 1234567890 | 10 |
| äöüäöü | 12 |
| äöüäöüöäü | 18 |
+--------------------+---------------+
5 rows in set (0.00 sec)
mysql> EXPLAIN Dummy;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| Label | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
1 row in set (0.00 sec)