MyBatis入門知識匯總

  • 2020 年 5 月 19 日
  • 筆記

 為什麼要使用MyBatis?

  我們都知道,在學習mybatis之前,要在Java中操作資料庫,需要用到JDBC,但是在使用JDBC時會有許多缺陷。

比如:

  1、使用時需要先進行資料庫連接,不用後要立即釋放連接,這樣對資料庫進行頻繁連接和關閉,會造成資料庫資源浪費,同時並發量較大時,會影響資料庫性能。

  解決方案:為了達到連接復用,使用資料庫連接池管理資料庫連接。

  2、將sql語句硬編碼到java程式碼中,使得程式碼耦合度高,如果sql 語句修改,就需要重新編譯java程式碼,不利於系統維護。

  解決方案:將sql語句配置在xml配置文件中,即使sql變化,不需要對java程式碼進行重新編譯,只要在配置文件中修改。

  3、向preparedStatement中設置參數,對佔位符號位置和設置參數值,硬編碼在java程式碼中,不利於系統維護。

  解決方案:將sql語句及佔位符號和參數全部配置在xml中。

  4、從resutSet中遍歷結果集獲取數據時,必須保證屬性名正確,否則無法取出數據,因此將獲取表的欄位進行硬編碼,不利於系統維護。

  解決方案:將查詢的結果集,自動映射成java對象。

  下面是使用JBDC操作時的程式碼:

  為了方便我使用的是maven項目來編寫的,所以在剛開始時需要在pom.xml文件中添加資料庫的依賴

  <!--添加資料庫依賴-->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.32</version>
  </dependency>

  下面就是程式碼部分。

