当前位置:   article > 正文

MySQL的表约束与数据完整性:非空(NOT NULL)、唯一(UNIQUE)、默认值(DEFAULT)、自增(AUTO_INCREMENT)_not null auto increment primary

not null auto increment primary
  • 数据完整性可以参阅另一篇文章:https://blog.csdn.net/qq_41453285/article/details/104142402
  • 概念:指数据能正确反映实际情况
  • 分类:
    • 实体完整性:标识符或主键完整性(主键、唯一值约束)
    • 域完整性:限制数据类型、格式、取值范围(检查、默认值、外键约束)
    • 引用完整性:输入或删除时,不能存在引用不存在的值(外键约束)
    • 自定义完整性:自定义规则
  • 约束:限制表数据的一个条件。
  • 约束写法:
    • 行级约束:定义在每个字段后(字段基础上)
    • 表级约束:定义在表后(表基础上)

一、非空约束(NOT NULL)

  • 概念:非空约束指定字段的值不能为空,如果用户添加数据时没有指定值,系统就会报错
  • 在设置表时,也可以指定一个列可以为空(null),但是NULL是默认设置,所以可以默认不书写
  • NULL与空串的区别:
    • NULL值是没有值,它不是空串
    • 如果是空串''(两个单引号,其中没有任何字符),这是一个有效的值
  • 创建表时指定非空约束:
  1. create  table  表名(
  2. 字段 数据类型 not null,
  3. );
  • 在已有表上设置非空约束:
alter table 表名 modify column 字段 数据类型 not null;
  • 删除非空约束:
alter table 表名 modify column 字段 数据类型;

二、唯一约束(UNIQUE)

  • 唯一约束要求该列唯一;允许为空,但是只能出现一个空值。
  • 可以设定一列或复合为唯一约束。
  • 创建表时指定唯一约束:
  1. create table 表名(
  2. 字段 数据类型 UNIQUE,
  3. );
  • 创建表时指定复合唯一约束(表级约束):
  1. create  table  表名 (
  2. 字段1  数据类型,
  3. 字段2  数据类型,
  4. [constraint 唯一约束名] unique(字段1,字段2)
  5. );
  • 在已有表上指定一/多列为唯一约束:
alter  table  表名  add  [constraint  唯一约束名]  unique(字段,字段2....);
  • 删除列的唯一约束:通过约束名删除
alter  table 表名  drop  唯一约束名;

三、默认值约束(DEFAULT)

  • 概念与特点:
    • 为字段指定默认值。
    • 当插入一条记录时没有为此字段赋值,则使用默认值。若指定值,默认值被替换。
  • 使用默认值而不是NULL值:许多开发人员使用默认值而不是NULL列,特别是对用于计算或数据分组的列更是如此。
  • 除了BLOB与TEXT类型、空间类型,或者具有AUTO_INCREMENT属性的列以外,你还可以指定DEFAULT def_value子句,以此来表明:当在创建新的行时 ,如果没有显式地指定某个值 , 那么该列将被赋值为默认值def_value。
  • 除了TIMESTAMP列和DATETIME列有限制以外,这里的默认值def_value必须是一个常量,它不能为表达式/函数等,也不能引用其他列。

DEFAULT与NULL

  • 如果某个列定义没有显式包含DEFAULT子句,并且该列允许为NULL值,那么其默认值为 NULL。
  • 否则 ,如果该列不允许为NULL值,并且在定义里没有显式包含DEFAULT子句,那么在创建它时也不会带有DEFAULT子句。也就是说 ,它没有默认值。在往表里插入新的行时 ,如果没有为列指定具体值,这会影响MySQL对列的处理。处理规则如下:
    • 如果没有启用SQL的严格模式,那么该列将被设置成其数据类型的隐含默认值。(各种隐含默认值将在稍后讨论)。
    • 在启用SQL的严格模式之后:
      • 如果表是事务性的,就会出现错误。这条语句会中止执行,然后回滚。
      • 对于非事务性的表:
        • 如果这行是该语句插入的第一个行,那么会出现一个错误,并且该语句会中止执行。
        • 如果插入的不是第一行,那么你可以选择让语句中止执行,或者选择把这列设 置为它的隐含默认值,同时发一条警告消息。
      • 具体的选择需要参考哪一种严格模式在起作用。更多相关细节请参考https://dongshao.blog.csdn.net/article/details/88055683。更多与事务有关的信息请参考https://dongshao.blog.csdn.net/article/details/104055508
  • 列的隐含默认值取决于它的数据类型:
    • 对于数字列(不包括那些具有AUTO_INCREMENT属性的列),其默认值为0。对于AUTO_INCREMENT列,其默认值是下一个列序号
    • 对于大多数时态类型列,其默认值为该类型的“零”值 (如DATE类型的“零”值是'0000-00-00')。对于TIMESTAMP列 (以及MySQL 5.6里的DATETIME列),其自动初始化规则比较特殊。更多相关信息请参考https://dongshao.blog.csdn.net/article/details/87366045
    • 对于字符串类型(不包括ENUM类型)列,其默认值为空串。对于ENUM列,其默认值为枚举集里的第一个元素。对于SET列,如果不允许包含NULL值 ,那么默认值将是一个空集,不过它等价于空串。
  • 使用SHOW CREATE TABLE tbl_name语句,可以査看到表里的哪些列带有DEFAULT子句,以及它们的默认值是什么。
  • 创建表时添加默认值:
  1. create  table  表名(
  2. 字段 数据类型 DEFAULT 默认值
  3. );
  • 在已有表上设置默认值约束:
