golang执行mysql创建函数脚本

近期在使用gorm的过程中遇到个问题: 我使用了gorm来进行mysql数据库初始化(建表/插入初始化数据/创建函数/添加触发器等),建表和插入初始化数据很容易实现,但是添加函数和触发器时,无法直接使用gorm实现(可能是我没找到方法),每次执行的时候都会报错。
我的mysql脚本如下:

-- 函数;
DELIMITER $$
DROP FUNCTION IF EXISTS get_ver$$
CREATE FUNCTION `get_ver` (    ver_name VARCHAR ( 50 )) RETURNS INT ( 11 )
DETERMINISTIC
BEGIN
    DECLARE    val INTEGER;
    SET val = 0;

    SELECT current_val INTO val
    FROM sys_sequence
    WHERE    seq_name = ver_name
    FOR UPDATE;

    UPDATE sys_sequence SET current_val = current_val + increment_val
    WHERE    seq_name = ver_name;

    RETURN val;

END $$
DELIMITER ;

-- 触发器;
DELIMITER $$

DROP TRIGGER IF EXISTS `TRI_user_info_before_insert`$$
CREATE TRIGGER `TRI_user_info_before_insert` BEFORE INSERT ON `user_info` FOR EACH ROW BEGIN
    set NEW.auto_ver = get_ver('user_info_ver');
END $$

DROP TRIGGER IF EXISTS `TRI_user_info_before_update`$$
CREATE TRIGGER `TRI_user_info_before_update` BEFORE UPDATE ON `user_info` FOR EACH ROW BEGIN
    set NEW.auto_ver = get_ver('user_info_ver');
END $$

DELIMITER ;

COMMIT;

最初尝试的是使用gorm的Exec方法,但是执行报错,说有语法错误“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 $$”

然后我又试了一种方式,将脚本写到单独的文件里,然后使用os.exec命令去执行,这样倒是执行成功了,但是这有个限制(运行的电脑上必须安装了mysql或mysql客户端)。

想问下大家有没有其他的好方法实现golang执行mysql原生脚本,如使用gorm等,不用电脑上必须安装mysql。

参考GPT和自己的思路:

针对你的问题,我们可以使用GORM的Raw方法来执行原生的SQL语句,这样就能够执行你的MySQL脚本了。你可以把你的MySQL脚本先写到一个字符串变量中,然后通过Raw方法执行它。

以下是一个示例代码,供你参考:

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

func main() {
    // 连接 MySQL 数据库
    dsn := "user:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        panic(err)
    }

    // 定义 MySQL 脚本
    sqlScript := `
        -- 函数;
        DELIMITER $$
        DROP FUNCTION IF EXISTS get\_ver$$
        CREATE FUNCTION ` + "`get_ver` (ver_name VARCHAR ( 50 )) RETURNS INT ( 11 )" + `
        DETERMINISTIC
        BEGIN
            DECLARE    val INTEGER;
            SET val = 0;

            SELECT current_val INTO val
            FROM sys_sequence
            WHERE    seq_name = ver_name
            FOR UPDATE;

            UPDATE sys_sequence SET current_val = current_val + increment_val
            WHERE    seq_name = ver_name;

            RETURN val;

        END $$
        DELIMITER ;

        -- 触发器;
        DELIMITER $$
        DROP TRIGGER IF EXISTS ` + "`TRI_user_info_before_insert`" + `$$
        CREATE TRIGGER ` + "`TRI_user_info_before_insert`" + ` BEFORE INSERT ON ` + "`user_info`" + ` FOR EACH ROW BEGIN
         set NEW.auto_ver = get_ver('user_info_ver');
        END $$

        DROP TRIGGER IF EXISTS ` + "`TRI_user_info_before_update`" + `$$
        CREATE TRIGGER ` + "`TRI_user_info_before_update`" + ` BEFORE UPDATE ON ` + "`user_info`" + ` FOR EACH ROW BEGIN
         set NEW.auto_ver = get_ver('user_info_ver');
        END $$
        DELIMITER ;

        COMMIT;
    `

    // 执行 MySQL 脚本
    if err := db.Exec(sqlScript).Error; err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("执行成功!")
    }
}

这个示例代码中,我们直接使用db.Exec方法执行MySQL脚本。因为我们使用的是GORM的MySQL驱动,所以是会自动将脚本中的;替换成\n,这样就可以解决语法错误的问题了。

关于这个问题,我没有找到比较好的执行整个脚本的方法,貌似golang的mysql驱动不支持DELIMITER ,最后用笨办法解决了。
我用的笨办法就是将各个语句拆开,然后用分别用Exec执行,并且整体加到一个事务里。
这个方法虽然能解决,但是个人认为并不好,等有空了试试写一个按$$分隔,循环执行的方法。