SpringBoot | 3.2 整合MyBatis
- 2021 年 8 月 8 日
- 筆記
- SpringBoot學習筆記, 學習筆記
前言
通過前一篇的學習,我們知道可以使用JDBC操作資料庫,但在實際生產中,我們一般使用MyBatis。在本篇,可以學習到SpringBoot如何整合MyBatis框架,以及相關自動配置原理。
MyBatis是目前Java持久層最為主流的技術之一,它可以避免幾乎所有的JDBC程式碼和手動設置參數以及獲取結果集。同時,MyBatis是基於一種SQL到POJO的模型,需要我們提供SQL、映射關係以及POJO。由於本筆記為SpringBoot系列筆記,故重點放在SpringBoot整合使用MyBatis。
註:在說明註解時,第一點加粗為註解中文含義,第二點為一般加在哪身上,縮進或程式碼塊為示例,如:
@註解
- 中文含義
- 加在哪
- 其他……
語句示例
//程式碼示例
1. 導入MyBatis場景
在SpringBoot中有兩種導入場景方式,一種是初始化導向,另一種是手動導入。
*這裡需要與前文的兩種配置方式做區別:筆者的導入指往應用中添加相應場景,注重一個從0到1的過程;而前文Druid連接池的兩種配置方式雖然也有導入的意思,但更加註重導入後的配置過程,是一個從1到2的過程。
1.1 初始化導向
初始化導向指在新建SpringBoot項目工程時進行導入:
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差不多,我們可以通過源碼分析得出可以自己配置哪些屬性,以及配置這些屬性時的前綴。
加入MyBatis場景後,我們可以發現該場景里有:
通過前面的文章,我們知道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是MyBatis操作的核心,是一個功能性程式碼,通常使用單例模式(在MyBatis的生命周期中只存在一個
-
SqlSession:自動配置了
SqlSessionTemplate
,可以生成SqlSession
; -
@Import(AutoConfiguredMapperScannerRegistrar.class):導入的類里有定義如何操作
@Mapper
註解的介面;- @Mapper: 只要寫的操作MyBatis的介面標註了
@Mapper
就會被自動掃描進容器。
- @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-location
與mapper-locations
不能同在,理由如下: - 當需要使用mybatis-config.xml配置文件的時需要配置
config-location
,config-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映射關係在哪,除了用介面方式外,還可以:
- 通過
MapperFactoryBean
裝配MyBatis; - 使用
MapperScannerConfigurer
; - 使用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"
"//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"
"//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
註解。
最後