alter  table  表名  modify column 字段  数据类型  default  默认值;
  • 删除默认值:赋值为NULL即可
alter  table  表名  modify  column 字段  数据类型  default  null;

四、处理序列(AUTO_INCREMENT)

  • 达到标识的目的,许多应用都需要生成唯一编号,如成员编号 、样品编号或批号、顾客ID、bug报告或故障报告表标签等。
  • MySQL提供唯一编号的机制是使用MySQL提供唯一编号的机制是使用AUTO_INCREMENT列属 性——它会自动生成序列编号。不过,MySQL所支持的那些存储引擎,处理AUTO_INCREMENT列的方式有所不同
  • 下面的讨论将描述:在一般情况下,AUTO_INCREMENT列是如何工作的,对于特定的存储引擎,它又是如何工作的。有了这些知识 ,你就可以高效地使用它们 ,而不会遭遇那些让人感到意外的陷讲 。下面还会对“不使用AUTO_INCREMENT列的情况下,如何生成序列”进行讨论。

五、通用的AUTO_INCREMENT属性

  • AUTO_INCREMENT的定义规则:
    • 每个表只能有一个列具有AUTO_INCREMENT属性,并且它应该为整数数据类型。(AUTO_INCREMENT也支持浮点类型,但很少那样使用)。
    • 列必须建立索引。最常见的情况是使用PRIMARY KEY或UNIQUE索引,但是也允许使用不唯一的索引。
    • 列必须拥有NOT NULL约束条件。即使没有显式地这样声明,MySQL也会自动把列设置为 NOT NULL

AUTO_INCREMENT列行为

  • 把NULL值插入AUTO_INCREMENT列将引发 MySQL自动生成下一个序列编号,并把它插入列。
  • AUTO_INCREMENT序列通常是从1开 始,并依次单步递增,因此连续插入表的各行的序号 值将为1、2、3,如此等等。
  • 在某些场合,根据所用存储引擎的不同,可以显式地设置或重置下一个序号,或者重复使用已从序列顶端删除的那些序号值。(例如,如果插入数据时指定了值,则字段的默认值改变,下一次插入时将为本次改变值的+1)。

LAST_INSERT_ID()函数

  • 要获得最近生成的序号值,可以调用LAST_INSERT_ID()函数 。这样,即使在你根本不知道AUTO_INCREMENT值到底是多少的时候,也可以在后续的语句里引用它。
  • 如果在当前会话里,还没有生成过AUTO_INCREMENT值 ,那么LAST_INSERT_ID()将返回0。