public class JDBC {
    public static void main(String[] args) {
        // 資料庫連接
        Connection connection = null;
        // 預編譯的Statement,使用預編譯的Statement提高資料庫性能
        PreparedStatement preparedStatement = null;
        // 結果集
        ResultSet resultSet = null;
        try{
            //載入mysql驅動
            Class.forName("com.mysql.jdbc.Driver");
            String URL="jdbc:mysql://localhost:3306/test";
            String USER="root";
            String PASS="123456";
            // 通過驅動管理類獲取資料庫鏈接
            connection=DriverManager.getConnection(URL,USER,PASS);
            // 定義sql語句 ?表示佔位符
            String sql="select * from student where SID=?";
            // 獲取預處理statement
            preparedStatement= connection.prepareStatement(sql);
            // 設置參數,第一個參數為sql語句中參數的序號(從1開始),第二個參數為設置的參數值
            preparedStatement.setString(1,"2");
            //返回結果集
            resultSet=preparedStatement.executeQuery();
            // 遍歷查詢結果集
            while (resultSet.next()) {
                System.out.println(resultSet.getString("Sname")+"   "+
                        resultSet.getString("Sage"));
            }
        }catch (Exception e){
            e.getMessage();
        }finally {
            //關閉連接
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

JDBC程式碼

  通過上述程式碼可以看出,sql語句和Java語句是混合在一塊編碼的,這大大更加了程式碼耦合度,這樣在修改sql語句時,都需要重新編譯Java程式碼,不利於系統維護。而且在實際開發中也經常會出現修改或優化sql語句的情況,所以之後人們便更多的使用MyBatis來進行操作資料庫。

一,MyBatis概述

  MyBatis 本是apache的一個開源項目iBatis,2010年6月由apache software foundation 遷移到了google code,並且改名為MyBatis,因為當時iBatis已經發布到3.x版本了,所以也可以理解為Mybatis實際就是ibatis 3.x的後續版。 

  MyBatis 是一款優秀的支援自定義 SQL 查詢存儲過程高級映射的持久層框架,消除了幾乎所有的 JDBC 程式碼和參數的手動設置以及結果集的檢索,使開發者只需要關注 SQL 本身,而不需要花費精力去處理例如註冊驅動、創建connection、創建statement、手動設置參數、結果集檢索等jdbc繁雜的過程程式碼。

  Mybatis通過xml或註解的方式將要執行的各種statement(statement、preparedStatemnt、CallableStatement)配置起來,並通過java對象和statement中的sql進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射成java對象並返回。

  另外MyBatis 支援聲明式數據快取 。當 SQL 語句被標記為「可快取」後,首次執行它時從資料庫獲取的所有數據會被存儲在高速快取中,後面再執行這條語句時就會從高速快取中讀取結果,而不是再次命中資料庫,MyBatis 提供了默認情況下基於 Java的HashMap 快取實現,以及用於與 OSCache Ehcache Hazeleast Memcached 連接的默認連接器,同時還提供了 API 供其他快取實現使用。
二,MyBatis的流程圖
三,Mybatis環境搭建及簡單實例(從資料庫查詢id為6的學生資訊)
1.準備開發環境:
 先新建一個項目, 添加依賴包:mybatis包、資料庫驅動包(我使用的是mysql)、日誌包(我使用的是log4j), 由於我的是maven項目, 那麼添加依賴包就簡單了,直接在pom.xml添加依賴即可。
pom.xml的文件配置:

 <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--添加mysql資料庫依賴-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.32</version>
    </dependency>
    <!--添加mybatis依賴-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.2.6</version>
    </dependency>
    <!-- 添加log4j 日誌依賴-->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
  </dependencies>

pom.xml

 2.添加全局配置文件(mybatis-cfg.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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/StudentMapper.xml"></mapper>
    </mappers>
</configuration>

mybatis-cfg.xml

3.根據資料庫中要訪問的表的資訊創建POJO類(Student.java)

public class Student {
    private int SID;
    private String Sname;
    private int Sage;
    private String Ssex;
    @Override
    public String toString() {
        return "Student{" +
                "SID=" + SID +
                ", Sname='" + Sname + '\'' +
                ", Sage=" + Sage +
                ", Ssex='" + Ssex + '\'' +
                '}';
    }
    public void setSID(int SID) {
        this.SID = SID;
    }
    public void setSname(String sname) {
        Sname = sname;
    }
    public void setSage(int sage) {
        Sage = sage;
    }
    public void setSsex(String ssex) {
        Ssex = ssex;
    }
    public int getSID() {
        return SID;
    }
    public String getSname() {
        return Sname;
    }
    public int getSage() {
        return Sage;
    }
    public String getSsex() {
        return Ssex;
    }
}

Student.java

4.創建Mapper介面文件(StudentMapper.java)

  這是一個介面類,裡面封裝了一些空方法,而方法的具體內容一般是在它的映射文件xml中用sql的語法來編寫的。

  JDBC:       Dao(介面)    ——>    DaoImpl(實現類)

  MyBatis:   Mapper(介面)—–>   xxxMapper.xml

public interface StudentMapper {
    public Student selectStudentById(int sid);
}

StudentMapper.java

5.添加Mapper.xml映射文件(StudentMapper.xml)

  注意寫好的Mapper.xml映射文件一定要註冊在全局配置文件(mybatis-cfg.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">
<!--
namespace:名稱空間
id:唯一標識
resultType:返回值類型
#{id}:從傳過來的參數中取出id值
-->
<mapper namespace="MyBatisDemo.StudentMapper">
    <!--查詢標籤:select  注意此處id為該方法的方法名-->
    <select id="selectStudentById" resultType="MyBatisDemo.Student">
        select * from student where SID=#{sid}
    </select>
</mapper>

StudentMapper.xml

6.添加日誌配置文件

## debug 級別
log4j.rootLogger=DEBUG,Console  
log4j.appender.Console=org.apache.log4j.ConsoleAppender  
log4j.appender.Console.Target=System.out  
log4j.appender.Console.layout = org.apache.log4j.PatternLayout  
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd-HH\:mm\:ss,SSS} [%t]  [%c] [%p] - %m%n  
log4j.logger.com.mybatis=DEBUG  /  

##輸出sql 語句
log4j.logger.java.sql.Connection=DEBUG  
log4j.logger.java.sql.Statement=DEBUG  
log4j.logger.java.sql.PreparedStatement=DEBUG 

log4.properties

7.測試類

public class MyBatisTest {
    public static void main( String[] args ) {
        SqlSession openSession = null;
        try {
            //mybatis配置文件
            String resourse="mybatis-cfg.xml";
            //通過 Resources 工具類將 mybatis-config.xm 配置文件讀入 Reader
            InputStream inputStream=Resources.getResourceAsStream(resourse);
            //通過 SqlSessionFactoryBuilder 建造類使用 Reader 創建 SqlSessionFactory工廠對象
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
            //通過SqlSessionFactory工廠得到SqlSession
            openSession = sqlSessionFactory.openSession();
            //通過反射機制來獲取對應的Mapper實例
            StudentMapper mapper=openSession.getMapper(StudentMapper.class);
            //通過mapper調用實例下的方法
            Student student=mapper.selectStudentById(6);
            System.out.println(student);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //最後一定不要忘記關閉 SqlSession ,否則會因為連接沒有關閉導致資料庫連接數過多,造成系統崩旗
            openSession.close();
        }
    }
}

8.運行結果

四.MyBatis-全局配置文件

1.properties標籤

  mybatis可以通過properties標籤來引入外部properties配置文件的內容,包括兩個路徑下的資源,

  • resource:引入類路徑下的資源
  • url:引入網路路徑或者磁碟路徑下的資源

  在使用properties標籤之前,配置資料庫是用下面的方法,由於是使用硬編碼的方式,修改value參數值都需要動程式碼。在使用properties標籤後,就可以將參數值封裝到一個配置文件中,每次修改參數只需在配置文件中修改即可。

      

 使用properties的步驟:

  1.在mybatis-cfg.xml的同目錄下創建一個db.properties文件,文件中存放資料庫連接使用的一些值,下面是文件中的內容。

           

  2.在mybaties-cfg.xml中添加properties標籤,雙引號之間是db.properties文件名

  

  3.將mybaties-cfg.xml中的值替換成變數

    

最後需要注意:如果屬性在不止一個地方進行了配置,那麼MyBatis將按照下面順序來載入

  • 在property元素體內指定的屬性首先被讀取
  • 然後根據properties元素中的resource屬性讀取類路徑下屬性文件或根據url屬性指定的路徑讀取屬性文件,並覆蓋已讀取的同名屬性
  • 最後讀取作為方法參數傳遞的屬性,並覆蓋已讀取的同名屬性

2.settings標籤

  下圖是MyBatis中重要的調整設置,他們會改變Mybatis的運行時行為

舉例:駝峰命名法

  為了保證查詢的數據可以正常顯示出來,我們在編寫POJO類時,必須保證它內部定義屬性名和資料庫中的屬性名必須相同,但我們在資料庫中定義屬性時一般習慣採用駝峰命名法A_B,而Java中又習慣採用aB這種格式命名,所以許多人在編寫程式碼時都會因為格式不相同而無法正確查出數據,所以就有了駝峰命名法,這樣即使格式不一樣(屬性名相同,僅格式不同),也可以正確查出數據。

駝峰命名法的使用方式:

  在mybatis-cfg.xml文件中添加settings標籤即可。

      

   settings用來設置每一個設置項,name設置項名,value設置項取值

3.typeAliases標籤(別名處理器)

   在mybatis中可以使用typeAliases來給變數取別名,這樣對於一些變數名較長的變數,我們就可直接使用它的別名。(別名不區分大小寫)

比如:我們每次在StudentMapper.xml中編寫查詢數據的程式碼時,都要指定數據返回類型,但又因為返回值類型的名字太長,每次編寫時都不方便,所以我們就可以給這個返回值類型起一個簡單易編寫的別名。

       

 起別名的方法:

  1.在mybatis-cfg.xml文件中添加typeAliases標籤

       

   2.將StudentMapper.xml映射文件中使用到MyBatisDemo.Student的地方都替換成TMS

  

 批量起別名的方法:

  1.在mybatis-cfg.xml文件中添加typeAliases標籤

  

  2.在使用該包下的某個類時,就可直接使用類名

  

   但是只用這種方法有個缺陷,就是當該A包底下還存在一個B包,該B包與A包存在相同的類名的類時,使用這種方法就無法區分要使用的是哪個類,所以為了避免這種情況,可結合@Alias註解

   4.給MyBatisDemo包下的類名衝突的子類添加註解

  

   3.將StudentMapper.xml映射文件中使用到MyBatisDemo.Student的地方都替換成TMS,將使用到MyBatisDemo.Teacher的地方都替換成TMT

  

4.typeHandlers標籤

5.objectFactory標籤

6.plugins標籤

7.environments標籤

 

8.databaseidProvider標籤

  可以支援多個資料庫廠商,使用該標籤,可以在多個不同的資料庫中進行查詢數據。

  1.在mybatis-cfg.xml文件中添加databaseidProvider標籤

  2.在StudentMapper.xml映射文件中修改select語句

  

  3.切換當前所使用的資料庫環境

 

9.mappers標籤

1.註冊一個sql映射,其中resource來指定引用類路徑下的sql映射,url用來引用網路路徑或者磁碟路徑下的sql映射

2.註冊介面,使用註冊介面的方法和註冊sql映射的方法的作用是一樣的。

 

 但是使用註冊介面的方法,要保證介面的類名和sql映射的文件名相同,並且兩個必須放到同一個包路徑下。

另外如果沒有映射文件,也可使用註冊介面的方法,與上面不同的是,sql語句是利用註解寫在介面上的,雖然這樣利用註解也可以實現,但是sql和java程式碼的耦合度會更高。所以還是建議利用創建sql映射文件的方式

     

10.總結

  在mybatis-cfg.xml中配置上面的這些標籤時,必須按照上面1-9的排列順序配置,可以缺少某一個標籤,但不允許順序發生變化,否則會報錯。

.XML映射文件的編寫

  由於xml映射文件和介面文件是綁定的關係,所以每次在xml映射文件中添加sql語句,在介面中也就要添加響應的Java語句。

1.查詢操作

介面文件:

  

sql映射文件:

  

測試類:

    

注意此查詢僅支援返回一個結果集,如果返回有多個會報TooManyExection異常。所以如果返回結果有多條就需要將介面文件中方法返回值改為List/Map類型,但sql映射文件不變,如下所示。

1.1.List類型

介面文件:

   

sql映射文件:不變(注意返回類型仍為Student,不為List<Student>)

測試類:

 

1.2.Map類型(只返回一條記錄)

  列名作為key,值就是查詢的值。

介面文件:

 

sql映射文件:(返回多天記錄時,返回值類型就為記錄的類型,但返回一條就可寫為map)

   

測試類:

 

1.3 Map類型(返回多條記錄)

  將多條記錄封裝在一個Map中,並要求指定屬性作為Key值,此處是以名字作為key。

介面文件:

   

sql映射文件:

    

測試類:

   

2.添加操作

介面文件:

  

sql映射文件:

  

注意:此處student()中的參數格式必須和資料庫中的參數格式相同,values()中的#{}中參數必須和POJO類中的參數名相同。

測試類:

  

此處方法是無返回類型的,所以在返回值類型那塊寫void即可,如果想改為Boolean/int類型,可直接將void改為Boolean/int即可,其他sql映射程式碼無需在修改。

3.更新操作

介面文件:

 

sql映射文件:

 

注意:此處set後面的參數格式必須和資料庫中的參數格式相同,#{}中的參數必須和POJO類中的參數名相同。

測試類:

  

4.刪除操作

介面文件:

    

sql映射文件:

     

因為此處是使用(int)sid來查詢刪除的,參數不為student,所以#{}中可任意寫。

測試類:

    

5.多參數查詢

1.使用param來傳參。因為在傳參數時出現多個參數的情況時,這多個參數會被封裝成Map集合,其中key存儲為param1.param2….paramn,value存儲就是參數的值,所以在sql映射文件中就需要使用param來取值。

介面文件:

   

sql映射文件:

    

2.命名參數。使用param來傳參難免會有些不便,當參數多了,就會混淆,為了更好區分,我們可以在傳參時,使用註解重新命名。這時候key存儲為@Param(變數名1).@Param(變數名2)……,value存儲就是參數的值,所以在sql映射文件中就需要使用param重新命的名來取值。

介面文件:

 

sql映射文件:

    

測試類:

   

3.如果多個參數正好都是POJO類中的變數,也可以使用POJO類來傳參。

4.補充:

 6.${}取值與#{}取值的區別

1.#{}是預編譯處理,$ {}是字元串替換。
2.MyBatis在處理#{}時,會將SQL中的#{}替換為?號,使用PreparedStatement的set方法來賦值;MyBatis在處理 $ { } 時,就是把 ${ } 替換成變數的值。
3.使用 #{} 可以有效的防止SQL注入,提高系統安全性。

 7.自定義結果集映射(resultMap)

1.當POJO類中定義的屬性名與資料庫中的屬性名格式不同時,我們除了可以開啟駝峰命名法,還可採用resultMap來解決。

2. 當有兩張表Student表和Course表,在學生表中存在課程表的id號的列,那如果想通過Student表即查出學生資訊又查出專業資訊,我們知道使用resultType是實現不了的,這時候就可使用resultMap來實現。

 除了上面這種使用方式,還可以藉助association標籤來實現。

 sql映射文件:

3.使用association標籤來實現分布查詢

步驟:使用select方法先查出Student的資訊,其中包括Cid,然後又根據Cid在Course表中查出課程名。

 測試類:

 4.延遲載入

  通過查看列印結果可知,在上面的分步查詢過程中,不過有沒有調用student.getCourse()方法,在底層都會進行資料庫的兩次查詢,這樣就會降低執行效率,但是使用延遲載入,就可以保證當我們使用了student.getCourse()方法,底層才會取資料庫進行查詢課程。

開啟延遲載入的方法:在全局配置文件(mybatis-cfg.xml)中,添加setting標籤。

 5.collection標籤

有一張teacher表,裡面既有教師資訊,也有教師授課的資訊,如果想通教師號查到該教師所授的課程資訊,由於是一對多的關係,因此就需要使用collection標籤

 六.MyBatis動態SQL

1.if標籤

舉例:根據傳入的學生資訊在資料庫中查找,如果輸入的姓名不為null,就根據姓名查找,如果輸入的id不為null,就根據id查找,如果都不為空,就查找兩個資訊都匹配的學生。

映射文件:

 測試類:

通過仔細觀察上述程式碼,就會發現上述程式碼是存在問題的,如果傳入的Sid為空,那麼查詢就變成了select * from student where and Sname=?,這明顯是有語法問題的,那該怎麼解決呢?

1.在where後添加1=1

2.將if標籤放到where標籤中,這樣在查詢時,就會自動省and,但必須要求and是在賦值語句前面的,如果在後面,必須使用trim標籤。

3.在update時後邊可能會多一個逗號,可以將更新語句放到set標籤里,當然也可以使用trim標籤。

2.trim(where,set)

prefix:給整個字元串添加一個前綴

prefixOverrides:去掉整個字元串前面多餘的字元

suffix:給整個字元串去掉一個後綴

suffixOverrides:去掉整個字元串後面多餘的字元

3.choose(when,otherwise)

對於if標籤中舉例的那個問題同樣可以使用choose解決。

4.foreach 標籤

separator:每個元素之間的分隔符。

open:給遍歷所有的結果拼接一個開始的字元

close:給遍歷出所有的結果拼接一個結束的字元

index:索引。遍歷list的時候,index是索引,item就是當前值。遍歷map的時候,index就是map的key,item就是map的值。

舉例1:給一些id號,然後在資料庫中查找與這些id號匹配的學生的資訊。

介面文件:

sql映射文件:

 

測試類:

 舉例2:批量添加學生資訊

介面文件:

sql映射文件:

測試類:

 5.bind標籤(可以給一個變數綁定上一些字元串)

舉例:想通過字元串匹配的方法,通過輸入’ h ‘ 找到名字中包含h的學生。

 介面文件:

 sql映射文件:

 測試類:

 6.抽取重複的sql語句