经过前一篇的学习,咱们知道可使用JDBC操做数据库,但在实际生产中,咱们通常使用MyBatis。在本篇,能够学习到SpringBoot如何整合MyBatis框架,以及相关自动配置原理。java
MyBatis是目前Java持久层最为主流的技术之一,它能够避免几乎全部的JDBC代码和手动设置参数以及获取结果集。同时,MyBatis是基于一种SQL到POJO的模型,须要咱们提供SQL、映射关系以及POJO。因为本笔记为SpringBoot系列笔记,故重点放在SpringBoot整合使用MyBatis。spring
注:在说明注解时,第一点加粗为注解中文含义,第二点为通常加在哪身上,缩进或代码块为示例,如:sql
@注解数据库
语句示例
//代码示例
在SpringBoot中有两种导入场景方式,一种是初始化导向,另外一种是手动导入。springboot
*这里须要与前文的两种配置方式作区别:笔者的导入指往应用中添加相应场景,注重一个从0到1的过程;而前文Druid链接池的两种配置方式虽然也有导入的意思,但更加注重导入后的配置过程,是一个从1到2的过程。mybatis
初始化导向指在新建SpringBoot项目工程时进行导入:
app
手动导入只须要在SpringBoot的pom.xml文件里添加下面场景便可:框架
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency>
MyBatis的自动配置原理跟Druid差很少,咱们能够经过源码分析得出能够本身配置哪些属性,以及配置这些属性时的前缀。ide
加入MyBatis场景后,咱们能够发现该场景里有:
spring-boot
经过前面的文章,咱们知道SpringBoot会先找到对应场景的自动配置类,在这里是MybatisAutoConfiguration
@Configuration @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }) @ConditionalOnBean(DataSource.class) @EnableConfigurationProperties(MybatisProperties.class) // MyBatis配置项绑定类 @AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) public class MybatisAutoConfiguration { }
从源码中,咱们能够获得如下信息:
跟MybatisProperties
配置类绑定,
配置属性的前缀为 mybatis
@ConfigurationProperties(prefix = "mybatis") public class MybatisProperties
全局配置文件:使用Mybatis须要进行全局配置;
SqlSessionFactory: 用来生成SqlSession
;
SqlSessionFactory
);SqlSession:自动配置了SqlSessionTemplate
,能够生成SqlSession
;
@Import(AutoConfiguredMapperScannerRegistrar.class):导入的类里有定义如何操做@Mapper
注解的接口;
@Mapper
就会被自动扫描进容器。全局配置文件的书写方式有三种,分别是配置模式、注解模式以及混合模式。在配置以前,咱们须要作些准备工做,让SpringBoot知道咱们的配置文件写在哪里。
准备工做:
配置全局配置文件位置( 在application.yaml
中指定Mapper配置文件的位置,以及指定全局配置文件的信息,建议配置在mybatis.configuration
);
mybatis: #全局配置文件位置 config-location: classpath:mybatis/mybatis-config.xml #sql映射文件位置 mapper-locations: classpath:mybatis/mapper/*.xml #定义别名扫描的包,须要与@Alias联合使用 type-aliases-package: …… #具体类须要与@MappedJdbcTypes联合使用 type-handlers-package: …… #执行器(Executor),能够配置STMPLE、REUSE、BATCH、默认为STMPLE executor-type: …… configuration: #配置MyBatis插件(拦截器等) interceptors: …… #级联延迟加载配置属性 aggressive-lazy-loading: ……
config-location
与mapper-locations
不能同在,理由以下:config-location
,config-location
的做用是肯定mybatis-config.xml文件位置;而mapper-locations
是用来注册xxxmapper.xml文件。若是使用了mybatis-config.xml,而且里面配置了mapper,那就不须要mapper-locations
。编写mapper接口,使用标准@Mapper
注解( 也能够在启动类上加上@MapperScan
替换@Mapper )
映射配置;
用在接口类上
在接口类上添加了@Mapper,在编译以后会生成相应的接口实现类;
若是有多组接口须要编译成实现类,须要在每一个接口上标注一个@Mapper;
@Mapper public interface UserDAO { //代码 }
映射扫描配置;
用在主启动类下;
指定要变成实现类的接口所在的包,而后包下面的全部接口在编译以后都会生成相应的实现类;
将MyBatis所需的对应接口扫描到Spring IOC容器中;
能够解决@Mapper标注过多问题,直接在主启动类上加上一个@MapperScan便可;
@SpringBootApplication //@MapperScan("com.dlhjw.mapper") @MapperScan( //指定扫描包 basePackages = "com.dlhjw.mapper", //指定SqlSessionFactory,若是sqlSessionTemplate被指定,则做废 sqlSessionFactoryRef = "sqlSessionFactory", //指定sqlSessionTemplate,将忽略sqlSessionFactory的配置(优先级高) sqlSessionTemplateRef = “sqlSessionTemplate”, //限制扫描接口,不经常使用 //markerInterface = class.class, annotationClass = Repository.class ) public class SpringbootMybatisDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootMybatisDemoApplication.class, args); } }
【如下不经常使用、不推荐】 上述两个接口均可以让SpringBoot知道用户配置的MyBatis映射关系在哪,除了用接口方式外,还能够:
MapperFactoryBean
装配MyBatis;MapperScannerConfigurer
;SqlSessionFactory
是SpringBoot自动生成好了,因此直接拿来使用);上面两个接口可改为以下代码:(不经常使用、不推荐)
1. 经过MapperFactoryBean装配MyBatis:
@Autowired SqlSessionFactory sqlSessionFactory = null; //定义一个MyBatis的Mapper接口 @Bean public MapperFactoryBean<MyBatisUserDao> initMyBatisUserDao(){ MapperFactoryBean<MyBatisUserDao> bean = new MapperFactoryBean<>(); bean.setMapperInterface(UserDAO.class); bean.setSessionFactory(sqlSessionFactory); return beam; }
2. 使用MapperScannerConfigurer:
@Bean public MapperScannerConfigurer mapperScannerConfig(){ //定义扫描器实例 MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); //加载SqlSessionFactory,SpringBoot会自动生产,SqlSessionFactory实例 mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory"); //定义扫描的包 mapperScannerConfigurer.setBeanPackage("com.dlhjw.mapper"); //限定被标注@Repository的接口才被扫描 mapperScannerConfigurer.setAnnotationClass(Repository.class); //经过继承某个接口限制扫描,通常使用很少 //mapperScannerConfigurer.setMarkerInterface(....); return mapperScannerConfigurer; }
3. 使用MyBatis接口:
public interface MyBatisUserService{ public User getUser(Long id); }
@Service public class MyBatisUserServiceImpl implements MyBatisUserService{ //由于在启动文件application.yaml配置了对应接口,因此直接依赖注入便可 @Autowired private MyBatisUserDao myBatisUserDao = null; @Override public User getUser(Long id){ return myBatisUserDao.getUser(id); } }
配置模式步骤以下。
1. 导入mybatis官方starter;
2. 编写mapper接口,使用@Mapper
或@MapperScan
注解;
3. 配置全局配置文件(springboot自动配置好了);
在resources/mybatis/mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 开启驼峰命名匹配,或者在配置文件中配置 --> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> </configuration>
配置mybatis.configuration下面的全部,就是至关于改mybatis全局配置文件中的值;
mybatis: #注意:只能有一个全局配置,下面语句不能存在 # config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml configuration: map-underscore-to-camel-case: true #推荐
4. 配置映射文件(编写sql映射文件并绑定mapper接口);
使用Mapper接口绑定Xml
在resources/mybatis/mapper/AccountMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.dlhjw.admin.mapper.AccountMapper"> <!-- public Account getAcct(Long id) --> <select id="getAcct" resultType="com.dlhjw.admin.bean.Account"> select * from account_tbl where id=#{id} </select> </mapper>
注解模式步骤以下(自上而下分析,从数据层到表示层)。
1. 导入mybatis官方starter;
2. 编写mapper接口,使用@Mapper
或@MapperScan
注解;
3. 接口的方法上标注@Select
注解,代替原来xml里的<select>
标签;
@Mapper public interface CityMapper { @Select("select * from city where id=#{id}") public City getById(Long id); }
4. 在service层里编写业务方法;
public interface CityService { City getById(Long id); }
@Service public class CityServiceImpl implements CityService { @Autowired CityMapper cityMapper; public City getById(Long id){ return cityMapper.getById(id); } }
5. 在Controller层里编写表示层相关方法;
*Controller相关知识参考下章。
@Controller public class IndexController { @Autowired CityService cityService; @ResponseBody @GetMapping("/city") public City getCityById(@RequestParam("id") Long id){ return cityService.getById(id); } }
混合模式步骤以下(自上而下分析,从数据层到表示层)。
1. 导入mybatis官方starter;
2. 编写mapper接口,使用@Mapper
或@MapperScan
注解;
@Mapper public interface CityMapper { @Select("select * from city where id=#{id}") public City getById(Long id); public void insert(City city); }
3. 为insert方法配置xml文件;
<mapper namespace="com.atguigu.admin.mapper.CityMapper"> <!-- useGeneratedKeys:使用自增主键,能够返回自增主键值 keyProperty:自增属性的id --> <insert id="insert" useGeneratedKeys="true" keyProperty="id"> insert into city(`name`,`state`,`country`) values(#{name},#{state},#{country}) </insert> </mapper>
4. 在service层里编写业务方法;
public interface CityService { City getById(Long id); void saveCity(City city); }
@Service public class CityServiceImpl implements CityService { @Autowired CityMapper cityMapper; public City getById(Long id){ return cityMapper.getById(id); } public void saveCity(City city) { counter.increment(); cityMapper.insert(city); } }
5. 在Controller层里编写表示层相关方法;
*Controller相关知识参考下章。
@Controller public class IndexController { @Autowired CityService cityService; @ResponseBody @PostMapping("/city") public City saveCity(City city){ cityService.saveCity(city); return city; } @ResponseBody @GetMapping("/city") public City getCityById(@RequestParam("id") Long id){ return cityService.getById(id); } }
6. *将上述insert
用注解方式改为注解模式
*此步骤不是必要的。
@Mapper public interface CityMapper { @Insert("insert into city(`name`,`state`,`country`) values(#{name},#{state},#{country})") @Options(useGeneratedKeys = true,keyProperty = "id") public void insert(City city); }
useGeneratedKeys
表示使用自增主键,能够返回自增主键值;keyProperty
表示自增属性的id。SpringBoot能够集成MyBatis插件完成一些复杂的功能,分页插件相关配置以下。
1. 整合插件;
@Configuration public class MyBatisConfig { @Bean public MybatisPlusInterceptor paginationInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // 设置请求的页面大于最大页后操做, true调回到首页,false 继续请求 默认false // paginationInterceptor.setOverflow(false); // 设置最大单页限制数量,默认 500 条,-1 不受限制 // paginationInterceptor.setLimit(500); // 开启 count 的 join 优化,只针对部分 left join //这是分页拦截器 PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); paginationInnerInterceptor.setOverflow(true); paginationInnerInterceptor.setMaxLimit(500L); mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor); return mybatisPlusInterceptor; } }
2. 编写插件相关controller;
*Controller相关知识参考下章。
@GetMapping("/dynamic_table") public String dynamic_table(@RequestParam(value="pn",defaultValue = "1") Integer pn,Model model){ //构造分页参数 Page<User> page = new Page<>(pn, 2); //调用page进行分页 Page<User> userPage = userService.page(page, null); model.addAttribute("users",userPage); //重定向 return "table/dynamic_table"; }
SpringBoot整合MyBatis的方法以下:
mybatis-starter
;application.yaml
中,指定mapper-location
位置便可;Mapper
接口并标注@Mapper
注解;
mapper.xml
进行绑定映射;@MapperScan("com.dlhjw.admin.mapper")
简化,其余的接口就能够不用标注@Mapper
注解。