【问题标题】:Spring and MySQL stored procedureSpring 和 MySQL 存储过程
【发布时间】:2016-06-24 23:27:19
【问题描述】:

我有一个在 MySql 工作台中运行良好的存储过程,但是当它由 Spring 使用 ResourceDatabasePopulator 运行时,它会因语法错误而失败。 阅读周围有类似的问题,应该在脚本中设置分隔符,我遵循了这些但同样的错误仍然存​​在。

这是SP

DELIMITER $$
CREATE PROCEDURE userAttributesOrder()
READS SQL DATA
    BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE i INT DEFAULT 0;
    DECLARE attCount INT DEFAULT 0;
        DECLARE cod VARCHAR(64) DEFAULT NULL;
        DECLARE curs CURSOR FOR SELECT CODE FROM PA_ATTR_TYPE ORDER BY NAME ASC;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
        SET i = 0;    
        OPEN curs;
            read_loop: LOOP
                FETCH curs INTO cod;
                IF done THEN
                    LEAVE read_loop;
                END IF;
                INSERT INTO LAYOUT(ELEMENT_TYPE, ELEMENT_CODE, LAYOUT_ORDER) VALUES ('PA_ATTRIB', cod, i);
                SET i = i + 1;
            END LOOP;
        CLOSE curs;
    END$$
DELIMITER ;

这是个例外

org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #4 of resource class path resource [database/updates/23-update.sql]: DELIMITER $$ CREATE PROCEDURE user
AttributesOrder() READS SQL DATA BEGIN DECLARE done INT DEFAULT FALSE; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corre
sponds to your MySQL server version for the right syntax to use near 'DELIMITER $$ CREATE PROCEDURE userAttributesOrder() READS SQL DATA BEGIN DECLARE' at line 1
        at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:472) ~[spring-jdbc-4.1.6.RELEASE.jar:4.1.6.RELEASE]

有人知道如何解决这个问题吗?只是 Spring 让我感到沮丧,因为使用纯 Java 我不会遇到问题。

包括更新 Spring 代码 这里要求的是我继承的运行脚本的 Spring 代码。

DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();

for (String script : orderedScripts) {
    databasePopulator.addScript(new ClassPathResource(script));
}

initializer.setDatabasePopulator(databasePopulator);
initializer.afterPropertiesSet();

【问题讨论】:

  • 该脚本不适用于ResourceDatabasePopulator,因为它认为; 是分隔符,它使用它来确定行尾。
  • @M. Denium 你好,谢谢你的回复。是的,我意识到这是问题所在,但问题是如何修复它以使其运行。您当然不能说存储过程不能与 ResourceDatabasePopulator 一起使用!设置 DELIMITER 和在 Spring 中使用 databasePopulator.setSeparator("$$"); 设置分隔符没有区别。导致所有其他脚本失败,这是预期的。任何人都知道我该如何解决这个问题,以便我可以使用 ResourceDatabasePopulator 运行存储过程?
  • 你不能。此外,您没有运行您正在定义它的存储过程。作为一种解决方法,您可以尝试将其放在单独的 ResourceDatabasePopulator 中,或者使用分隔符集实现您自己的 DatabasePopulator,并为其他脚本使用默认值。
  • 是的,我定义它并在下一行运行它......但谢谢。很高兴知道 Spring 再次限制了我想做的事情。我将创建一个临时表,形成我的数据,然后复制。感谢您的回复。

标签: mysql spring stored-procedures spring-jdbc


【解决方案1】:

我使用 ;; 作为分隔符,将其设置为 ResourceDatabasePopulator.setSeperator()

这似乎不会破坏其他东西并在我的 DB IDE 中运行。我的 DB IDE (dbVisualizer) 看到 2 个分隔符并且不在乎。

【讨论】:

    【解决方案2】:

    我也遇到过这个问题,现在我找到了解决方案。 其实是3!因此,您可以选择适合您需求的任何一种。但它的关键是格式正确的String,它代表创建SP 的DB 脚本。 我还没有弄清楚如何在一个 SQL 脚本/字符串中结合删除和创建 SP,但无论如何我对这些解决方案很满意。

    仅供参考:

    解决方案 1:使用 JdbcTemplate 和 Java String

    在格式良好的String sql 脚本中包含尾随空格非常重要

            String sqlSP = "CREATE PROCEDURE test_stored_proc (IN pInstanceId varchar(255)) " +
                    "BEGIN " +
                        "SELECT * FROM vw_subscriptions WHERE instanceId = pInstanceId; " +
                    "END";
    
            jdbcTemplate.execute(sqlSP);
    

    解决方案2:使用ResourceDatabasePopulator & ClassPathResource 在文件中加载SQL脚本

            ClassPathResource resource = new ClassPathResource("/data/create-sp_TEST_STORED_PROC.sql");
            jdbcTemplate.execute("DROP procedure IF EXISTS `test_stored_proc`;");
    
            ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(resource);
            databasePopulator.setSeparator(ScriptUtils.EOF_STATEMENT_SEPARATOR);
            databasePopulator.execute(testSetupDataSource);
    

    解决方案 3:使用ScriptUtils & ClassPathResource 在文件中加载 SQL 脚本

            ClassPathResource resource = new ClassPathResource("/data/create-sp_TEST_STORED_PROC.sql");
            jdbcTemplate.execute("DROP procedure IF EXISTS `test_stored_proc`;");
    
            ScriptUtils.executeSqlScript(Objects.requireNonNull(testSetupDataSource).getConnection(), new EncodedResource(resource),
                    false, false,
                    ScriptUtils.DEFAULT_COMMENT_PREFIX, ScriptUtils.EOF_STATEMENT_SEPARATOR,
                    ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER, ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER);
    
    

    create-sp_TEST_STORED_PROC.sql 脚本的内容

    对于解决方案 #1 和 #2,适用与第一个解决方案相同的规则:

    • 空白字符的格式和存在非常重要,尤其是每行末尾的额外尾随空格。

    所以下面的代码是由我的vim设置存档的,代表空白字符

    CREATE·PROCEDURE·test_stored_proc·(IN·pInstanceId·varchar(255))~¬
    BEGIN~¬
    –→SELECT·*·FROM·vw_subscriptions·WHERE·instanceId·=·pInstanceId;~¬
    END;~¬
    

    我相信它在内部表示为一行字符串: CREATE PROCEDURE test_stored_proc (IN pInstanceId varchar(255)) BEGIN SELECT * FROM vw_subscriptions WHERE instanceId = pInstanceId; END

    几乎完整的源代码可以在我的GitHub找到

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多