基於前文"Spring Boot初步學習02"(點擊前往查看),已經學習了Spring框架整合鏈接池的部分,鏈接池就是用於與數據庫鏈接的工具,那麼本文就繼續講解與數據庫交互的部分---整合Mybatis框架.java
MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,而且更名爲MyBatis 。2013年11月遷移到Github。spring
iBATIS一詞來源於「internet」和「abatis」的組合,是一個基於Java的持久層框架。iBATIS提供的持久層框架包括SQL Maps和Data Access Objects(DAOs)sql
以上是百度中對於Mybatis框架的概述,在我理解來講,Mybatis框架是如今較爲優秀,使用較爲普遍的一個持久層框架,底層時基於JDBC去實現與數據庫的交互,而且在使用的過程當中,能夠靈活去編寫SQL語句,而且對於JDBC作了優化與封裝,框架較小型,但很適用.數據庫
現在項目中使用Mybatis框架時,一般是由Spring框架進行整合,去實現數據交互操做,接下來就來講一下在Spring Boot中如何整合Mybatis.apache
測試類<-->mybatis<-->JDBC<-->Driver<-->數據庫segmentfault
須要注意的是:環節之間都是耦合於接口的,這樣的設計更加靈活,更低耦合易維護修改.數組
首先須要建立Spring Boot項目,建立過程可見Spring Boot快速入門案例.安全
固然若是已經有建立好的項目直接使用便可.springboot
添加依賴時,主要參考官網 mybatis.org/spring ,在springboot菜單中找到啓動依賴,複製粘貼至pom.xml中mybatis
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency>
另外一種方式:右鍵項目中pom.xml-->spring-->Edit Starters-->搜索Mybatis,添加依賴.
但要注意:springboot並無爲mybatis指定版本,以這種方式添加依賴,須要本身指定版本.
Spring Boot特色就是零配置或簡單配置,在mybatis官網中,雖然提供了一些配置,可是也都是可選的,不配置也能夠正常運行,這裏建議配置幾點
#spring.mybatis mybatis.configuration.default-statement-timeout=30 mybatis.configuration.map-underscore-to-camel-case=true logging.level.com.cy=DEBUG
前兩個配置分別是:設置sql超時時間以及將數據庫中的user_name(這類下劃線命名)自動轉換爲userName(Java中的駝峯命名)
第三個配置是mybatis中的sql日誌的輸出:其中com.cy爲我項目中的根包.
到這裏關於mybatis與Springboot的整合就已經完成了,很方便簡單,後面是一些基礎業務的實現.
首先要建立數據層接口,代碼以下:
@Mapper public interface GoodsDao {}
其中@Mapper註解是由Mybatis提供,描述數據層接口的的註解,用於告訴Spring框架此接口的實現由mybatis建立,並將其實現類對象存儲到spring容器,交由spring管理.
須要在數據層接口中,編寫實際運行的業務方法,代碼以下:
@Mapper public interface GoodsDao { /** * 基於商品id執行刪除業務 * @param id * @return 刪除的行數 */ @Delete("delete from tb_goods where id=#{id}") public int deleteById(Integer id); }
這種業務方法的編寫模式,是將簡單的sql語句經過註解的形式進行定義,寫在方法上進行描述,可是複雜的sql語句仍是要寫在映射文件中(xml文件中).
首先須要說的是,在測試類中咱們聲明屬性時只經過@Autowired註解聲明接口(@Mapper描述的接口)不寫實現類,是因爲基於咱們已經將springboot和mybatis整合,實現類會由mybatis建立再交由spring框架進行依賴注入(DI),因此咱們只要"面向接口"便可,實際建立由框架替咱們操心.
另外,若是你想要去肯定框架建立的實現類到底是什麼呢?
能夠經過打樁(System.out.println(goodsDao.getClass().getName());)或是加斷點的方式獲得答案.
測試類代碼以下:
@SpringBootTest public class GoodsDaoTests { @Autowired private GoodsDao goodsDao; @Test public void testDeleteById() { int rows = goodsDao.deleteById(10); System.out.println("rows="+rows); } }
測試類是經過建立的實現類對象去調用@Mapper接口的業務方法,實現對數據庫的操做.
上文中也有提到複雜的sql語句仍是要寫在映射文件中(xml文件中)利用動態SQL進行映射的,這個案例就要實際操做一下.
首先建立xml映射文件,springboot項目中有嚴格的目錄分類,須要將xml文件放在src/main/resource目錄下,咱們能夠再建立mapper/goods目錄,而後將咱們的GoodsMapper.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>標籤並在其中添加sql標籤及其語句,此案例是根據ID批量刪除,代碼以下:
<mapper namespace="com.cy.pj.goods.dao.GoodsDao"> <delete id="deleteObjects"> delete from tb_goods where id in <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach> </delete> </mapper>
在@Mapper接口中定義批量刪除多個元素的方法,代碼以下:
@Mapper public interface GoodsDao { /** * 基於多個商品id刪除 * @param ids * @return 刪除的行數 */ public int deleteObjects(@Param("ids")Integer... ids); }
方法中傳參爲"(@Param("ids")Integer... ids)",這是可變參數,能夠理解爲一類特殊的數組,能夠傳入0/1/2...n個數均可.通常最新版本的mybatis能夠不加"@Param("ids")"這部分.
注意:xml文件中的namespace與接口的全限定類名對應,SQL標籤的ID要與對應的接口方法名對應.
如今咱們已經寫好了映射文件,以及接口方法,可若是有多個xml文件,spring框架如何知道那個是咱們要它進行管理的呢?
就須要在application.properties配置文件中添加配置以下:
mybatis.mapper-locations=classpath:/mapper/*/*.xml
"*"爲通配符,意味全部的,咱們的xml映射文件路徑是在根目錄下的mapper/goods/GoodsMapper.xml,就在配置的範圍內.
在src/test/java目錄下編寫測試類,代碼以下:
@SpringBootTest public class GoodsDaoTests { @Autowired private GoodsDao goodsDao; @Test public void testDeleteObjects() { int rows = goodsDao.deleteObjects(6,7,8,9); System.out.println("rows="+rows); } }
底層的執行順序是:
測試方法執行時,咱們調用接口實現類的方法,實現類內部會檢測接口方法上是否有定義sql映射;假如沒有會基於接口類全名找到對應的配置的映射文件,而後再基於方法名找到對應映射文件中的標籤,進而獲取sql映射.
以上已經完成了咱們的要求,可是在xml映射文件中寫複雜SQL語句時,咱們須要增強SQL語句的可靠性,尤爲是刪除語句,在對數據庫進行操做時,刪除語句永遠是咱們最須要當心的!
咱們須要考慮到傳入各類數據的狀況,如上文所寫的:
<mapper namespace="com.cy.pj.goods.dao.GoodsDao"> <delete id="deleteObjects"> delete from tb_goods where id in <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach> </delete> </mapper>
當咱們若是什麼都不傳時,SQL語句就變爲:delete from tb_goods where id in ;這樣就會報錯,因此咱們能夠添加動態SQL完善!以下:
<mapper namespace="com.cy.pj.goods.dao.GoodsDao"> <delete id="deleteObjects"> delete from tb_goods <if test="ids!=null and ids.length>0"> where id in <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach> </if> </delete> </mapper>
加入<if>標籤進行判斷,排除了傳入null的狀況,可是又發現ids不爲null時能夠正常執行,但若是ids爲null,沒進入判斷,SQL語句是沒有語法問題,可是執行就變爲:delete from tb_goods,刪除整個表,在工做中這就是鑄成大錯了!因此還須要進一步改進,以下再加入<where>標籤:
<mapper namespace="com.cy.pj.goods.dao.GoodsDao"> <delete id="deleteObjects"> delete from tb_goods <where> <if test="ids!=null and ids.length>0"> id in <!-- (1,2,3,4) --> <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach> </if> or 1=2 </where> </delete> </mapper>
這樣就解決了全部狀況能夠安全使用了.