在单元测试时支持 H2 数据库中的 DB2 功能
Posted
技术标签:
【中文标题】在单元测试时支持 H2 数据库中的 DB2 功能【英文标题】:Support DB2 functions in H2 database while unit testing 【发布时间】:2015-08-20 08:12:25 【问题描述】:我们有一个 DB2 数据库在生产中,我们正在设置一个 H2 内存数据库用于测试。我知道即使我们在 DB2 模式下配置 H2,也不是所有的 DB2 功能都受支持。 我们如何对包含数据库特定功能但在 H2 中尚不支持的 SQL 进行单元测试?
如果我们开始编写 H2 特定的 DB 服务,那么我们将结束编写不同层的功能代码。
功能不支持
VARCHAR_FORMAT
H2 配置
jdbc:h2:mem:test;MODE=DB2
H2版
1.4.188
Java 堆栈跟踪
Caused by: org.h2.jdbc.JdbcSQLException: Function "VARCHAR_FORMAT" not found; SQL statement:
select S.SCHEDULE_ID scheduleId, VARCHAR_FORMAT(S.START_DATE, 'DD-Mon-YYYY') startDate
from ScheduleSubscription S WITH UR [90022-182]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.182.jar:1.4.182]
at org.h2.message.DbException.get(DbException.java:179) ~[h2-1.4.182.jar:1.4.182]
at org.h2.message.DbException.get(DbException.java:155) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readJavaFunction(Parser.java:2333) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readFunction(Parser.java:2385) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readTerm(Parser.java:2719) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readFactor(Parser.java:2251) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readSum(Parser.java:2238) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readConcat(Parser.java:2208) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readCondition(Parser.java:2058) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readAnd(Parser.java:2030) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readExpression(Parser.java:2022) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSimpleSelectPart(Parser.java:1934) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSimple(Parser.java:1966) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSub(Parser.java:1860) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectUnion(Parser.java:1681) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelect(Parser.java:1669) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parsePrepared(Parser.java:433) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parse(Parser.java:305) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parse(Parser.java:277) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.prepareCommand(Parser.java:242) ~[h2-1.4.182.jar:1.4.182]
at org.h2.engine.Session.prepareLocal(Session.java:446) ~[h2-1.4.182.jar:1.4.182]
at org.h2.engine.Session.prepareCommand(Session.java:388) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1190) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:72) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:666) ~[h2-1.4.182.jar:1.4.182]
at org.apache.commons.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:295) ~[commons-dbcp-1.4.jar:1.4]
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:318) ~[commons-dbcp-1.4.jar:1.4]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_35]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_35]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_35]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_35]
at org.apache.ibatis.logging.jdbc.ConnectionLogger.invoke(ConnectionLogger.java:54) ~[mybatis-3.2.8.jar:3.2.8]
at $Proxy35.prepareStatement(Unknown Source) ~[na:na]
at org.apache.ibatis.executor.statement.PreparedStatementHandler.instantiateStatement(PreparedStatementHandler.java:73) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.statement.BaseStatementHandler.prepare(BaseStatementHandler.java:85) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.statement.RoutingStatementHandler.prepare(RoutingStatementHandler.java:57) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:73) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:59) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:137) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:96) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:77) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102) ~[mybatis-3.2.8.jar:3.2.8]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_35]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_35]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_35]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_35]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
... 47 common frames omitted
【问题讨论】:
另一个很好的例子说明为什么在测试和生产中使用不同的 DBMS 是一个坏主意。 【参考方案1】:创建一个名为 VARCHAR_FORMAT
的 H2 函数,并确保它至少为测试数据返回正确的值。
这当然需要为 H2 中尚不存在的每个功能付出努力,但非常可行。测试也保持干净。
【讨论】:
我用了这个链接h2database.com/html/features.html#user_defined_functions以上是关于在单元测试时支持 H2 数据库中的 DB2 功能的主要内容,如果未能解决你的问题,请参考以下文章
内存数据库中的 H2:使用 JDBC 设置时区? Java 单元测试