com.h2database
h2
2.1.214
spring:
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:ut_test;DB_CLOSE_DELAY=-1;MODE=MySQL
username:
password:
sql:
init:
schema-locations:
- classpath:schema.sql
data-locations:
- classpath:data.sql
mybatis-plus:
mapper-locations: classpath*:mapper/*Mapper.xml
global-config:
db-config:
logic-delete-field: IsDeleted
logic-delete-value: 1
logic-not-delete-value: 0
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class) //启动SpringRunner运行单测
@SpringBootTest(classes = { // 指定需要加载到Spring容器中的类
DataSourceAutoConfiguration.class, // 数据源自动装配类,装配数据源DataSource
MybatisPlusAutoConfiguration.class, // mybatisPlus自动装配类,SqlSession相关Bean
SqlInitializationAutoConfiguration.class,// sql初始化自动装配类,以运行sql初始化文件(eg. schema.sql)
RepoTestConfig.class // 自定义配置类,指定mapper扫描路径
})
public class BaseTest {
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan({"com.xx.mapper"}) // 指定mapper类扫描位置
public class RepoTestConfig {
}
// 具体测试类
public class MapperTest extends BaseTest {
@Autowired
TestgMapper testgMapper ;
@Test
public void selectByKey() {
testgMapper .selectByKey("");
}
}
schema.sql
CREATE TABLE `xx` (
`Id` bigint(20) NOT NULL AUTO_INCREMENT,
`K` varchar(255) NOT NULL COMMENT 'key',
`V` text COMMENT 'value',
`Remark` varchar(255) DEFAULT NULL,
`CreatedBy` int(11) DEFAULT '0' COMMENT '0-system',
`CreatedDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`UpdatedBy` int(11) DEFAULT '0' COMMENT '0-system',
`UpdatedDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`IsDeleted` bit(1) DEFAULT '0',
PRIMARY KEY (`Id`),
UNIQUE KEY `Idx_K` (`K`)
);
data.sql (看需求)
insert into ...
5.1 Spring容器需要加载哪些类,如何加载
方式一,通过@SpringBootApplication启动容器&加载Bean
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = {"com.xx.mapper"})
public class UTApplication {
public static void main(String[] args) {
SpringApplication.run(UTApplication.class, args);
}
}
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = UTApplication.class)
public class BaseTest {
}
pros:简单,几个注解简单配置搞定,不用去关心具体需要配置的Bean(因为所有用到的用不到的都被引入了)
cons:@SpringBootApplication注解会开启自动装配,一些非必要的类也会被装配到单测的Spring环境中
方式二 按需装配
@RunWith(SpringRunner.class) //启动SpringRunner运行单测
@SpringBootTest(classes = { // 指定需要加载到Spring容器中的类
DataSourceAutoConfiguration.class, // 数据源自动装配类,装配数据源DataSource
MybatisPlusAutoConfiguration.class, // mybatisPlus自动装配类,SqlSession相关Bean
SqlInitializationAutoConfiguration.class,// sql初始化自动装配类,以运行sql初始化文件(eg. schema.sql)
RepoTestConfig.class // 自定义配置类,指定mapper扫描路径
})
public class BaseTest {
}
pros:按需加载,用到哪些加载哪些
cons:需要花些时间确定需要加载的Bean,最后确定如上图
5.2 问题&解决
按照spring.datasource.schema: schema.sql的方式配置sql初始化脚本,以@SpringBootApplication方式启动容器没问题,改成按需装配后初始化脚本schema.sql 未执行
spring:
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:ut_test;DB_CLOSE_DELAY=-1;MODE=MySQL
username:
password:
schema : schema.sql // 一开始错误的配置方式
sql:
init:
schema-locations:
- classpath:schema.sql // 修正后正确的配置方式
排查一番后发现,原因是按需加载方式未将负责初始化sql的sql Initializer加载到容器中,所以就做不了这事,经过排查,此类是SqlInitializationAutoConfiguration,将其指定加载到容器中即可。
而@SpringBootApplication方式默认是装配了该类的,所以可行。
并且在排查过程中发现,sql Initializer默认会去找spring.sql.init下指定的sql文件,如果找不到,再去加载了classpath下的schema.sql。所以之前schema: schema.sql指定的sql文件能被正确加载,是因为他被命名为schemal.sql并且被放在了classpath下,并不是因为schema: schema.sql的配置,换个名就不行了。也就是说不需要配置schema: schema.sql, 直接在resource下放一个名叫schema.sql的文件,都能正常工作。正确的方式是通过spring.sql.init方式指定
排查过程
通过查看配置文件中schema-locations的引用位置,定位到SqlInitializationProperties
通过对SqlInitializationProperties的引用加上合理猜测定位SettingsCreator
根据引用定位SqlDataSourceScriptDatabaseInitializer
再看是谁负责加载SqlDataSourceScriptDatabaseInitializer. nice,that's DataSourceInitializationConfiguration,也就是说只要把DataSourceInitializationConfiguration加载进容器,就可以了。但是,发现这个类是包私有的,外部不能引用,好吧,那就再网上找一级,谁来负责加载DataSourceInitializationConfiguration
SqlInitializationAutoConfiguration,就是他,配置到容器即可
@SpringBootTest(classes = {SqlInitializationAutoConfiguration.class})