SpringBoot | 3.2 整合MyBatis


前言

经过前一篇的学习,咱们知道可使用JDBC操做数据库,但在实际生产中,咱们通常使用MyBatis。在本篇,能够学习到SpringBoot如何整合MyBatis框架,以及相关自动配置原理。java

MyBatis是目前Java持久层最为主流的技术之一,它能够避免几乎全部的JDBC代码和手动设置参数以及获取结果集。同时,MyBatis是基于一种SQL到POJO的模型,须要咱们提供SQL、映射关系以及POJO。因为本笔记为SpringBoot系列笔记,故重点放在SpringBoot整合使用MyBatis。spring

注:在说明注解时,第一点加粗为注解中文含义,第二点为通常加在哪身上,缩进或代码块为示例,如:sql

@注解数据库

  • 中文含义
  • 加在哪
  • 其余……
    • 语句示例
    //代码示例

1. 导入MyBatis场景

在SpringBoot中有两种导入场景方式,一种是初始化导向,另外一种是手动导入。springboot

*这里须要与前文的两种配置方式作区别:笔者的导入指往应用中添加相应场景,注重一个从0到1的过程;而前文Druid链接池的两种配置方式虽然也有导入的意思,但更加注重导入后的配置过程,是一个从1到2的过程。mybatis

1.1 初始化导向

初始化导向指在新建SpringBoot项目工程时进行导入:
MyBatis的初始化导向app

1.2 手动导入

手动导入只须要在SpringBoot的pom.xml文件里添加下面场景便可:框架

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

2. *MyBatis自动配置原理

MyBatis的自动配置原理跟Druid差很少,咱们能够经过源码分析得出能够本身配置哪些属性,以及配置这些属性时的前缀。ide

加入MyBatis场景后,咱们能够发现该场景里有:
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

    • SqlSession是MyBatis操做的核心,是一个功能性代码,一般使用单例模式(在MyBatis的生命周期中只存在一个SqlSessionFactory);
  • SqlSession:自动配置了SqlSessionTemplate,能够生成SqlSession

  • @Import(AutoConfiguredMapperScannerRegistrar.class):导入的类里有定义如何操做@Mapper注解的接口;

    • @Mapper: 只要写的操做MyBatis的接口标注了@Mapper就会被自动扫描进容器。

MyBatis配置内容结构


3. 全局配置文件

全局配置文件的书写方式有三种,分别是配置模式、注解模式以及混合模式。在配置以前,咱们须要作些准备工做,让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-locationmapper-locations不能同在,理由以下:
    • 当须要使用mybatis-config.xml配置文件的时须要配置config-locationconfig-location的做用是肯定mybatis-config.xml文件位置;而mapper-locations是用来注册xxxmapper.xml文件。若是使用了mybatis-config.xml,而且里面配置了mapper,那就不须要mapper-locations
  • 编写mapper接口,使用标准@Mapper注解( 也能够在启动类上加上@MapperScan替换@Mapper )

@Mapper

  • 映射配置

  • 用在接口类上

  • 在接口类上添加了@Mapper,在编译以后会生成相应的接口实现类;

  • 若是有多组接口须要编译成实现类,须要在每一个接口上标注一个@Mapper;

    @Mapper
    public interface UserDAO {
       //代码
    }

@MapperScan

  • 映射扫描配置

  • 用在主启动类下;

  • 指定要变成实现类的接口所在的包,而后包下面的全部接口在编译以后都会生成相应的实现类;

  • 将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映射关系在哪,除了用接口方式外,还能够:

  1. 经过MapperFactoryBean装配MyBatis;
  2. 使用MapperScannerConfigurer
  3. 使用MyBatis接口(由于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);
    }
}

3.1 配置模式

配置模式步骤以下。

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>

3.2 注解模式

注解模式步骤以下(自上而下分析,从数据层到表示层)。

@Select

  • 选择
  • 标注在mapper接口上;
  • 用来代替原来xml里的<select>标签,参数为原生的sql;

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);
    }
}

3.3 混合模式

混合模式步骤以下(自上而下分析,从数据层到表示层)。

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);
}

@Insert

  • 插入语句
  • 用在mapper接口上;
  • 用来代替原来xml里的 标签,参数为原生的插入insert相关的sql;

@Options

  • 选择的参数
  • 用在mapper接口上;
  • 用来代替原来xml里的 标签的参数配置,参数为相关的配置属性;
  • useGeneratedKeys表示使用自增主键,能够返回自增主键值;keyProperty表示自增属性的id。

4 MyBatis的分页插件功能

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";
}

5 总结

SpringBoot整合MyBatis的方法以下:

  • 引入mybatis-starter
  • 配置application.yaml中,指定mapper-location位置便可;
  • 编写Mapper接口并标注@Mapper注解;
    • 简单方法直接注解方式;
    • 复杂方法编写mapper.xml进行绑定映射;
  • @MapperScan("com.dlhjw.admin.mapper") 简化,其余的接口就能够不用标注@Mapper注解。


最后

新人制做,若有错误,欢迎指出,感激涕零!
欢迎关注公众号,会分享一些更平常的东西!
如需转载,请标注出处!
相关文章
相关标签/搜索