前言:
一、自动配置
当Spring Boot应用从主方法main()启动后,首先加载Spring Boot注解类@SpringBootApplication。
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
在该类里加载注解类@EnableAutoConfiguration。
在EnableAutoConfiguration类使用注解类@Import导入了AutoConfigurationImportSelector自动配置选择器类来加载其他可自动配置的组件,步骤如下:
1、AutoConfigurationImportSelector自动配置选择器调用getCandidateConfigurations方法,方法中SpringFactoriesLoader类通过loadFactoryNames方法扫描获取各jar包类路径下的META-INF/spring.factories文件
2、将扫描到的META-INF/spring.factories文件封装成Properties对象
3、遍历Properties对象,从中取出属性名org.springframework.boot.autoconfigure.EnableAutoConfiguration.EnableAutoConfiguration对应的值,值就为当前Jar包需Spring Boot加载的配置类,加载到容器中,并根据配置条件实例化配置类中的类对象
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//扫描META-INF/spring.factories文件
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
//通过spring.factories文件Url封成Properties对象
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
来看下mybatis-plus-boot-starter包下的META-INF/spring.factories文件
文件中只有一条配置属性值,对应的自动配置类为MybatisPlusAutoConfiguration。至此,MyBatis-Plus是如何被自动配置并加载容器介绍到这里,后续会讲解Spring Boot时会更细致自动配置原理,各位同伴们继续关注。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
二、通用CRUD
上一章节,我们准备了一个sql脚本,执行脚本后创建t_sys_log表,表结构可以查看上一章节。接着我们在项目中创建对应entity类和mapper接口
1. 目录结构如下
2. 实体类SysLog属性如下
public class SysLog implements Serializable {
private int logId;
private Integer optionType;
private String optionPerson;
private String optionContent;
private String optionIp;
private String optionStatus;
private String errorInfo;
private Date optionTime;
//get与set方法
3. 在SysLogMapper接口中继承MyBatis-Plus包中BaseMapper接口,接口定义泛型,使用SysLog类
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface SysLogMapper extends BaseMapper<SysLog> {
}
4. 注入mapper接口,需要将mapper实例到Spring容器中,在这三种方式
- 在Spring Boot主方法类上加上@MapperScan("com.banxun.demo.mapper"),配置mapper接口所在包路径,自动扫描此路径下的mapper接口
@SpringBootApplication @MapperScan("com.banxun.demo.mapper") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
- 直接在mapper接口上加入@Mapper注解
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysLogMapper extends BaseMapper<SysLog> {
}
- 在项目中新建config目录,再新建MybatisConfig配置类,使用注解@Configuration定义此类为配置类,使用注解注解@Bean。容器启动时,创建MapperScannerConfigurer对象,设置basePackage属性值为mapper接口的包路径
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MybatisConfig { @Bean public MapperScannerConfigurer MapperScannerConfigurer(){ MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer(); scannerConfigurer.setBasePackage("com.banxun.demo.mapper"); return scannerConfigurer; } }
三、测试通用CRUD
1、插入数据
在junit测试类中注入SysLogMapper,编写如下代码插入一条日志记录,执行junit测试方法
@RunWith(SpringRunner.class)
@SpringBootTest
public class BootApplicationTests {
@Autowired
private SysLogMapper sysLogMapper;
@Test
public void contextLoads() {
SysLog sysLog = new SysLog();
sysLog.setOptionTime(new Date());
sysLog.setOptionType(1);
sysLog.setOptionContent("测试mybatis-plus");
sysLogMapper.insert(sysLog);
}
}
问题1: Error updating database. Cause: java.sql.SQLSyntaxErrorException: Table 'wechat.sys_log' doesn't exist
执行完成控制台输出打印上面的异常信息,报sys_log表不存在,而我们创建的表名为t_sys_log,有前缀"t_"。在现在配置下,MyBatis-Plus默认自动按驼峰结构类名进行映射成带下划线_隔离的表名,解决此问题有两种方法:
- 在实体类名SysLog上加@TableName注解指定映射表名
@TableName("t_sys_log")
public class SysLog implements Serializable {
- 在配置文件application.properties添加全局配置属性统一处理未注解指定表名实体类映射表名时加入前缀"t_"
mybatis-plus.global-config.db-config.table-prefix=t_
问题2: Cause: java.sql.SQLSyntaxErrorException: Unknown column 'log_id' in 'field list'
根据问题1配置完成后再次执行junit测试方法,控制台输出打印上面的异常信息,报log_id列不存在。在t_sys_log表中,主键名为f_log_id,这里同样缺少字段前缀,解决方法有两种:
- 属性名上加@TableField("字段名")注解指定映射字段名,主键字段使用@TableId("字段名")注解
- 通过配置文件application.properties添加全局配置属性统一处理,%s对应自动映射字段名
mybatis-plus.global-config.db-config.column-format=f_%s
问题3:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Could not set property 'logId' of 'class com.banxun.demo.entity.SysLog' with value '1164549971505057794' Cause: java.lang.IllegalArgumentException: argument type mismatch
配置完问题2后,控制台输出再次打印上面的异常信息。此问题原因是插入数据时MyBatis-Plus为主键生成的Id值过长,需要配置主键生成策略。这问题解决也有两种方式:
- 在主键性加上@TableId(value = "f_log_id", type = IdType.AUTO),IdType有六个选项值,默认ID_WORKER,我们表使用键值自动递增,所以选AUTO
public enum IdType {
AUTO(0), //数据库自增
NONE(1), //无状态
INPUT(2), //自行输入
ID_WORKER(3), //分布式全局唯一ID 长整型类型
UUID(4), //32位UUID字符串
ID_WORKER_STR(5); //分布式全局唯一ID 字符串类型
在配置文件application.properties添加全局配置属性统一处理
mybatis-plus.global-config.db-config.id-type=auto
经过前面的配置后,junit方法执行成功,在库中插入了一条日志记录
2、查询数据
- 根据id查询
@Test
public void contextLoads() {
SysLog sysLog = sysLogMapper.selectById(173);
System.out.println(sysLog.getOptionContent());
}
控制台打印输入前面插入的日志内容信息
2019-08-22 23:16:00.489 INFO 5112 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
_ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\
/ |
3.1.2
2019-08-22 23:16:00.867 INFO 5112 --- [ main] com.banxun.demo.DemoApplicationTests : Started DemoApplicationTests in 2.204 seconds (JVM running for 3.16)
测试mybatis-plus
2019-08-22 23:16:01.132 INFO 5112 --- [ Thread-2] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2019-08-22 23:16:01.317 INFO 5112 --- [ Thread-2] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
- 根据内容模糊查询,这使用QueryWrapper条件构造器进行条件查询
@Test
public void contextLoads() {
QueryWrapper<SysLog> queryWrapper = new QueryWrapper<>();
queryWrapper.like("f_option_content", "plus");
List<SysLog> sysLogs = sysLogMapper.selectList(queryWrapper);
for (SysLog sysLog : sysLogs) {
System.out.println(sysLog.getOptionContent());
}
}
3、更新数据
@Test
public void contextLoads() {
SysLog sysLog = new SysLog();
sysLog.setLogId(173);
sysLog.setOptionContent("测试Spring Boot + MyBatis-Plus");
sysLogMapper.updateById(sysLog);
}
执行完成后,我们再通过上面根据id查询,可以看到控制台打印输入更新的日志内容信息
2019-08-22 23:26:57.358 INFO 22964 --- [ main] com.banxun.demo.DemoApplicationTests : Starting DemoApplicationTests on LAPTOP-6AQTBBR1 with PID 22964 (started by karanatarm in E:\ideaplace\demo)
2019-08-22 23:26:57.359 INFO 22964 --- [ main] com.banxun.demo.DemoApplicationTests : No active profile set, falling back to default profiles: default
2019-08-22 23:26:58.369 INFO 22964 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2019-08-22 23:26:58.813 INFO 22964 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
_ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\
/ |
3.1.2
2019-08-22 23:26:59.167 INFO 22964 --- [ main] com.banxun.demo.DemoApplicationTests : Started DemoApplicationTests in 2.087 seconds (JVM running for 3.044)
测试Spring Boot + MyBatis-Plus
2019-08-22 23:26:59.456 INFO 22964 --- [ Thread-2] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2019-08-22 23:26:59.518 INFO 22964 --- [ Thread-2] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
4、删除数据
@Test
public void tes() {
SysLog sysLog = new SysLog();
sysLog.setLogId(173);
sysLogMapper.deleteById(sysLog);
}
执行完成后,我们再根据id查询,可以看到控制台没有打印输入日志内容
四、小结
本章节介绍MyBatis-Plus如何自动配置、CRUD基础配置以及测试CRUD操作。一起学习的同伴们应该对MyBatis-Plus的CRUD意犹未尽。接下来的章节我们在一起学习MyBatis-Plus的进阶CRUD操作,结合JDK8新特性的lambda方式的条件结构查询及相关配置。