有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用MyBatis、H2和Oracle程序进行java集成测试

我有一个存储Oracle过程,我这样调用它:

CALL MY_PROC(
        p_arg    =>   #{arg,     jdbcType=INTEGER,  mode=IN},
        p_var    =>   #{var,     jdbcType=VARCHAR,  mode=IN},
        p_date   =>   #{date,    jdbcType=DATE,     mode=IN}
    )

我用MyBatis这样写:

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.MyMapper">
    <update id="callMyProc" statementType="CALLABLE">
        CALL MY_PROC(
            p_arg    => #{arg,    jdbcType=INTEGER,  mode=IN},
            p_var    => #{var,    jdbcType=VARCHAR,  mode=IN},
            p_date   => #{date,   jdbcType=DATE,     mode=IN}
        )
    </update>
</mapper>

过程本身会执行一些FOR UPDATE,因为我必须在更新行之前锁定它们。代码完成了它的工作,但我现在想编写一些集成测试,我使用H2作为数据库。我知道在这种情况下,我应该编写用户定义的函数来处理这种情况。我非常确定,编写这样一个查询(为了这个问题,sql查询被简化了):

CREATE ALIAS IF NOT EXISTS MY_PROC AS $$
import java.net.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.UUID;
import java.time.LocalDateTime;
@CODE
void callMyProc(Connection conn, Integer p_arg, String p_var, LocalDateTime p_date) throws Exception {
    String sqlStatement = String.format("UPDATE mytable SET myvar = '%s', mydate = '%t' WHERE myarg = %d", p_var, p_date, p_arg);
    PreparedStatement ps = conn.prepareStatement(sqlStatement);
    ps.execute();
}
$$;

可以做到这一点,但不幸的是,由于MyBatis格式,我遇到了语法错误:

### The error may exist in com.example/MyMapper.xml
### The error may involve com.example.MyMapper.callMyProc
### The error occurred while executing an update
### SQL: CALL MY_PROC(                 p_arg       => ?, p_var => ?, p_date => ?  )
### Cause: org.h2.jdbc.JdbcSQLSyntaxErrorException: Błąd składniowy w wyrażeniu SQL "CALL MY_PROC(
                P_ARG[*]       => ?,
                P_VAR[*]       => ?,
                P_DATE[*]       => ?
            )"
Syntax error in SQL statement "CALL MY_PROC(
                P_ARG[*]       => ?,
                P_VAR[*]       => ?,
                P_DATE[*]       => ?
CALL MY_PROC(
                p_arg       => ?,
                p_var[*]       => ?,
                p_date[*]       => ?
            ) [42000-200]

我的问题是,我应该如何为程序编写我的H2别名,以便MyBatis和H2都能满足要求


共 (1) 个答案

  1. # 1 楼答案

    正如用户所建议的,事实证明,去掉Oracles语法,只需将MyBatis mapper写成这样就足够了:

    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.MyMapper">
        <update id="callMyProc" statementType="CALLABLE">
            CALL MY_PROC(
                #{arg,    jdbcType=INTEGER,  mode=IN},
                #{var,    jdbcType=VARCHAR,  mode=IN},
                #{date,   jdbcType=TIMESTAMP,     mode=IN}
            )
        </update>
    </mapper>
    

    我还必须将date类型更改为TIMESTAMP,别名应该如下所示:

    CREATE ALIAS IF NOT EXISTS MY_PROC AS $$
    import java.net.*;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.util.Date;
    @CODE
    void callMyProc(Connection conn, Integer p_arg, String p_var, Date p_date) throws Exception {
        String sqlStatement = String.format("UPDATE mytable SET myvar = '%s', mydate = PARSEDATETIME('%s','yyyy-MM-dd HH:mm:ss') WHERE myarg = %d", p_var, p_date.toString(), p_arg);
        PreparedStatement ps = conn.prepareStatement(sqlStatement);
        ps.execute();
    }
    $$;
    

    匹配LocalDateTime类型的Java(此时,从LocalDateTimejava.util.Date的映射将自动完成)。这样编写的唯一缺点是,在调用存储过程时,必须注意参数的顺序