Sybase ASE转HSQLDB时JUnit触发SQLSyntaxErrorException问题求助
解决HSQLDB测试中Sybase ASE SQL语句的语法报错问题
我之前也碰到过不同数据库之间SQL语法、类型兼容的坑,你的问题核心是HSQLDB不支持Sybase ASE特有的image数据类型和convert(image, ...)转换语法,导致JUnit测试抛出java.sql.SQLSyntaxErrorException。下面给你几个可行的解决思路:
思路1:直接修改测试用SQL,适配HSQLDB规则
因为是测试环境用的HSQLDB,我们可以把SQL改成HSQLDB能识别的写法:
- HSQLDB没有Sybase的
image类型,对应的二进制类型是VARBINARY或者BINARY - 虽然HSQLDB也支持
convert函数,但类型参数要换成它认识的,或者直接用更通用的CAST函数
修改后的MyBatis映射语句如下:
<select id="GET_FILE_BY_FILE_ID" parameterType="long" resultType="com.employer.my.File" statementType="PREPARED"> SELECT file_id fileId, file_name name, file_type type, CASE WHEN file_data_long IS NULL THEN CAST(file_data_short AS VARBINARY) ELSE file_data_long END AS fileData FROM FILES_TABLE WHERE file_id = #{id} </select>
如果file_data_short本身就是二进制类型,甚至可以直接去掉转换逻辑,HSQLDB会自动兼容。
思路2:用MyBatis多环境适配(推荐,不影响生产代码)
为了避免生产环境(Sybase)和测试环境(HSQLDB)的SQL冲突,最好用MyBatis的数据库ID功能来做动态适配:
- 先在MyBatis配置文件里配置数据库ID映射,让MyBatis能识别当前连接的数据库:
<databaseIdProvider type="DB_VENDOR"> <property name="Sybase" value="sybase"/> <property name="HSQL Database Engine" value="hsqldb"/> </databaseIdProvider>
- 然后在SQL映射里用
<if>标签根据数据库ID选择对应的语法:
<select id="GET_FILE_BY_FILE_ID" parameterType="long" resultType="com.employer.my.File" statementType="PREPARED"> SELECT file_id fileId, file_name name, file_type type, CASE WHEN file_data_long IS NULL THEN <if test="_databaseId == 'sybase'"> convert(image, file_data_short) </if> <if test="_databaseId == 'hsqldb'"> CAST(file_data_short AS VARBINARY) </if> ELSE file_data_long END AS fileData FROM FILES_TABLE WHERE file_id = #{id} </select>
这样MyBatis会自动根据当前数据库环境切换对应的SQL片段,生产环境用Sybase原生语法,测试环境用HSQLDB兼容写法,完美隔离两者的差异。
思路3:给HSQLDB添加自定义类型别名
你也可以在测试初始化的时候,给HSQLDB创建一个image类型的别名,映射到它支持的二进制类型:
CREATE TYPE image AS VARBINARY;
之后原来的convert(image, ...)语法在HSQLDB里就能被识别了。不过这种方法需要额外的初始化脚本,灵活性不如思路2。
总结一下,思路2是最稳妥的方案,既能保证生产代码的正确性,又能让测试顺利跑起来,不会因为数据库差异来回修改SQL。
内容的提问来源于stack exchange,提问作者datv
相关产品推荐
相关产品推荐

