Spring 中 H2 数据库的集成测试 MySQL 语法出现问题
Trouble with Integration Testing MySQL Syntax on an H2 Database in Spring
我正在从事一个使用不同 MySQL 模式进行客户管理的项目,例如每个客户都有自己的数据库架构,该架构是使用框架模板创建的。
对于兼容性问题,我必须从 Java 创建新的 MySQL 模式,这是在 PHP 之前完成的。我创建了一个小型服务 class,它通过重复使用 CREATE TABLE 'a' LIKE 'b';
在 MySQL 数据库上完美运行,但是这不适用于 H2db,因为 H2 不支持 LIKE
-创建表时的部分。然后我创建了一个 MySQL 并修改了文件以便用 Java 轻松处理(Files.readAllLines
,它被馈送到 Statement.executeBatch
)。但是,由于像 COLLATION=UTF8
这样的语句,此转储在 H2db 上也会失败。遗憾的是,这些很重要,因为我们经常有需要正确编码的特殊字符,所以不建议简单地从 sql 文件中删除所述语句。
我这样初始化数据源:
public DataSource dataSource(ResourceLoader resourceLoader) {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("data.sql").build();
}
所以,我的配置可能性很少。我们使用 gradle
来构建我们的应用程序,因此建议的 maven
-plugin 也无济于事 - 至少我还没有发现如何将它与 gradle
一起使用,如果可能的话完全没有。
所以我的问题是,我需要检查服务是否真的正确保存了数据,但我不能在内存中进行,因为 H2 不支持语法,而且我不允许使用"real" MySQL 数据库,因为我们所有的测试都必须从 "real" 连接中分离出来,并且只应在必要时将内存存储用于数据库。
您使用MySQL。
你有几种可能性。
我使用的几个:
1.Create in gradle with use groove (plugin) 您为 mysql 测试创建新数据库,并以相同的方式创建模式。
gradle中的一些配置可以帮助您。
def dbUser = 'root'
def dbPasswd = 'root'
def dbHost = 'localhost'
def dbName = 'testDB'
def dbPort = '3306'
def dbUrl = 'jdbc:mysql:////localhost:3306/testDB?
useUnicode=yes&characterEncoding=UTF-8'
dependencies {
testCompile files('libs/junit-4.12.jar')
testCompile files('libs/hamcrest-core-1.3.jar')
testCompile files('libs/mysql-connector-java-5.1.29.jar')
}
//create DB for test
task loadDriver {
URLClassLoader loader = GroovyObject.class.classLoader
loader.addURL(file('libs/mysql-connector-java-5.1.29.jar').toURL())
java.sql.DriverManager.registerDriver(loader.loadClass('com.mysql.jdbc.Driver').newInstance())
}
task createTestData(dependsOn: loadDriver) {
// println 'Connecting to database ...'
// def sql = groovy.sql.Sql.newInstance('jdbc:mysql://localhost:3306/?useUnicode=yes&characterEncoding=UTF-8', dbUser, dbPasswd, 'com.mysql.jdbc.Driver')
// println '... connected'
// println 'Drop test database testDB...'
// sql.execute 'drop database IF exists testDB;'
// println 'database testDB is droped'
// println 'Create test database testDB...'
// sql.execute 'create database if not exists testDB'
// println 'Database testDB is created'
}
2.You 可能会以类似的方式在 java 中创建基础 class,您在测试中使用它来创建 testDB mysql 例如:
public class TestDAO {
@Before
public void setUp() throws ClassNotFoundException, SQLException {
java.util.Date date = new java.util.Date();
LOG.info("Set up database for test "+date.getTime());
database = database + date.getTime();
LOG.info("DATABASE NAME:"+database);
LOG.info("Create database:"+database);
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(URL+":"+PORT, USER, PASS);
stmt = conn.createStatement();
String sql = "CREATE DATABASE " + database;
stmt.executeUpdate(sql);
} finally {
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
}
人们还可以发明其他一些方法。
数据库迁移工具
使用数据库迁移工具构建和重新构建您的数据库架构,例如:
与其直接编辑数据库,不如编写 SQL 脚本 and/or Java JDBC 类 来定义数据库架构。创建 table、定义列、导入数据、插入预期的行,全部在 SQL 或 Java 中作为 SQL 个脚本的集合 and/or Java 类。测试时,这些工具中的任何一个都将通过按照说明执行不断增长的 scripts/classes 集合来创建和加载新数据库。测试后,删除数据库。
为此,您的 Java 类 可以根据需要使用特定于 MySQL 或 H2 的替代语法。
在生产中使用 H2
此外,您可以完全跳过 MySQL,并在生产中使用 H2。
您可以通过为每个客户提供自己独立的 H2 数据库来解决 multi-tenancy 问题,这意味着每个客户都有自己的物理数据文件。
上面提到的数据库迁移工具通过在您的数据库中创建一个额外的 table 来工作,其中包含版本控制信息。在部署您的应用程序时,应用程序首先 运行 迁移工具首先更新数据库结构和数据,始终保持最新。这使得在生产中拥有许多单独的数据库变得容易,每个数据库都会在下次使用时在生产中实时自动更新。
您的数据库服务器需要足够的内存来支持可能同时被 H2 打开和使用的尽可能多的多个数据库。对于大量租户,您可以 运行 多个数据库服务器,每个服务器都有租户数据库的一个子集。
有关详细信息,请参阅 。
我最终使用 https://github.com/vorburger/MariaDB4j 作为嵌入式数据库,因为无论如何我们都使用 MariaDB,所以这肯定会消除所有方言问题。由于这与嵌入式 MongoDB 的工作方式相同,因此可以接受额外的测试成本。
但要注意:这 需要 64 位 OS 才能工作。
我正在从事一个使用不同 MySQL 模式进行客户管理的项目,例如每个客户都有自己的数据库架构,该架构是使用框架模板创建的。
对于兼容性问题,我必须从 Java 创建新的 MySQL 模式,这是在 PHP 之前完成的。我创建了一个小型服务 class,它通过重复使用 CREATE TABLE 'a' LIKE 'b';
在 MySQL 数据库上完美运行,但是这不适用于 H2db,因为 H2 不支持 LIKE
-创建表时的部分。然后我创建了一个 MySQL 并修改了文件以便用 Java 轻松处理(Files.readAllLines
,它被馈送到 Statement.executeBatch
)。但是,由于像 COLLATION=UTF8
这样的语句,此转储在 H2db 上也会失败。遗憾的是,这些很重要,因为我们经常有需要正确编码的特殊字符,所以不建议简单地从 sql 文件中删除所述语句。
我这样初始化数据源:
public DataSource dataSource(ResourceLoader resourceLoader) {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("data.sql").build();
}
所以,我的配置可能性很少。我们使用 gradle
来构建我们的应用程序,因此建议的 maven
-plugin 也无济于事 - 至少我还没有发现如何将它与 gradle
一起使用,如果可能的话完全没有。
所以我的问题是,我需要检查服务是否真的正确保存了数据,但我不能在内存中进行,因为 H2 不支持语法,而且我不允许使用"real" MySQL 数据库,因为我们所有的测试都必须从 "real" 连接中分离出来,并且只应在必要时将内存存储用于数据库。
您使用MySQL。 你有几种可能性。
我使用的几个:
1.Create in gradle with use groove (plugin) 您为 mysql 测试创建新数据库,并以相同的方式创建模式。
gradle中的一些配置可以帮助您。
def dbUser = 'root'
def dbPasswd = 'root'
def dbHost = 'localhost'
def dbName = 'testDB'
def dbPort = '3306'
def dbUrl = 'jdbc:mysql:////localhost:3306/testDB?
useUnicode=yes&characterEncoding=UTF-8'
dependencies {
testCompile files('libs/junit-4.12.jar')
testCompile files('libs/hamcrest-core-1.3.jar')
testCompile files('libs/mysql-connector-java-5.1.29.jar')
}
//create DB for test
task loadDriver {
URLClassLoader loader = GroovyObject.class.classLoader
loader.addURL(file('libs/mysql-connector-java-5.1.29.jar').toURL())
java.sql.DriverManager.registerDriver(loader.loadClass('com.mysql.jdbc.Driver').newInstance())
}
task createTestData(dependsOn: loadDriver) {
// println 'Connecting to database ...'
// def sql = groovy.sql.Sql.newInstance('jdbc:mysql://localhost:3306/?useUnicode=yes&characterEncoding=UTF-8', dbUser, dbPasswd, 'com.mysql.jdbc.Driver')
// println '... connected'
// println 'Drop test database testDB...'
// sql.execute 'drop database IF exists testDB;'
// println 'database testDB is droped'
// println 'Create test database testDB...'
// sql.execute 'create database if not exists testDB'
// println 'Database testDB is created'
}
2.You 可能会以类似的方式在 java 中创建基础 class,您在测试中使用它来创建 testDB mysql 例如:
public class TestDAO {
@Before
public void setUp() throws ClassNotFoundException, SQLException {
java.util.Date date = new java.util.Date();
LOG.info("Set up database for test "+date.getTime());
database = database + date.getTime();
LOG.info("DATABASE NAME:"+database);
LOG.info("Create database:"+database);
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(URL+":"+PORT, USER, PASS);
stmt = conn.createStatement();
String sql = "CREATE DATABASE " + database;
stmt.executeUpdate(sql);
} finally {
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
}
人们还可以发明其他一些方法。
数据库迁移工具
使用数据库迁移工具构建和重新构建您的数据库架构,例如:
与其直接编辑数据库,不如编写 SQL 脚本 and/or Java JDBC 类 来定义数据库架构。创建 table、定义列、导入数据、插入预期的行,全部在 SQL 或 Java 中作为 SQL 个脚本的集合 and/or Java 类。测试时,这些工具中的任何一个都将通过按照说明执行不断增长的 scripts/classes 集合来创建和加载新数据库。测试后,删除数据库。
为此,您的 Java 类 可以根据需要使用特定于 MySQL 或 H2 的替代语法。
在生产中使用 H2
此外,您可以完全跳过 MySQL,并在生产中使用 H2。
您可以通过为每个客户提供自己独立的 H2 数据库来解决 multi-tenancy 问题,这意味着每个客户都有自己的物理数据文件。
上面提到的数据库迁移工具通过在您的数据库中创建一个额外的 table 来工作,其中包含版本控制信息。在部署您的应用程序时,应用程序首先 运行 迁移工具首先更新数据库结构和数据,始终保持最新。这使得在生产中拥有许多单独的数据库变得容易,每个数据库都会在下次使用时在生产中实时自动更新。
您的数据库服务器需要足够的内存来支持可能同时被 H2 打开和使用的尽可能多的多个数据库。对于大量租户,您可以 运行 多个数据库服务器,每个服务器都有租户数据库的一个子集。
有关详细信息,请参阅
我最终使用 https://github.com/vorburger/MariaDB4j 作为嵌入式数据库,因为无论如何我们都使用 MariaDB,所以这肯定会消除所有方言问题。由于这与嵌入式 MongoDB 的工作方式相同,因此可以接受额外的测试成本。
但要注意:这 需要 64 位 OS 才能工作。