MySQL如何创建两个自增列?Liquibase执行自定义函数语法报错如何解决
问题原因
- 第一个错误来自
DELIMITER指令的误用:DELIMITER是MySQL命令行客户端专属的分隔符控制指令,不属于标准SQL语法,Liquibase底层通过JDBC执行SQL时,JDBC驱动无法识别该指令,直接写在sql标签中就会触发语法报错。 - 第二个隐性问题是你当前的函数逻辑存在错误和缺陷:
- 表中定义的用户ID字段是
ID_USER,但函数中查询的是USER_ID,字段名不匹配执行时会报错 - 用
COUNT(USER_ID) + 1实现自增完全不抗并发,多线程同时插入数据时会生成大量重复的ID_USER值,无法实现自增效果 - 你仅定义了函数,没有给
ID_USER字段绑定默认值或触发器,插入数据时不会自动调用该函数,逻辑不会生效 - 低于8.0版本的MySQL不支持将自定义函数的返回值作为字段默认值,就算修复语法问题也无法直接用默认值的方式实现需求
- 表中定义的用户ID字段是
解决方案
1. 修复Liquibase创建函数的语法
不要写DELIMITER语句,改用createProcedure标签自动处理分隔符,或者给sql标签添加endDelimiter属性,示例如下:
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 # 其他字段省略 # 用createProcedure创建函数,自动处理分隔符 - createProcedure: dbms: mysql procedureName: autoInc procedureBody: | CREATE FUNCTION autoInc () RETURNS INT(10) BEGIN DECLARE getCount INT(10); -- 改用MAX取最大值,为空时默认从1开始 SET getCount = (SELECT IFNULL(MAX(ID_USER), 0) FROM ORDERS) + 1; RETURN getCount; END
2. 优化自增逻辑
如果你的需求是ID_USER和主键ID保持同步自增,完全不需要自定义函数,两种更靠谱的实现方式:
- 方式一:插入数据时直接取主键自增的返回值赋值给
ID_USER,或者直接在插入语句中调用2505233,性能最高无并发问题 - 方式二:如果要数据库层面自动处理,用触发器实现,不需要自定义函数:
- createProcedure: dbms: mysql procedureName: orders_before_insert_trigger procedureBody: | CREATE TRIGGER orders_before_insert BEFORE INSERT ON ORDERS FOR EACH ROW BEGIN -- 直接和主键ID保持一致即可,不需要查表统计 SET NEW.ID_USER = (SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ORDERS'); END
内容的提问来源于stack exchange,提问作者Jonas_Astley
相关产品推荐
相关产品推荐