SELECT LAST_INSERT_ID();
  • LAST_INSERT_ID()只会依赖于与服务器的当前会话连接所生成的AUTO_INCREMENT值。
  • 你可以生成一个序号,接着在同一个会话连接里调用LAST_INSERT_ID()来检索它。即使其他客户在此期间生成了它们自己的序号值,也不会出现任何问题。
  • 一次插入多个行的INSERT语句,将生成多个AUTO_INCREMENT值,LAST_INSERT_ID()只会返回其中的第一个
  • 如果使用INSERT DELAYED,那么要直到实际插入行时,才会生成AUTO_INCREMENT值 。这时,就不能依靠LAST_INSERT_ID()来返回序号值了。
  • 在插入一行时,如果不为AUTO_INCREMENT列指定值 ,则等同于向该列插入一个NULL值 。如ai_col是一个 AUTO_INCREMENT列,那么下面这两条语句就是等效的:
  1. INSERT INTO t (ai_col,name) VALUES(NULL, 'abc');
  2. INSERT INTO t (name) VALUES('abc');
  • 默认情况下,把0插入AUTO_INCREMENT列,等效于插入NULL值。如果启用了SQL的 NO_AUTO_VALUE_ON_ZERO模式,那么插入0则会导致存储值为0,而非下一个序号值 。
  • 如果要插入一行,并为某个拥有唯一索引的AUTO_INCREMENT列指定一个既不为NULL,也不为0的值,那么将发生这样两种情况中的某一种:
    • 如果已存在一行使用该值的记录,那么将会发生键重复错误
    • 否则,这行会被正常插入,而那个AUTO_INCREMENT列会被设置为那个给定值。如果该值大于当前的下一个序号值 ,那么这个序列将被重置,对于随后的行,所使用的编号会继续由该值开始生成。换句话说 ,即可以插入一行,让其序号值大于当前计数 器值 ,以此达到增大计数器的目的。
  • 对于某些存储引擎,从序列顶端删除的值可以被重用
    • 如果把包含最大AUTO_INCREMENT列值的那行删除,那么在下次生成新值时可以重用这个最大值。
    • 如果把表里的所有记录都删除,那么所有值都可以重用,并且这个序列会重新从1开 始。
  • 如果使用UPDATE命令把AUTO_INCREMENT列的值设置成某个正被其他行使用的值,并且这个列拥有唯一索引,那么会出现一个键重复错误。如果把这个列设置成某个大于所有已有列值的编号值 ,那么对于随后的行,这个序列从那个值开始继续生成下一个编号。 如果 把该列更新为0,那么它会被设置为0(不管是否启用了NO_AUTO_VALUE_ON_ZERO都一样)。
  • 如果根据AUTO_INCREMENT列的值 ,使用REPLACE来更新行,那么这个行的AUTO_INCREMENT值将保持不变。如果择据其他具有PRIMARY KEY或UNIQUE索引的列 的值,使用REPLACE命令来更新行,那么当你把AUTO_INCREMENT列设置为NULL,或者把它设置为0,而且没有启用NO_AUTO_VALUE_ON_ZERO时,该列的值将被更新为一个新的序号值

六、存储引擎特有的AUTO_INCREMENT属性

  • 刚才介绍的通用AUTO_INCREMENT特征,是理解各种存储引擎特有序列行为的基础。绝大多数 引擎实现的行为与上面的描述大体是一致的。MylSAM为序列处理提供了最大的灵活性,因此这 里的讨论便由该引擎开始。

