如何使用 MySQL 创建两个自增列?

How to create two auto increment columns using MySQL?

databaseChangeLog:
  - changeSet:
      id: ...
      author: ...
      preConditions:
        - onError: MARK_RAN
        - not:
            - tableExists:
                tableName: ORDERS
      changes:
        - createTable:
            tableName: ORDERS
            columns:
              - column:
                  name: ID
                  type: INT
                  autoIncrement: true
                  constraints:
                    primaryKey: true
              - column:
                  name: ID_USER
                  type: INT
              ...

        - sql:
            "DELIMITER $$
             CREATE FUNCTION autoInc ()
                 RETURNS INT(10)
                 BEGIN
                     DECLARE getCount INT(10);

                     SET getCount = (
                         SELECT COUNT(USER_ID)
                         FROM ORDERS) + 1;

                     RETURN getCount;
                 END$$
             DELIMITER ;"

我正在使用这种方法。当我在订单中插入新条目时,它也应该增加 user_id。因为我需要 user_id 作为另一个自动递增列。我正在使用 Liquibase 迁移来创建此 table,但出现错误:

Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER $$ CREATE FUNCTION autoInc () RETURNS INT(10) BEGIN DECLARE getCount I' at line 1
    ...

也许,我做错了什么?

您的方法存在各种问题。

首先,DELIMITER是一个built-in command of the mysql client, it is not recognized by the MySQL Server's SQL parser. Also, I wonder why you are not using https://docs.liquibase.com/change-types/pro/create-function.html

其次,你模拟二次自增的方法有问题。它会遇到竞争条件,因为如果多个并发事务正在插入一行,它们都会从您的 SELECT COUNT(*) 查询中获得相同的结果,因此它们都会尝试插入相同的值user_id.

MySQL 中真正的自动增量机制在事务范围之外工作,因此确保多个会话在每个 table 中读取相同的增量值。还有一个简短的 table 锁定,同时每个会话都会增加 table 的计数器。

为了使您的函数免受竞争条件的影响,您必须锁定 table,以确保一次只有一个会话可以读取该值。

第三,如果你要计算下一个更高的值,自动增量应该基于MAX(USER_ID),而不是COUNT(USER_ID)。如果您要从 table 中删除几行,那么 COUNT(USER_ID) 将生成一个低于最大值的值。

最后,我无法理解您为什么要为订单 table 设置 user_id 自动递增。您真的希望 每个 订单都生成一个新的 user_id 吗? user_id 不应该引用当前存在的用户吗?