尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

3-8 spring boot如何集成mybatis?

3-8 spring boot如何集成mybatis? 背景小白师傅现在的java开发统一的都是spring boot使用原生mybatis或者springmybatis的都很少能否讲讲sprng boot怎么集成mybaits的集成的原理是什么扫地僧得益于spring boot各种开发好的startersspring boot集成mybatis相对容易。其中的原理则是利用Spring boot的自动注册原理来集成SqlSessionFactory最终在spring boot容器中生成各种mapper的bean。代码撸下看看就知道了。Spring Boot集成mybatis实例准备工作mysql数据库,本实例的版本为:8.0.16mysql客户端SQLyog(免费不需要注册码)或者navicat for mysql创建数据库davidwang456和表CREATEdatabase davidwang456;use davidwang456;DROPTABLEIFEXISTSstudent;CREATETABLEstudent(idint(11)NOTNULLAUTO_INCREMENT,first_namevarchar(100)DEFAULTNULL,last_namevarchar(100)DEFAULTNULL,ageint(11)DEFAULTNULL,PRIMARYKEY(id))ENGINEInnoDBDEFAULTCHARSETutf8mb4;mock数据INSERTINTOstudent(id,first_name,last_name,age)VALUES(1,wang1,david1,21);INSERTINTOstudent(id,first_name,last_name,age)VALUES(2,wang2,david2,22);INSERTINTOstudent(id,first_name,last_name,age)VALUES(3,wang3,david3,23);INSERTINTOstudent(id,first_name,last_name,age)VALUES(4,wang4,david4,24);INSERTINTOstudent(id,first_name,last_name,age)VALUES(5,wang5,david5,25);INSERTINTOstudent(id,first_name,last_name,age)VALUES(6,wang6,david6,26);INSERTINTOstudent(id,first_name,last_name,age)VALUES(7,wang7,david7,27);INSERTINTOstudent(id,first_name,last_name,age)VALUES(8,wang8,david8,28);创建maven项目添加依赖pom.xml?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.5.1/version relativePath/ !-- lookup parent from repository -- /parent groupIdcom.davidwang456.integrate/groupId artifactIdSpringBootIntegrateMybatis/artifactId version3.8.0-SNAPSHOT/version nameSpringBootIntegrateMybatis/name descriptionSpring Boot integrate mybatis/description properties java.version1.8/java.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.1.3/version /dependency dependency groupIdcom.zaxxer/groupId artifactIdHikariCP/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.16/version scopeprovided/scope /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /project实体数据库实体packagecom.davidwang456.mybatis.integrate;importjava.io.Serializable;importlombok.Data;DatapublicclassStudentDTOimplementsSerializable{privatestaticfinallongserialVersionUID1L;//字段privateIntegerid;privateStringfirstName;privateStringlastName;privateIntegerage;OverridepublicStringtoString(){returnstudent [idid, firstNamefirstName, lastNamelastName, ageage];}}查询实体packagecom.davidwang456.mybatis.integrate;importlombok.Data;DatapublicclassStudentQueryDTO{//字段privateIntegerid;privateStringfirstName;privateStringlastName;privateIntegerage;//排序列privateStringsort;//排序 DESC|ASCprivateStringorderBy;}配置数据库配置application.propertiesmybatis.mapper-locationsclasspath:mapper/*.xml mybatis.configuration.map-underscore-to-camel-casetrue mybatis.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl spring.datasource.urljdbc:mysql://localhost:3306/davidwang456?characterEncodingUTF-8useSSLfalseuseLegacyDatetimeCodefalseserverTimezoneUTC spring.datasource.usernameroot spring.datasource.passwordwangwei456 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # Hikari will use the above plus the following to setup connection pooling spring.datasource.typecom.zaxxer.hikari.HikariDataSource spring.datasource.hikari.minimum-idle5 spring.datasource.hikari.maximum-pool-size15 spring.datasource.hikari.auto-committrue spring.datasource.hikari.idle-timeout30000 spring.datasource.hikari.pool-nameHikariCP spring.datasource.hikari.max-lifetime1800000 spring.datasource.hikari.connection-timeout30000其中配置mybatis.configuration.map-underscore-to-camel-casetrue定义了支持驼峰形式配置mybatis.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl定义了日志打印的类类似与xml配置settingssettingnamelogImplvalueSTDOUT_LOGGING/settingnamemapUnderscoreToCamelCasevaluetrue//settings在src/main/resources目录下定义**mapper.xml文件。?xml version1.0 encodingUTF-8?!DOCTYPEmapperPUBLIC-//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtdmappernamespacecom.davidwang456.mybatis.integrate.StudentMapperselectidgetStudentInfoByConditionparameterTypecom.davidwang456.mybatis.integrate.StudentQueryDTOresultTypecom.davidwang456.mybatis.integrate.StudentDTOuseCachefalsebindnamefirstvalue%firstName%/bindnamelastvalue%lastName%/select id, first_name , last_name , age from student where 11iftestid!nulland id#{id}/ififtestfirstName!null and firstName!and first_name like #{first}/ififtestlastName!null and lastName!and last_name like #{last}/ififtestage!null and age!0and age#{age}/if/select/mapperMapper文件packagecom.davidwang456.mybatis.integrate;importjava.util.List;importorg.apache.ibatis.annotations.Mapper;MapperpublicinterfaceStudentMapper{publicListStudentDTOgetStudentInfoByCondition(StudentQueryDTOstudentQueryDTO);}测试程序packagecom.davidwang456.mybatis.integrate;importjava.util.List;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.ResponseBody;ControllerpublicclassTestController{AutowiredprivateStudentMapperstudentMapper;PostMapping(/list)ResponseBodypublicListStudentDTOlist(RequestBodyStudentQueryDTOstudentQueryDTO){returnstudentMapper.getStudentInfoByCondition(studentQueryDTO);}}启动spring主程序packagecom.davidwang456.mybatis.integrate;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplicationpublicclassSpringBootIntegrateMybatisApplication{publicstaticvoidmain(String[]args){SpringApplication.run(SpringBootIntegrateMybatisApplication.class,args);}}此时默认启动端口8080.使用postman进行测试curl--location--requestPOSThttp://127.0.0.1:8080/list \--header Content-Type:application/json \--data-raw {id:null,firstName:wang,lastName:david,age:null}返回结果符合预期:[{id:1,firstName:wang1,lastName:david1,age:21},{id:2,firstName:wang2,lastName:david2,age:22},{id:3,firstName:wang3,lastName:david3,age:23},{id:4,firstName:wang4,lastName:david4,age:24},{id:5,firstName:wang5,lastName:david5,age:25},{id:6,firstName:wang6,lastName:david6,age:26},{id:7,firstName:wang7,lastName:david7,age:27},{id:8,firstName:wang8,lastName:david8,age:28}]至此spring boot集成mybatis就完成了。如果是老系统升级到spring boot则可以利用配置属性mybatis.config-location来定义MyBatis.xml配置文件。其它mybatis的属性可自行参考。接下来我们看看spring boot集成mybatis的内部原理吧。spring boot集成mybatis的内部原理我们接下来说springboot是如何和mybatis进行整合的1.首先springboot中使用mybatis需要用到mybatis-spring-boot-start可以理解为mybatis开发的整合springboot的jar包有一个关键点先说明前面也提到过不管是mybatis和spring整合还是和springboot整合都需要做两个操作1.把当前接口和对应的mapperProxyFactory存入到knownMappers中2.把sql包装成mappedStatement存入到mappedStatements这个map中1.springboot项目中SpringbootApplication注解上有一个EnableAutoConfiguration注解而EnableAutoConfiguration注解又利用了Import注解注入了一个ImportSelector的实现类 AutoConfigurationImportSelector.class2.AutoConfigurationImportSelector在selectImports()方法中有一行重要的代码List configurations SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());这行代码内部会从所有jar包中META-INF/spring.factories文件中加载EnableAutoConfiguration对应的实现类那mybatis-spring-boot-autoconfigure.jar包中配置了两个实现类1 org.springframework.boot.autoconfigure.EnableAutoConfiguration\ 2 org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\ 3 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration3.我们来说 MybatisAutoConfiguration.class1 org.springframework.context.annotation.Configuration 2 ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }) 3 ConditionalOnSingleCandidate(DataSource.class) 4 EnableConfigurationProperties(MybatisProperties.class) 5 AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) 6 public class MybatisAutoConfiguration implements InitializingBean { 7 8 9 }这里有一个点就是 EnableConfigurationProperties(MybatisProperties.class)点开MybatisProperties.class文件会发现这里面声明的就是在application.properties配置文件中mybatis提供的配置信息比如mybatis.mapper-locationsclasspath:mapping/*Mapper.xml这个点不细说了后面可能会写一篇自定义starter的学习笔记到时候 再详细写4.在MybatisAutoConfiguration中有一个静态内部类 AutoConfiguredMapperScannerRegistrar 实现了ImportBeanDefinitionRegistrar;所以spring在refresh的时候会执行这个类的 registerBeanDefinitions()方法将 MapperScannerConfigurer存到了beanDefinitionMap中1 Override 2 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 3 4 5 if (!AutoConfigurationPackages.has(this.beanFactory)) { 6 logger.debug(Could not determine auto-configuration package, automatic mapper scanning disabled.); 7 return; 8 } 9 //中间删除了部分代码 10 registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition()); 11 }5.MapperScannerConfigurer是BeanDefinitionRegistryPostProcessor的实现类在refresh() -- invokeBeanFactoryPostProcessors(beanFactory)中会遍历所有beanFactoryPostProcessor和BeanDefinitionRegistrtPostProcessor的实现类依次执行postProcessorBeanDefinitionRegistrar()方法MapperScannerConfigurer的postProcessBeanDefinitionRegistry()方法会执行扫描方法这里的扫描方法和mapperScannerRegistrar的registerBeanDefinitions中的doScan是一样的这里扫描的包是在初始化MapperScannerConfigurer的时候在执行完属性注入之后调用了截图中的方法把当前pvs中的basePackage传到MapperScannerConfigurer中这里是如何传过去的待研究6.在将mapper扫描完之后需要进行sql的解析在和springboot整合之后需要在配置文件中配置当前要扫描的mapper.xml文件mybatis.mapper-locationsclasspath:mapping/*Mapper.xml这里的mapperLocation,是在sqlSesionFactorybean中进行解析的在第3步中的自动配置类中通过Bean,注入了SqlSessionFactory,在sqlSessionFactory()方法最后会调用factoryBean.getObject()方法这里其实调用的就是SqlSessionFactory的getObject()方法1 Override 2 public SqlSessionFactory getObject() throws Exception { 3 if (this.sqlSessionFactory null) { 4 afterPropertiesSet(); 5 } 6 7 8 return this.sqlSessionFactory; 9 }从afterPropertiesSet()方法一直往下追会追到同类中的buildSqlSessionFactory()方法在这个方法中判断如果当前mapperlocation不为null就进行解析1 if (this.mapperLocations ! null) { 2 if (this.mapperLocations.length 0) { 3 LOGGER.warn(() - Property mapperLocations was specified but matching resources are not found.); 4 } else { 5 for (Resource mapperLocation : this.mapperLocations) { 6 if (mapperLocation null) { 7 continue; 8 } 9 try { 10 XMLMapperBuilder xmlMapperBuilder new XMLMapperBuilder(mapperLocation.getInputStream(), 11 targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments()); 12 xmlMapperBuilder.parse(); 13 } catch (Exception e) { 14 throw new NestedIOException(Failed to parse mapping resource: mapperLocation , e); 15 } finally { 16 ErrorContext.instance().reset(); 17 } 18 LOGGER.debug(() - Parsed mapper file: mapperLocation ); 19 } 20 } 21 }在xmlMapperBuilder.parse()就是原生mybatis在解析xml文件时需要调用的方法7.在service中注入mapper接口在初始化service注入依赖的mapper接口时还是调用的mapperFactorybean.getObject()方法来获取代理对象springboot整合mybatis 和 springmybatis整合时解析xml文件有一个区别spring-mybatis是利用mapperFactorybean的checkDao()方法来解析xmlput数据到mappedStatement和knowmappersspringboot是利用SqlSessionFactoryBean的getObject()来解析xml,put数据到mappedStatement和knowMappers
返回列表