MyISAM

  • MylSAM存储引擎拥有以下AUTO_INCREMENT特征:
    • MylSAM表里的序列一般是单调的。在一个自动生成的序列里,这些值都是严格递增的;并且在行被删除之后,不会被重用。如果最大值是143,而你删除了包含这个值的行,那么MySQL生成的下一个值仍然是144。不过,这种行为存在以下两种例外情况 :
      • 如果使用TRUNCATE TABLE清空了表,那么计数器将被重置为从1开 始。
      • 如果在表里使用了复合索引来生成多个序列,那么从序列顶 端删除的那些值将 被重用 。 (此项技术随后将被讨论到)。
    • MylSAM序列将默认从1开 始,不过你可以在CREATETABLE语句里,通过AUTO_INCREMENT=n选项显式地指定初始值 。下面这个示例会创建一个MylSAM表, 其中带有一个名为seq的AUTO_INCREMENT列,其起始值为1000000:CREATE TABLE mytbl(...)ENGINE=MYISAM AUTO_INCREMENT=1000000;
    • ALTER TABLE:
      • 可以使用ALTER TABLE来更改某个已有MylSAM表的当前序列计数器。例如,序列的当 前编号为1000,那么下面这条语句将使下一个生成的编号值变为2000:ALTER TABLE mytbl AUTO_INCREMENT=2000;
      • 如果想要重用那些从序列顶端删除了的值,也可以用ALTER TABLE语句来设置。把编号计数器设置到最低,使得下一个编号只比当前最大序号值多1:ALTER TABLE mytbl AUTO_INCREMENT=1;
      • 不能使用AUTO_INCREMENT选项来把当前计数值设置得比表里当前的最大计数值还小。例如,如果某个AUTO_INCREMENT列包含的值为1〜10,那么使用AUTO_INCREMENT = 5来设置这个计数器,得到的下一个自动值仍然为11,而非5。
  • MylSAM存储引擎支持在同一个表里使用复合(多列)索引,以创建多个相互独立的序列。
  • 为利用这个特性,为表创建一个由多列组成的KRIMARYKEY或UNIQUE索引,并把包含 AUTO_INCREMENT的那个列作为其中的最后一个。对于该索引最左边的列构成的每一个 相异键, AUTO_INCREMENT列将生成一组彼此互不干扰的序列值
  • 例如,有一个名为bugs的表,你需要用它来同时记录多个软件项目的bug报告,该表的定义如下:
    • 其中,proj_name列用于标识项目名,description列用于存放bug描述。
    • bug_id列是一个 AUTO_INCREMENT列,通过创建一个与proj_name列相关联的索引,可以为各个项目分别生成一个互不干扰的序列编号。
  1. CREATE TABLE bugs
  2. (
  3. proj_name VARCHAR(20) NOT NULL,
  4. bug_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  5. description VARCHAR(100),
  6. PRIMARY KEY (proj_name, bug_id)
  7. )ENGINE=MYISAM;

  • 假设,需要把下面几行输到表里,记录SuperBrowser项目的3个bug,以及SpamSquisher项目的2个bug:
  1. INSERT INTO bugs (proj_name,description)
  2. VALUES('SuperBrowser','crashes when displaying complex tables');
  3. INSERT INTO bugs (proj_name,description)
  4. VALUES('SuperBrowser','image scaling does not work');
  5. INSERT INTO bugs (proj_name,description)
  6. VALUES('SpamSquisher','fails to block known blacklisted domains');
  7. INSERT INTO bugs (proj_name,description)
  8. VALUES('SpamSquisher','fails to respect whitelist addresses');
  9. INSERT INTO bugs (proj_name,description)
  10. VALUES('SpamSquisher','background patterns not displayed');

  • 表的最终内容如下所示:
SELECT * FROM bugs ORDER BY proj_name,bug_id;

  • 这个表为每一个项目的bug_id值进行了单独的编号,整个过程与这些项目的行输入顺序毫无关系。在输入另一个项目的行之前,你不用先全部输入某个项目的所有行。
  • 如果使用复合索引来创建多个序列,那么从各个序列顶端删除的值都可以被重用。这 一点 与MylSAM表的不重用序号值的行为有所不同。

InnoDB

  • 在CREATE TABLE语句里,可以使用AUTO_INCREMENT=n表选项来设置初始序列值,并 且在表创建之后,还可以使用ALTER TABLE来进行更改。(参考上面MyISAM语法)
  • 从序列顶端删除的值通常不能再重用
    • 不过,如果使用TRUNCA TETABLE清空表,那么序列将被重置,并重新从1开始编号。
    • 此外,在满足后面几个条件时也可以重用:
      • 首先,在首次为AUTO_INCREMENT列生成序号值时,InnoDB会把列的当前最大值加上1,得到的结果作为新生成的序号值 (如果表此前为空,那么新的序号值为1)。
      • 其次,为满足生成后续序号值的需要,InnoDB是在内存里维护这个计数器——它并未存储在表内部。这意味着,如果从这个序列的顶端删除了某些值,然后又重启 了服务器,那么这些删除的值将会被重用。重启服务器还将取消在CREATE TABLE或ALTER TABLE语句里使用AUTO_INCREMENT表选项所带来的效果。
  • 如果生成AUTO_INCREMENT值的事务被回滚,那么在序列里可能会出现断裂
  • 在表里,不能使用复合索引生成多个独立的序列。

MEMORY

  • 在CREATE TABLE语句里,可以使用AUTO_INCREMENT=n表选项来设置初始序列值,并 且在表创建之后,还可以使用ALTER TABLE来进行更改。(参考上面MyISAM语法)
  • 从序列顶端删除的值通常不能再重用。不过,如果使用TRUNCA TETABLE清空表,那么序列将被重置,并重新从1开始编号。
  • 在表里,不能使用复合索引生成多个独立的序列。

