我在MS SQL Server中有一个用户定义的函数,从Java代码调用,在H2数据库中运行集成测试时似乎未定义。您可以在the previous question中找到我的代码。
测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {H2Config.class})
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DbUnitTestExecutionListener.class,
TransactionalTestExecutionListener.class
})
@TransactionConfiguration(defaultRollback = true)
public class TableDaoTest {
@Autowired
private TableDao tableDao;
@Test
@DatabaseSetup("/datasets/import.xml")
public void testMethod01() {
tableDao.getRecordsByGroup();
...
数据库模式由Hibernate自动生成。正如您所见,DbUnit使用xml数据集填充测试数据。此测试失败,因为我在MS SQL Server DB中存在的函数在H2数据库中未定义。
应用程序日志:
Caused by: org.hibernate.exception.GenericJDBCException: could not prepare statement
...
Caused by: org.h2.jdbc.JdbcSQLException: Function "SAFE_MOD" not found; SQL statement:
select table10_.id, table10_.value, ... from Table1 table10_ where table10_.group1=dbo.safe_mod(?, ?);
...
如何在DbUnit测试之前导入/创建函数?
答案 0 :(得分:1)
@naXa 和@Alan 方法适用于标量值函数。对于表值函数,使用 ResultSet
:
package com.package.app;
import org.h2.tools.SimpleResultSet;
@SuppressWarnings("unused")
public class H2Functions {
// All function params goes here
// LocalDate not working here, we have to use java.sql.Date
public static ResultSet gePrice(Long recipientId, Long currencyId, Date priceDate) {
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("price", Types.DECIMAL, 10, 0);
rs.addColumn("priceDate", Types.TIMESTAMP, 10, 0);
rs.addRow(new BigDecimal("123.23"), new Timestamp(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)) );
return rs;
}
}
示例 application.yml 配置:
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:h2:DB_NAME;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
name:
username:
password:
hikari:
auto-commit: false
# create alias for functions on db connection initialization
connection-init-sql: "CREATE ALIAS IF NOT EXISTS SAFE_MOD DETERMINISTIC FOR \"com.package.app.H2Functions.gePrice\";"
然后你可以用你的 POJO 包装响应。
您可以在 H2 文档中找到有关用户定义函数的更多信息: http://www.h2database.com/html/features.html#user_defined_functions
答案 1 :(得分:0)
H2数据库不支持用户定义的SQL函数。但是,在此数据库中,Java函数也可以用作存储过程。
@SuppressWarnings("unused")
public class H2Function {
public static int safeMod(Integer n, Integer divider) {
if (divider == null) {
divider = 5000;
}
return n % divider;
}
}
请注意,仅支持静态Java方法;类和方法都必须是公共的。
必须先通过调用CREATE ALIAS ... FOR
来声明(在数据库中注册)Java函数,然后才能使用它:
CREATE ALIAS IF NOT EXISTS safe_mod DETERMINISTIC FOR "by.naxa.H2Function.safeMod";
这个语句应该在任何测试之前执行,所以我决定把它放在连接init SQL中:
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:my_db_name");
dataSource.setUsername("sa");
dataSource.setPassword("");
dataSource.setConnectionInitSqls(Collections.singleton(
"CREATE ALIAS IF NOT EXISTS safe_mod DETERMINISTIC FOR \"by.naxa.H2Function.safeMod\";"));
return dataSource;
}
答案 2 :(得分:0)
请相信naxa,此解决方案基于他们的解决方案。这是为了从postgres中“存根” WORD_SIMILARITY,
@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(
locations = "classpath:application-test.properties")
public class testServiceTests {
@Autowired
private MyService myService;
@Test
public void someTest() {
}
}
这应该在您的application-test.properties中
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:~/my_database;MODE=PostgreSQL;INIT=CREATE ALIAS IF NOT EXISTS WORD_SIMILARITY DETERMINISTIC FOR "com.example.H2Function.wordSimilarity";TRACE_LEVEL_FILE=0;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;
spring.datasource.username=postgres
spring.datasource.password=postgres
hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
hibernate.flushMode=FLUSH_AUTO
hibernate.hbm2ddl.auto=create-drop
spring.datasource.data=classpath:V1__base-schema.sql
这是要替换的H2功能
@SuppressWarnings("unused")
public class H2Function {
public static double wordSimilarity(String string, String word) {
if ( word== null ) {
return 0;
}
return 0.5;
}
}