MyBatis框架學習-1

MyBatis框架安排

1. 第一天:

1. MyBatis入門

  1. 什麼是框架?
    答:它是我們軟件開發過程中的一套解決方案, 不同的框架解決不同的問題。
    簡而言之,框架其實就是某種應用的半成品,就是一組組件,供你選用完成你自己的系統。簡單說就是使用別 人搭好的舞臺,你來做表演。而且,框架一般是成熟的,不斷升級的軟件。
  2. 三層框架
    1. 表現層:control
    2. 業務邏輯層:service
    3. 持久層:dao

在這裏插入圖片描述
可以看到不同的框架各司其職,在軟件開發中擔任不同的角色,MyBatis框架主要是與數據庫打交道,所以它工作在持久層。
在這裏插入圖片描述

  1. 持久層的傳統解決方案
    1. JDBC技術
      1. Connection:連接數據庫對象
      2. PrepareStatement:預處理對象,用於操作sql
      3. ResultSet:操作數據庫後生成的結果集
    2. Spring的SpringTemplate技術
      Spring中對jdbc的簡單封裝
    3. Apache的DBUtils
      和SpringTemplate類似,Apache中對jdbc的簡單封裝

以上所用都不是框架
JDBC是接口規範
SpringTemplate和DBUtils都是對jdbc接口規範的實現類,是一個工具類。

傳統的jdbc訪問數據庫:

public static void main(String[] args) {    
	Connection connection = null;    
	PreparedStatement preparedStatement = null;    
	ResultSet resultSet = null;   
	 try {     
		 	//加載數據庫驅動     
			Class.forName("com.mysql.jdbc.Driver");     
			 //通過驅動管理類獲取數據庫鏈接    
			connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8","ro ot", "root"); 
		    //定義 sql 語句 ?表示佔位符    
		    String sql = "select * from user where username = ?"; 
			//獲取預處理 statement     
			preparedStatement = connection.prepareStatement(sql); 
		    //設置參數,第一個參數爲 sql 語句中參數的序號(從 1 開始),第二個參數爲設置的 參數值     
		   	 preparedStatement.setString(1, "王五");     
		    //向數據庫發出 sql 執行查詢,查詢出結果集     resultSet =  preparedStatement.executeQuery(); 
		    //遍歷查詢結果集     
		   	 while(resultSet.next()){             
			     System.out.println(resultSet.getString("id")+"   "+resultSet.getString("username"));     
		     }   
		     } catch (Exception e)	 {     
		       e.printStackTrace(); 
		   }
		   finally{     
			   //釋放資源    
			    if(resultSet!=null){     
			     try {       
			     resultSet.close(); 
			     } catch (SQLException e) {      
			      e.printStackTrace();    
			        }   
		          }   
		        if(preparedStatement!=null){    
		              try {     
		                preparedStatement.close();   
		                   } catch (SQLException e) {   
		                       e.printStackTrace();  
		                           }   
		                             }     
		        if(connection!=null){ 
	                   try {    
	                      connection.close();    
	                        } catch (SQLException e) {   
	                            // TODO Auto-generated catch block      
	                             e.printStackTrace(); 
	                        }     
	                      	  }  
	                              }  
		                               } 
上邊使用 jdbc 的原始方法(未經封裝)實現了查詢數據庫表記錄的操作。 

PreparedStatement對象它的執行方法

  1. execute:可以執行任何CRUD語句,返回值是一個布爾值,表示是否有結果。
  2. excuteUpdate:只能執行CUD,查詢語句無法執行,返回值數據庫操作影響的行數。
  3. excuteQuery:只能執行Select 語句,無法進行增刪改操作,執行的結果集爲ResultSet對象

2. MyBatis概述

  1. 概念:mybatis是一個持久層框架,用Java編寫,它封裝了jdbc的很多細節,使開發者能夠只關注sql語句本身,無需關注註冊驅動,創建連接等繁瑣的過程,它使用了ORM思想實現了結果集的封裝。
    ORM思想:
    Object Relational Mapping對象關係映射
    簡單的說就是實體類的屬性和數據庫表的字段產生了對應關係,使得我們操作實體類就可以操作數據庫表了。
    例如:

    user表 User類
    username varchar(32) String username
    id int(12) int id
    grade varchar(12) String grade

3. MyBatis環境搭建

  1. 環境搭建步驟:

    1. 創建maven工程並導入座標
    2. 創建實體類和dao接口
    3. 創建MyBatis的主配置文件:SqlMapConfig.xml
    4. 創建dao層映射配置文件:IUserDao.xml
  2. 注意事項:

    1. 映射配置文件還有一種寫法是Mapper.xml。我們寫成IUserDao.xml主要是爲了和之前寫過的dao做一個過渡。
    2. 在裏面創建目錄時,它和創建包是不一樣的。例如
      創建目錄:com.liuzeyu.dao 它只是一級目錄,在硬盤上也是一級目錄
      創建包:com.liuzeyu.dao 它只是三級目錄,分層顯示,在硬盤上也是三級目錄
    3. mybatis的映射配置文件必須和dao層的包結構相同,映射配置文件寫在resource資源文件下
    4. 映射配置文件的mapper標籤下的namespace屬性取值必須是dao層接口的全限定類名
    5. 映射配置文件的操作配置,如select的id屬性取值必須是dao層接口的方法名

    當我們遵從了3,4,5點後,就可以不用像從前那樣寫dao接口的實現類了。