七、使用AUTO_INCREMENT需要考虑的问题

  • AUTO_INCREMENT机制的主要用途是生成一个正整数序列。AUTO_INCREMENT列不支持使用非正数。因此,我们还可以把AUTO_INCREMENT列定义为UNSIGNED类型。对于整型列,使用UNSIGNED还有一个好处:在达到该数据类型的范围上限前,可以获得两倍的序列编号
  • 把AUTO_INCREMENT添加到列的定义里,并不能得到无穷尽的序列编号。AUTO_INCREMENT序列总是会受到底层数据类型的取值范围的约束。例如,如果你使用的是一个TINYINT列,那么 序列编号的最大值即为127。一旦达到这个上限,应用程序便会因“键重复”错误而失败。如果使用的是TINYINT UNSIGNED,那么序列编号的上限会扩充到255,不过它还是很有限。
  • 使用TRUNCATE TABLE语句来清除某个表的内容,可以把该表的计数序列重置为重新从1开始。即使对于那些通常不会重用AUTO_INCREMENT值的存储引擎,也是如此。之所以会重置序列,是因为MySQL需要对整表的删除操作进行优化。只要有可能,它会快速丢弃全部的行和索引,并 且从头开始重建该表,而不是一次删除一行。这样做将导致序列编号信息出现丢失。如果想在删 除所有行的同时把序列信息保留下来,那么可以使用带有一个永远为真的WHERE子句的DELETE语句来阻止这个优化操作的执行。该语句会迫使MySQL针对每行计算一次条件,然后单独地删除每行:
DELETE FROM tbl_name WHERE TRUE;

八、AUTO_INCREMENT列的使用语法

  • 建表时创建自增列:
  1. create table 表名(
  2. 字段 数据类型 PRIMARY KEY AUTO_INCREMENT
  3. );
  • 在已有表上指定自增列:
  1. # 如果表已经设置了主键或索引
  2. ALTER TABLE 表名 MODIFY COLUMN 字段 数据类型 AUTO_INCREMENT;
  3. # 如果表没有设置主键或索引
  4. ALTER TABLE 表名 MODIFY COLUMN 字段 数据类型 PRIMARY KEY AUTO_INCREMENT;

重置已有列的序列编号

  • 如果表已经有了一个AUTO_INCREMENT列,但是你想要对其进行重新编号,以便消除因删除行而在序列里产生的断裂。实现这一目标的最简单办法是:先删除该列,然后再重新添加它。 当MySQL添加列时,会自动分配新的序列号。
  • 假设,有这样一个表t,其中的i为一个AUTO_INCREMENT列:
  1. CREATE TABLE t
  2. (
  3. c CHAR(10),
  4. i INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY
  5. );
  6. INSERT INTO t(c) VALUES('a'),('b'),('c'),('d'),('e'),('f'),('g'),('h'),('i'),('j'),('k');
  7. DELETE FROM t WHERE c IN('a','d','f','g','i');
  8. SELECT * FROM t;

  • 下面的ALTER TABLE语句将依次删除列,再重加它,重回的过程中会对列重新编号:
  1. ALTER TABLE t DROP PRIMARY KEY, DROP i, ADD i INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,AUTO_INCREMENT = 1;
  2. SELECT * FROM t;

  • AUTO_INCREMENT=1子句将把序列的起始编号重置为1对于MylSAM、MEMORY或 InnoDB表,可以把序列的起始编号设置为不等于1的其他数。对于其他的存储引擎,则可以忽略AUTO_INCREMENT子句,因为它们不允许使用这样的方式设定序列的初始值。这个序列将从1开始编号。
  • 虽然可以轻易地重新设置列的编号,但是“要怎么才能做到呢?”这个问题仍然很常见,而且通常没有必要这么做。MySQL并不会在意序列里是否存在有断裂,并且在重置序列编号后 也不会获得任何性能上的提高。此外,如果在另一个表里有行引用了AUTO_INCREMENT列里的值,那么调整该列的编号将破坏这两个表之间的对应关系。

九、在无AUTO_INCREMENT的情况下生成序列

  • MySQL支持一种生成序列编号的办法,它根本不需要使用AUTO_INCREMENT列。事实上,它 使用的是LAST_INSERT_ID()函数另一种带参数的形式。如果在插入或修改一个列时使用了LAST_INSERT_ID(expr)函数,那么下次不带参数调用LAST_INSERT_ID()时,它会返回表达式的值。换句话说,MySQL会把表达式expr当作是一个新生成的AOTO_INCREMENT值,因此,你可以先创建一个序列编号,然后在随后的会话中检索它,同时不用担心这个编号值会受到其他客户端程序活动的影响 。

