使用 HSQL 而不是 Oracle 对 MyBatis 进行单元测试
我想使用 HSQL 内存数据库对 MyBatis 持久层进行单元测试。实际应用使用Oracle数据库。在我们开始为 id 列添加自动递增数字之前,这工作得很好。 Oracle 需要使用序列来获取递增的数字,因此在 Oracle 数据库中创建了一个名为 basic_seq 的序列。在我的 MyBatis 映射器 XML 文件中,我有以下内容:
<insert id="insertBasis" parameterType="com.foo.Basis" useGeneratedKeys="true" keyProperty="id">
<selectKey resultType="long" keyProperty="id" order="BEFORE">
SELECT basis_seq.NEXTVAL FROM DUAL
</selectKey>
insert into basis
(id, name)
values
(#{id}, #{name})
</insert>
当我运行应用程序但单元测试出现错误时,此方法有效:
org.springframework.jdbc.BadSqlGrammarException:选择密钥时出错 或将结果设置为参数对象。原因: java.sql.SQLSyntaxErrorException:用户缺乏权限或对象没有 发现:双;错误的 SQL 语法 [];嵌套异常是 java.sql.SQLSyntaxErrorException:用户缺乏权限或对象没有 发现:双
据我了解,“DUAL”是 Oracle 中存储序列的某种虚拟表,但我的测试数据库中没有此表。如果我删除
标签,则单元测试可以工作(因为 HSQL 可以为标记为 identity
的列自动生成 id),但不能用于真正的应用程序。一种解决方法是为单元测试创建单独的 MyBatis 映射器 XML 文件,而不使用
标签,但这是不希望的,因为我想测试真实的配置。
有没有办法在 HSQL 中创建和使用序列,或者可能有一些 MyBatis 解决方法?或者我应该使用另一个数据库(例如 H2)进行单元测试?
我使用:
- Spring 3.0.5
- HSQL 2.2.4
- MyBatis 3.0.5
更新:
从 fredt 得到答案后,这是我编辑 Spring 配置的方式:
在我定义数据源之前:
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:test-data/schema.sql" />
<jdbc:script location="classpath:test-data/data.sql" />
</jdbc:embedded-database>
现在我这样做:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:test;sql.syntax_ora=true" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:test-data/schema.sql" />
<jdbc:script location="classpath:test-data/data.sql" />
</jdbc:initialize-database>
此外,在 schema.sql 中,我需要创建序列:(
CREATE SEQUENCE BASIS_SEQ START WITH 1000 INCREMENT BY 1;
CREATE SEQUENCE OTHER_SEQ START WITH 1000 INCREMENT BY 1;
如果在单元测试期间多次运行此脚本,请记住添加 drop sequence BASIS_SEQ if isn't;
到顶部架构.sql)
I would like to unit test my MyBatis persistence layer using an HSQL in-memory database. The real application uses an Oracle database. This worked fine unitl we started adding auto incremented numbers for the id columns. Oracle requires the use of a sequence to get the incremented number so a sequence called basis_seq was created in the Oracle database. In my MyBatis mapper XML file I have this:
<insert id="insertBasis" parameterType="com.foo.Basis" useGeneratedKeys="true" keyProperty="id">
<selectKey resultType="long" keyProperty="id" order="BEFORE">
SELECT basis_seq.NEXTVAL FROM DUAL
</selectKey>
insert into basis
(id, name)
values
(#{id}, #{name})
</insert>
This works when I run the application but the unit test gets an error:
org.springframework.jdbc.BadSqlGrammarException: Error selecting key
or setting result to parameter object. Cause:
java.sql.SQLSyntaxErrorException: user lacks privilege or object not
found: DUAL ; bad SQL grammar []; nested exception is
java.sql.SQLSyntaxErrorException: user lacks privilege or object not
found: DUAL
As I understand 'DUAL' is some kind of virtual table in Oracle that stores the sequences and I don't have this in my test database. If I remove the <selectKey>
-tag the unit test work (since HSQL can autogenerate ids for columns marked identity
) but not the real application. One workaround would be to create separate MyBatis mapper XML files for the unit tests without the <selectKey>
-tag but this is undesired since I want to test the real configuration.
Is there a way to create and use a sequence in HSQL as well or maybe some MyBatis workaround for this? Or should I use another database for my unit test like H2?
I use:
- Spring 3.0.5
- HSQL 2.2.4
- MyBatis 3.0.5
UPDATE:
After getting the answer from fredt, here is how I edited my Spring configuration:
Before I defined my data source with:
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:test-data/schema.sql" />
<jdbc:script location="classpath:test-data/data.sql" />
</jdbc:embedded-database>
Now I do this:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:test;sql.syntax_ora=true" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:test-data/schema.sql" />
<jdbc:script location="classpath:test-data/data.sql" />
</jdbc:initialize-database>
Also, in schema.sql I need to create the sequences:
CREATE SEQUENCE BASIS_SEQ START WITH 1000 INCREMENT BY 1;
CREATE SEQUENCE OTHER_SEQ START WITH 1000 INCREMENT BY 1;
(if you run this script many times during unit testing, remember to add drop sequence BASIS_SEQ if exists;
to top of schema.sql)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
最新的 HSQLDB 提供了广泛的 Oracle 语法兼容性。您只需将
sql.syntax_ora=true
添加到数据库 URL 即可。例如:请参阅指南
http://hsqldb.org/doc/2.0/guide/deployment-chapt。 html
http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html
SQL 语法兼容性在新版本的 HSQLDB 中不断扩展,因此最好使用最新的可用版本。
Latest HSQLDB provides extensive Oracle syntax compatibility. All you need is add
sql.syntax_ora=true
to your database URL. For example:See the Guide
http://hsqldb.org/doc/2.0/guide/deployment-chapt.html
http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html
SQL syntax compatibility is constantly extended in new versions of HSQLDB, so it's best to use the latest available version.
您仍然可以使用
来使用原来的 4 行配置。只需在 test-data/schema.sql 文件的开头添加以下行:这实际上与将
sql.syntax_ora=true
附加到 JDBC URL 相同。You can still use your original 4 line configuration using
<jdbc:embedded-database ...>
. Just add following line at the beginning of your test-data/schema.sql file:This is effectivelly same as appending
sql.syntax_ora=true
to your JDBC URL.