4. MyBatis入門案例

  1. 在搭建完環境後,完成入門案例。首選創建實體類和MySQL數據庫和表,並生成相應的getter和setter方法
    在這裏插入圖片描述
    sql代碼:

    DROP TABLE IF EXISTS `user`;
    
    CREATE TABLE `user` (
      `id` int(11) NOT NULL auto_increment,
      `username` varchar(32) NOT NULL COMMENT '用戶名稱',
      `birthday` datetime default NULL COMMENT '生日',
      `sex` char(1) default NULL COMMENT '性別',
      `address` varchar(256) default NULL COMMENT '地址',
      PRIMARY KEY  (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    
    
    insert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2018-02-27 17:47:08','男','北京'),(42,'小二王','2018-03-02 15:09:37','女','北京金燕龍'),(43,'小二王','2018-03-04 11:34:34','女','北京金燕龍'),(45,'傳智播客','2018-03-04 12:04:06','男','北京金燕龍'),(46,'老王','2018-03-07 17:37:26','男','北京'),(48,'小馬寶莉','2018-03-08 11:44:00','女','北京修正');
    
    
  2. 項目對象模型(pom.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.liuzeyu</groupId>
        <artifactId>day01_mybatis</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
        <dependencies>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.5</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.6</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.10</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.12</version>
            </dependency>
        </dependencies>
    </project>
    
  3. dao層接口

    package com.liuzeyu.dao;
    import com.liuzeyu.domain.User;
    import java.util.List;
    
    public interface IUserDao {
        public List<User> findAll();
    }
    
    
  4. SqlMapConfig.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">
    <!-- mybatis主配置文件 -->
    <configuration>
        <!-- 配置環境 -->
        <environments default="mysql">
            <!-- 配置mysql環境 -->
            <environment id="mysql">
                <!-- 配置事物類型 -->
                <transactionManager type="JDBC"></transactionManager>
                <!-- 配置數據庫源(連接池)-->
                <dataSource type="POOLED">
                    <!-- 配置連接數據庫的四個基本信息 -->
                    <property name="driver" value="com.mysql.jdbc.Driver" />
                    <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis" />
                    <property name="username" value="root" />
                    <property name="password" value="809080" />
                </dataSource>
            </environment>
        </environments>
    
        <!-- 指定映射配置文件的位置,映射配置文件是指每一個獨立的dao接口配置-->
        <mappers>
            <mapper resource="com.liuzeyu.dao.IUserDao.xml"/>
        </mappers>
    </configuration>
    
  5. 映射文件IUserDao.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.liuzeyu.dao.IUserDao">
        <select id="findAll">
            SELECT * from user
        </select>
    </mapper>
    

在這裏插入圖片描述

  1. 編寫測試類MyBatisTest.java

    public class MyBatisTest {
        /**
         * mybatis入門案例測試
         * @param args
         */
        public static void main(String[] args) throws Exception{
            //1.讀取配置文件SqlMapConfig.xml
            InputStream is = MyBatisTest.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
            //2.創建SqlSessionFactory工廠
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(is);
            //3.使用factory創建SqlSession
            SqlSession session = factory.openSession();
            //4.使用SqlSessionFactory創建dao層接口的動態代理對象
            IUserDao dao = session.getMapper(IUserDao.class);
            //5.使用代理對象執行方法
            List<User> users = dao.findAll();
            //6.遍歷輸出結果
            for (User user : users) {
                System.out.println(user);
            }
            //釋放資源
            is.close();
            session.close();
        }
    }
    
    
  2. 運行後出現
    在這裏插入圖片描述
    翻譯過來,沒有找到IUserDao.xml,考慮到映射文件是在SqlMapConfig.xml上配置的,故檢查SqlMapConfig.xml
    發現:
    在這裏插入圖片描述
    改成:
    在這裏插入圖片描述
    再次運行又發現:
    在這裏插入圖片描述
    這個問題是未在接口的映射配置文件中定義resultType導致的,resultType是操作數據庫返回封裝結果集的對象
    在這裏插入圖片描述
    添加後:
    在這裏插入圖片描述

  3. 測試輸出:
    在這裏插入圖片描述
    設計到的設計模式分析(涉及到構建者模式,工廠模式,代理模式簡單看一下,下面還會學習到)在這裏插入圖片描述

  4. 查看測試類方法,發現代碼也比較複雜,涉及到多個對象,如SqlSessionFactoryBuilder,SqlSessionFactory…其實MyBat也提供了更爲簡潔的實習方式,即,註解配置,這樣雖然不能減少測試類的代碼編寫,但是可以直接刪除掉映射接口的配置文件,採用註解配置,將原來的配置文件刪除
    在這裏插入圖片描述
    重新在接口的定義處添加
    在這裏插入圖片描述
    感覺簡單了很多,少了配置文件,但是需要在Mybatis的主配置文件中修改映射文件的配置,將resource屬性改爲class屬性,並添加接口的全限定類名
    在這裏插入圖片描述
    重新運行程序:
    在這裏插入圖片描述

  5. 其實MyBatis也提供了接口實現類的方法來與數據庫交互,只需要對dao層添加接口實現類,可以在9的基礎上進行改造
    添加dao層的接口實現:
    在這裏插入圖片描述
    測試函數部分就可以省去SqlSession對象的建立
    在這裏插入圖片描述
    小結:
    通過學習mybatis的案例可以發現,比我們之前使用的jdbc簡單很多,可以省去接口實現類和jdbc初始化等一系列操作,添加兩個配置文件即可,再者可以通過註解配置,使得與數據庫的交互更加的簡單。
    但是這裏麪包含了很多的細節,爲什麼會有工廠對象SqlSessionFactory,爲什麼有了工廠對象後還需要有構建者對象SqlSessionFactoryBuilder,爲什麼IUserDao.xml 在創建的時候有文件名和位置的規定。通過下一章的學習可以明白mybatis的內部執行流程,並且可以對這些設計模式有一個認識。

注意事項

  1. 不要忘記在接口的映射配置文件中告知mybatis要封裝到哪個實體類中,配置的方式:指定實體類的全限定類名。
  2. 如果使用註解配置,需要在主配置文件處修改mapper屬性爲class屬性

5. 自定義MyBatis框架(深入瞭解MyBatis執行細節)

  1. 分析在上述案例中的測試類selectList是如何運行的?
    在這裏插入圖片描述
    List< E > selectList(PreparedStatement statement)
    當代理對象過程中,調用了Proxy.newInstanceProxy(類加載器,代理對象要實現的接口字節碼數組,增強代碼),在增強代碼部分進行selectList的調用。
    先不談代理模式,來看看selectList都是怎麼進行的呢?

    1. 首先程序通過xml解析技術對SqlMapConfig.xml進行讀取,獲取到4個連接數據庫的必備信息和映射接口配置文件的路徑
    2. 有了driver,url,username,password就可以在selectList中創建Connection對象
    3. 通過配置文件的映射關係可以得到真正執行的sql語句和結果集的全限定類名。
    4. 有了sql就可以獲取到PreparedStatement 的preparedStatement對象了,prepareStatement = connection.prepareStatement(sql);
    5. 有了結果集的全限定類名接口就可以通過反射機制ClassforName(“全限定類名”).newInstance()得到真實的返回值類型對象
    6. 有了4,5兩對象就可以通過遍歷結果集來將結果存入準備好的list集合中並返回

    問題:
    基於4,5,如何將

    <mapper namespace="com.liuzeyu.dao.IUserDao">
        <select id="findAll" resultType="com.liuzeyu.domain.User">
            SELECT * from user
        </select>
    </mapper>
    

    發送到selectList,需要將映射信息封裝成一個Mapper對象,這是一個Map對象

    key(String) value(Mapper)
    com.liuzeyu.dao.findAll 全限定類名+sql語句

    這樣做的好處是,如果以後會有多個查詢findById,findByName等一系列方法可以直接和全限定類名找到對應關係。

  2. 問題2:內部的SqlSession創建代理對象的執行流程

    //4.使用SqlSessionFactory創建dao層接口的動態代理對象
    IUserDao dao = session.getMapper(IUserDao.class);
    

    核心是通過getMapper(IUserDao.class);來獲取代理對象的

public <T> getMapper(Class<T> daoInterfaceClass){
	/**
		類加載器:它使用的和被代理對象相同的類加載器
		代理對象要實現的接口:它使用的和被代理對象實現相同的接口
		如何代理:增強方法,需要我們字節來提供
		此處是一個InvocationHandler的接口,我們需要寫一個該接口的實現類,在實現類中調用selectList方法
	*/
	Proxy.newProxyInstance(類加載器,代理對象要實現的接口字節碼數組,如何代理);
}
  1. 自定義代理模式
    1. 分析:

      1. mybatis使用dao代理的方式實現增刪改操作時做什麼事?
        兩件事:
        1. 創建代理對象
        2. 在代理對象中調用selectList
    2. 自定義mybatis 所需要的類
      1. Class Resource
      2. Class SqlSessionFactoryBuilder
      3. interface SqlSessionFactory
      4. interface SqlSession

    3. 由於涉及的代碼較爲複雜,故將項目up到git上面

      https://github.com/liuzeyu12a/mybatis-

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章