这种策略的一种用途是,创建一个只有一个行的表,其中包含一个在每次需要该序列里下一个值 时都会进行更新的值。例如,可以像下面这样创建和初始化这个表:

  1. CREATE TABLE seq_table (seq INT UNSIGNED NOT NULL);
  2. INSERT INTO seq_table VALUES(0);

 

  • 上面这些语句会创建一个只有一个行的seq_table表,其中seq的值为0。为生成下一个序列编号 ,并对它进行检索,可以这样做:
  1. UPDATE seq_table SET seq=LAST_INSERT_ID(seq+1);
  2. SELECT LAST_INSERT_ID();

  • 上面的UPDATE语句将检索seq列的当前值,并把它加上1,从而产生该序列的下一个编号。利用LAST_INSERT_ID(seq+1)生成的新编号值,与AUTO_INCREMENT值很相像,因此可以通 过不带参数调用LAST_INSERT_ID()的方式来检索它。LAST_INSERT_ID()函数是客户端专用的,因此即使在UPDATE和SELECT两个操作之间的时间间隔里,其他客户端程序又生成多个序列编号,你也会检索到正确值。
  • 利用这种方法,可以生成步长不为1(甚至可以为负值)的序列编号。例如,反复执行下面这条语句,将生成一个步长为100的序列:
UPDATE seq_table SET seq=LAST_INSERT_ID(seq+100);
  • 反复执行下面这条语句将生成一个递减序列:
UPDATE seq_table SET seq=LAST_INSERT_ID(seq-1);
  • 你也可以生成一个从任意值开始编号的序列,只要给seq列设置一个合适的初始值就行。
  • 前面的讨论描述了如何利用一个只包含一行的表来建立一个计数器。如果需要多个计数器,则 可以这样做:首先给这个表增加一列,用作计数器的标识符,然后在这个表里为每个计数器单独增加一行
  • 假设,你有一个网站,想要实现“本网页已被访问过n次”的页计数器。为此,创建一个具有两个列的表:一列用于保存计数器的唯一标识,而另一列则用于保存计数器的当前值。你仍可以使用LAST_INSERTED_ID()函数 ,但需要根据计数器的名字来确定它应该应用于哪一行。例如,可以用下面的语句来创建这样一个表:
  1. CREATE TABLE counter
  2. (
  3. name VARCHAR(255) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
  4. value INT UNSIGNED,
  5. PRIMARY KEY(name)
  6. );

  • 其中,name列是一个字符串,因此你可以把计数器命名为你想要的任何名字。同时,为了避免计数器的名字出现重复,它还被定义成了PRIMARY KEY。这里假定使用这个表的应用程序,对它们所使用的名字有所了解。就Web计数器而言,可以使用每个页面在文档树里的路径名作为计器名,以此保证记数器名的唯一性。name列的排序规则是区分大小写的,所以路径名的值也 是区分大小写的。如果你的系统不区分路径名的大小写,则需要使用不区分大小写的排序规则 。
  • 在使用counter表时,INSERT ... ON DUPLICATE KEY UPDATE语句会非常有用,因为它既可以为一个未曾统计过的页面插入一个新行,也可以更新已有页面的计数值。此外,通过使用LAST_INSERT_ID(expr)函数来生成计数值 ,你还可以在更新当前计数器后,轻易地将其值检索出来。例如,为了初始化或递增网站主页的计数器,然后检索计数器显示结果,可以像下面这样做:
  1. INSERT INTO counter(name,value)
  2. VALUES('index.html',LAST_INSERT_ID(1))
  3. ON DUPLICATE KEY UPDATE value=LAST_INSERT_ID(value+1);
  4. SELECT LAST_INSERT_ID();

  • 在不使用LAST_INSERT_ID()函数的情况下,另一种递增已有页面计数器的方法是:
  1. UPDATE counter SET value = value+1 WHERE name='index.html';
  2. SELECT value FROM counter WHERE name='index.html';

  • 不过 ,在执行UPDATE语句之后,且在执行SELECT语句之前,如果有另一个客户端递增了这个计数器,那么这种方法就无法正确地工作
    • 可以通过LOCK TABLE和UNLOCK TABLE把这两条语句围起来,解决此问题。或者,选用支持事务处理的存储引擎来创建这个表,并且在一个事务里更新这个表。
    • 上面两种办法都可以在你使用这个计数器时,阻断其他客户端,但是使用LAST_INSERT_ID()函数可以更容易地完成这件事情。因为计数器的值是客户端专用的,所以你总是能获得你刚插入的那个值 ,而不会获得来自其他客户端插入的值;并且,你不用为了达到排斥其他客户端的目的,而使用表锁定或事务来把代码弄得很复杂 。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/297128
推荐阅读
相关标签
  

闽ICP备14008679号