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註解。


最後

新人制做,若有錯誤,歡迎指出,感激涕零!
歡迎關注公衆號,會分享一些更平常的東西!
如需轉載,請標註出處!
相關文章
相關標籤/搜索