一文帶你讀懂MyBatis的使用

頭圖: www.zcool.com.cn/work/ZNTE1M…html

Mybatis


框架的好處java

框架是一個半成品,已經對基礎的代碼進行了封裝並提供相應的 API,開發者在 使用框架是直接調用封裝好的 API 能夠省去不少代碼編寫,從而提升工做效率和開發速度mysql

  1. 重用代碼大大增長,軟件生產效率和質量也獲得了提升;
  2. 代碼結構的規範化,下降程序員之間溝通以及往後維護的成本;
  3. 開發速度加快,開發人員減小,維護費用下降,
  4. 減小開發時間、下降開發難度

學習目標git

掌握:程序員

Mybatis的基本使用、Java 日誌處理框架、Mybatis 配置完善 、SqlSession 經常使用 API 、Mapper 動態代理 、動態 SQL 、Mybatis 緩存 、Mybatis 多表關聯查詢、Mybatis 註解的使用 、Mybatis Generator 工具的使用、PageHelper 分頁插件、Mybatis 與 Servlet 整合web

ORM,Object-Relationl Mapping

MyBatis框架的優勢和缺點算法


對象關係映射,它的做用是在關係型數據庫和對象之間做一個映射處理。項目中的業務實體有兩種表現形式:對象和關係數據,即在內存中表現爲對象,在數據庫中表現爲關係數據。spring

JDBC 的缺點:須要手動的完成面向對象的 Java 語言、面向關係的數據庫之間數據的轉換,代碼繁瑣,影響了開發效率。sql

ORM:在面向對象的java語言中,面向關係的數據庫之間數據的轉換是必須的,數據庫中的數據是不能直接拿來使用,須要轉換成須要的對象來使用,可是每次在開發時須要先創建數據庫而後在對數據庫中的數據轉成咱們能夠操做的對象;所以ORM就至關於轉換的橋樑,開發者不須要和sql語句打交道了。數據庫

ORM將數據庫映射成對象

  • 數據庫的表(table) --> 類(class)
  • 記錄(record,行數據)--> 對象(object)
  • 字段(field)--> 對象的屬性(attribute)

Mybatis框架簡介

MyBatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎全部的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain OrdinaryJava Object,普通的 Java 對象)映射成數據庫中的記錄。MyBatis是一個半自動ORM框架,其本質是對JDBC的封裝。使用MyBatis重點須要程序員編寫 SQL 命令,不須要寫一行 JDBC 代碼。

持久層框架:優化了對數據庫的訪問速度,減小了對數據庫中的訪問頻率,將數據庫中的關係數據經過對象關係映射成對象,這時對象中的存放的就是數據庫中的內容(若是須要執行則存放到內存中),當程序須要某一個對象的屬性執行時,無需再從數據庫中訪問且作轉換就能夠獲取。

與 Hibernate 的比較

Hibernate 是一個全自動的 ORM 框架。由於 Hibernate 建立了 Java 對象和數據庫表之間的完整映射,能夠徹底以面向對象的思想來操做數據庫,程序員不須要手寫 SQL 語句。而 MyBatis 中還須要手寫 SQL 語句,因此是半自動化的,工做量要大於 Hibernate。爲何半自動化的 Mybatis 自動化的 Hibernate 受歡迎?

MyBatis 須要手寫 SQL 語句,因此工做量要大於 Hibernate。可是也正是因爲自定義SQL 語句,因此其靈活性、可優化性就超過了 Hibernate。MyBatis 將手寫 SQL 語句的工做丟給開發者,能夠更加精確的定義 SQL,更加靈活, 也便於優化性能。完成一樣功能的兩條 SQL 語句的性能可能相差十幾倍到幾十倍,在高併發、快響應要求下的互聯網系統中,對性能的影響更明顯。MyBatis 對存儲過程可提供很好的支持。

Mybatis 的 jar 包介紹

  1. asm-7.1.jar :字節碼修改框架
  2. javassist-3.27.0-GA.jar: 可用來檢查、」動態」修改及建立 Java 類。功能與 JDK 自帶反射功能相似,但比反射功能更強大
  3. cglib-3.3.0.jar :實現動態代理的技術,延遲加載時使用
  4. ognl-3.2.14.jar :對象導航圖語言的縮寫,功能強大的表達式語言工具包。在動態 SQL 和${param}中使用
  5. commons-logging-1.2.jar: 日誌包
  6. slf4j-api-1.7.30.jar: 日誌包
  7. slf4j-log4j12-1.7.30.jar: 日誌包
  8. log4j-1.2.17.jar: 日誌包
  9. log4j-api-2.13.3.jar :日誌包
  10. log4j-core-2.13.3.jar: 日誌包

核心API

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder的做用是用來建立 SqlSessionFactory 對象。當 SqlSessionFactory 對象被建立後,SqlSessionFactoryBuilder 就失去了做用,因此它只能存在於建立 SqlSessionFactory 的方法中,而不要讓其長期存在。所以 SqlSessionFactoryBuilder 實例的最佳做用域是方法做用域。

SqlSessionFactory

能夠被認爲是一個數據庫鏈接池,它的做用是建立 SqlSession接口對象。一旦建立了SqlSessionFactory,就要長期保存它,直至再也不使用 MyBatis 應用,因此能夠認爲SqlSessionFactory 的生命週期就等同於 MyBatis 的應用週期。因爲 SqlSessionFactory是 一 個 對 數 據 庫 的 連 接 池 , 所 以 它 佔 據 着 數 據 庫 的 連 接 資 源 。 如 果 創 建 多 個SqlSessionFactory,那麼就存在多個數據庫鏈接池,這樣不利於對數據庫資源的控制,也會致使數據庫鏈接資源被消耗光,出現系統宕機等狀況,因此儘可能避免發生這樣的狀況。所以 SqlSessionFactory 是一個單例,讓它在應用中被共享。

SqlSession

若是說 SqlSessionFactory 至關於數據庫鏈接池,那麼 SqlSession 就至關於一個數據庫鏈接(Connection 對象),你能夠在一個事務裏面執行多條 SQL,而後經過它的commit、rollback 方法提交或者回滾事務。SqlSession 應該存活在一個業務請求中,處理完整個請求後,應該關閉這條鏈接,讓它歸還給 SqlSessionFactory,不然數據庫資源就很快被耗費精光,系統就會癱瘓,因此用 try...catch...finally... 語句來保證其正確關閉

Mapper

映射器。由一個 Java 接口和 XML 文件(或者註解構成),須要給出對應的 SQL 和映射規則,負責發送 SQL 去執行並返回結果。因爲 SqlSession 的關閉,它的數據庫鏈接資源也會消失,因此它的生命週期應該小於等於 SqlSession 的生命週期。Mapper 表明的是一個請求中的業務處理,因此它應該在一個請求中,一旦處理完了相關的業務,就應該廢棄它。

Mybatis的配置文件

全局配置文件和映射配置文件:若是說全局配置聞不見是鏈接數據庫的配置已經環境的設置,那麼映射配置文件就是編寫sql語句的(JDBC是將sql語句和代碼寫在一塊兒而後進行CRUD,Mybatis則是進行了節偶,是功能代碼具備可用性,開發簡單。


全局配置文件

全局配置文件的名稱是自定義的,在 JavaProject 項目中須要放到 src 目錄下。全局配置文件的做用是完成一些全局性的配置,如:對 Mybatis 框架的設置、別名設置、環境設置、指定映射配置文件等相關配置。

<?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>
</configuration>
複製代碼

  1. properties 標籤

properties 標籤中容許內部定義屬性,也能夠是外部的properties 文件定義屬性。不管是內部定義仍是外部定義,均可以使用${name}獲取值。

配置文件中內部定義

<properties>
    <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
    <property name="jdbc.url" value="jdbc:mysql://localhost:3306/bjsxt"/>
    <property name="jdbc.username" value="root"/>
    <property name="jdbc.password" value="root"/>
</properties>
複製代碼

配置文件中外部定義

<properties resource="db.properties"></properties>
複製代碼

  1. settings 標籤

setting 標籤的配置是配置 MyBatis 框架運行時的一些行爲的,例如緩存、延遲加載、結果集控制、執行器、分頁設置、命名規則等一系列控制性參數,其全部的 setting 配置都放在父標籤 settings 標籤中(也能夠不用配置)。

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="multipleResultSetsEnabled" value="true"/>
    <setting name="useColumnLabel" value="true"/>
    <setting name="useGeneratedKeys" value="false"/>
    <setting name="autoMappingBehavior" value="PARTIAL"/>
    <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
    <setting name="defaultExecutorType" value="SIMPLE"/>
    <setting name="defaultStatementTimeout" value="25"/>
    <setting name="defaultFetchSize" value="100"/>
    <setting name="safeRowBoundsEnabled" value="false"/>
    <setting name="mapUnderscoreToCamelCase" value="false"/>
    <setting name="localCacheScope" value="SESSION"/>
    <setting name="jdbcTypeForNull" value="OTHER"/>
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
複製代碼

  1. typeAliases 標籤

類型別名可爲 Java 類型設置一個縮寫名字。

<typeAliases>
	<typeAlias alias="user" type="com.bjsxt.pojo.User" />
</typeAliases>
複製代碼

也能夠指定一個包名,MyBatis 會在包名下面搜索須要的 Java Bean

<typeAliases>
	<package name="com.bjsxt.pojo"/>
</typeAliases>
複製代碼

  1. environments 標籤

配置鏈接數據庫的環境,能夠配置多個環境,好比:開發、測試、發佈產品的環境

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driver}"/>
		    <property name="url" value="${jdbc.url}"/>
    		<property name="username" value="${jdbc.username}"/>
    		<property name="password" value="${jdbc.password}"/>
    	</dataSource>
	</environment>
</environments>
複製代碼

transactionManager 節點

事務處理器。在Mybatis中有兩種事務管理器,也就是type = JDBC或type = MANAGED

  • JDBC:這個配置直接使用了 JDBC 的提交和回滾事務,它依賴從數據源得到的鏈接來管理事務做用域

  • MANAGED在Mybatis中不作事務處理,在JavaEE開發的標準中根據開發框架獲取事務


  1. dataSource 標籤

配置數據鏈接源(JDBC鏈接對象的資源,獲取數據鏈接池)

  • UNPOOLED:使用直連
  • POOLED:使用池連
  • JNDI:使用JNDI方法鏈接

  1. mapper 標籤

指定映射配置文件

使用相對類路徑指定映射配置文件

<mappers>
	<mapper resource="com/bjsxt/mapper/UserMapper.xml"/>
</mappers>
複製代碼

使用 filter:///協議指定映射配置文件

<mappers>
<mapper url="file:///D:\code\mybatis\src\com\bjsxt\mapper\UserMapper.xml"/>
</mappers>
複製代碼

指定映射接口

<mappers>
	<mapper class="com.bjsxt.mapper.UserMapper"/>
</mappers>
複製代碼

經過包名指定映射接口(指定映射文件)

<mappers>
	<package name="com.bjsxt.mapper"/>
</mappers>
複製代碼

映射配置文件

映射配置文件主要是用來編寫 sql 語句的,結果集的映射關係的指定,以及緩存的一些配置等等。

image-20210314085004478

<?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.bjsxt.mapper.UserMapper">
    
</mapper>
複製代碼
  • namespace

mybatis中能夠爲每一個映射文件起一個惟一的命名空間(namespace),只要這個命名空間的id是惟一,即便不一樣的映射文件的sql語句id同樣也不會產生衝突


  1. resultMap 標籤
<resultMap id="userMapper" type="com.bjsxt.pojo.User">
    <id property="userid" column="user_id"/>
    <result property="username" column="user_name"/>
</resultMap>
複製代碼

指定查詢結果集與對象的映射關係的標籤

type:類的徹底名, 或者一個類型別名,能夠理解爲數據庫中的錶轉換成了一個對象,該對象裏面的屬性即便數據庫中表的字段名稱,CRUD該表時,將字段對應的數據填充到改對象中。

id:惟一標識。在進行業務處理時,該標籤指定程序獲取執行sql語句,在一個映射文件中是惟一的

  1. id 標籤

指定主鍵中的值,用於標識一個結果映射。

property: 該屬性值至關於在操做sql語句時起的別名

  1. select、insert、updata、delete標籤
<select id="selectUser" parameterType="int" resultType="u">
	select * from users where userid = #{userid}
</select>
複製代碼

parameterType:指定參數類型。該屬性是可選屬性。由於 MyBatis 能夠經過類型處理器(TypeHandler)推斷出具體傳入語句的參數。

resultType:指望從這條語句中返回結果的類全名或別名。

resultMap:使用 resultMap 標籤來處理結果集映射。

Mybatis案例

添加DTD約束文件

在沒有聯網的狀況下,若是讓 dtd 約束繼續起做用,而且出現標籤提示,能夠經過引入本地 dtd 文件來實現,將下載的 dtd 拷貝到本地的一個目錄下

Idea 操做路徑:File---Settings---Languages & Frameworks。其中 URI 複製 dtd 的網絡地址便可。File 選擇 dtd 文件在本地的地址

注意:在 MyBatis 的核心 jar 包中就提供了 mybatis-3-config.dtd

添加 jar 包

image-20210314092422960

建立實體

public class Users {
    private int userid;
    private String username;
    private String usresex;
    
    public int getUserid() {
    	return userid;
    }
    
    public void setUserid(int userid) {
    	this.userid = userid;
    }
    
    public String getUsername() {
    	return username;
    }
    
    public void setUsername(String username) {
    	this.username = username;
    }
    
    public String getUsresex() {
    	return usresex;
    }
    
    public void setUsresex(String usresex) {
    	this.usresex = usresex;
    }
}
複製代碼

建立 properties 文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bjsxt
jdbc.username=root
jdbc.password=root
複製代碼

建立全局配置文件

在這裏使用了外部定義的properties屬性

<?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>
    <!-- 引入 properties 文件 -->
    <properties resource="db.properties"/>
    <!-- 環境的配置 -->
    <environments default="development">
        <environment id="development">
            <!-- 配置事務 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置數據源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 引入映射配置文件 -->
    <mappers>
    <!-- 使用相對路徑方式引入,不一樣的實體類有不一樣的映射配置文件,若是實體類比較多則比較麻煩 -->
    <mapper resource="com/bjsxt/mapper/UsersMapper.xml"/>
    </mappers>
</configuration>
複製代碼

建立映射配置文件

<?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.bjsxt.mapper.UserMapper">
    <!-- 查詢全部用戶 -->
	<select id="selectUsersAll" resultType="com.bjsxt.pojo.Users">
		select * from users
    </select>
</mapper>
複製代碼

建立 UsersDao 接口

public interface UsersDao {
	List<Users> selectUsersAll()throws IOException;
}
複製代碼

建立 UsersDao 接口實現類

public class UsersDaoImpl implements UsersDao {
    /** * 查詢全部用戶 * @return */
    @Override
    public List<Users> selectUsersAll()throws IOException {
        // 建立 SqlSessionFactory 對象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        // 獲取 SqlSession 對象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        // 經過 SqlSession 對象下的 API 完成對數據庫的操做
        List<Users> list = sqlSession.selectList("com.bjsxt.mapper.UserMapper.selectUsersAll");
        // 關閉 SqlSession 對象
        sqlSession.close();
        return list;
    }
}
複製代碼

Mybatis 中的參數綁定

在映射配置文件中向 SQL 語句中綁定參數的語法結構爲#{ }和${ }。

#{}和${}的區別(面)

#{ }: 解析爲一個 JDBC 預編譯語句(PreparedStatement)的參數標記符佔位符 ?。使 用該方式可避免 SQL 注入

** :僅僅爲一個純碎的 S t r i n g 替換,在 M y b a t i s 的動態 S Q L 解析階段將會進行變量替換。 { }**: 僅僅爲一個純碎的 String 替換,在 Mybatis 的動態 SQL 解析階段將會進行變量替 換。 { } 在預編譯以前已經被變量替換了,這會存在 SQL 注入問題。

Mybatis工具類

ThreadLocal 介紹

ThreadLocal 提供了線程內存儲變量的能力,這些變量不一樣之處在於每個線程讀取的變量是對應的互相獨立的。經過 get 和 set 方法就能夠獲得當前線程對應的值

使用 ThreadLocal 存儲 SqlSession

若是多個 DML 操做屬於一個事務,由於 commit()和 rollback()都是由 SqlSession 完成的,因此必須保證使用一個 SqlSession。可是多個不一樣的 DML 操做可能在不一樣類的不一樣方法中,每一個方法中要單獨的獲取 SqlSession。好比商城下訂單時,其實涉及商品庫存變化、訂單添加、訂單明細添加、付款、日誌添加等多個 DML 操做,分佈在不一樣類中。如何在多個 DML 操做之間使用同一個 SqlSession 呢,可使用 ThreadLocal 來存儲。保證一個線程中的操做使用的都是一個 SqlSession。

在 Web 項目中用戶的每次請求會啓動一個新的線程,好比點擊」結算」完成購物車結算。在 Java 項目中每次啓動 main()也會自動開啓一個 main 線程

public class MybatisUtils {
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    private static SqlSessionFactory sqlSessionFactory = null;
    static{
        // 建立 SqlSessionFactory
        InputStream is = null;
        try{
        	is = Resources.getResourceAsStream("mybatis-cfg.xml");
        }catch (IOException e){
        	e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    }
    
    // 獲取 SqlSession
    public static SqlSession getSqlSession(){
    	SqlSession sqlSession = threadLocal.get();
        if(sqlSession == null){
            sqlSession = sqlSessionFactory.openSession();
            threadLocal.set(sqlSession);
        }
    	return sqlSession;
    }
    
    // 關閉 SqlSession
    public static void closeSqlSession(){
        SqlSession sqlSession = threadLocal.get();
        if(sqlSession != null){
            sqlSession.close();
        	threadLocal.set(null);
    	}
    }
}
複製代碼

Mybatis 的事務提交方式

在 Mybatis 中事務提交方式默認爲手動提交,這與 JDBC 是不一樣的。在 JDBC 中事務默認提交方式爲自動提交。

  • 手動提交事務(默認)
SqlSession sqlSession = sqlSessionFacotry.openSession();
複製代碼
  • 自動提交事務
SqlSession sqlSession = sqlSessionFacotry.openSession(true);
複製代碼

Java日誌處理框架

經常使用日誌處理框架

  1. Log4j: Log For Java(Java 的日誌) 是 Apache 提供的一個開源的 Java 主流的日誌框架。

  2. Log4j2:

    Log4j 定義了 8 個日誌級別(除去 OFF 和 ALL,能夠說分爲 6 個級別),優先級從高到 低依次爲:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。

    在 Log4j 中建議只使用 DEBUG、INFO、WARN、ERROR 四個日誌級別

    • ALL 最低等級的,用於打開全部日誌記錄。
    • TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的 日誌級別,通常不會使用。
    • DEBUG 指出細粒度信息事件對調試應用程序是很是有幫助的,主要用於開發過程當中打印一些運行信息。
    • INFO 消息在粗粒度級別上突出強調應用程序的運行過程。打印一些你感興趣的或者重要的信息,這個能夠用於生產環境中輸出程序運行的一些重要信息,可是不能濫用,避免打印過多的日誌
    • WARN 代表會出現潛在錯誤的情形,有些信息不是錯誤信息,可是也要給程序員的一 些提示。
    • ERROR 指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。打印錯誤和異常信息, 若是不想輸出太多的日誌,可使用這個級別。
    • FATAL 指出每一個嚴重的錯誤事件將會致使應用程序的退出。這個級別比較高了。重大錯

    誤,這種級別你能夠直接中止程序了。

    • OFF 最高等級的,用於關閉全部日誌記錄。
  3. Commons

  4. Logging,

  5. Slf4j,

  6. Logback,

  7. Jul。

Log4j 的使用

  1. Log4j 配置文件名:log4j 配置文件名:log4j.properties,Log4j 配值文件存放位置:項目的 src 的根目錄中

  2. 配置根 Logger

    log4j.rootLogger = [level],appenderName,appenderName2,...
    複製代碼

    level 是日誌記錄的優先級,優先級從低到高分別是 DEBUG,INFO,WARN,ERROR。經過在這裏定義的級別,您能夠控制到應用程序中相應級別的日誌信息的開關,好比在這裏定義了INFO 級別,則應用程序中全部 DEBUG 級別的日誌信息將不被打印出來appenderName 就是指定日誌信息輸出到哪一個地方。可同時指定多個輸出目的地。

  3. Log4j 中的 appender

    org.apache.log4j.ConsoleAppender(輸出到控制檯) org.apache.log4j.FileAppender(輸出到文件) org.apache.log4j.DailyRollingFileAppender(天天產生一個日誌文件) org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件) org.apache.log4j.WriterAppender(將日誌信息以流格式發送到任意指定的地方) org.apache.log4j.jdbc.JDBCAppender(將日誌信息添加數據庫中)

  4. 向控制檯輸出的 appender

    # appender.console 輸出到控制檯
    log4j.appender.console=org.apache.log4j.ConsoleAppender
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=<%d> %5p (%F:%L) [%t] (%c)- %m%n
    log4j.appender.console.Target=System.out
    複製代碼
  5. 向文件輸出的 appender

    ### appender.logfile 輸出到日誌文件 ###
    log4j.appender.logfile=org.apache.log4j.RollingFileAppender
    log4j.appender.logfile.File=SysLog.log
    log4j.appender.logfile.MaxFileSize=500KB
    log4j.appender.logfile.MaxBackupIndex=7
    log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
    log4j.appender.logfile.layout.ConversionPattern=<%d> %p (%F:%L) [%t] %c - %m%n
    複製代碼
  6. 向數據庫輸出的 appender

    log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender
    log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
    log4j.appender.logDB.Driver=com.mysql.jdbc.Driver
    log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/bjsxt
    log4j.appender.logDB.User=root
    log4j.appender.logDB.Password=root
    log4j.appender.logDB.Sql=INSERT INTO
    logs(project_name,create_date,level,category,file_name,thread_name,line,all_
    category,message)values('logDemo','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
    複製代碼
  7. 經過包名控制日誌輸出級別

    log4j.logger.org.apache=FATAL
    log4j.logger.org.apache.commons=ERROR
    log4j.logger.org.springframework=ERROR
    log4j.logger.com.bjsxt=ERROR
    複製代碼

Mapper 動態代理

規範

  1. 接口名稱須要與映射配置文件名稱相同
  2. 映射配置文件中 namespace 必須是接口的全名。
  3. 接口中的方法名和映射配置文件中的標籤的 id 一致。
  4. 接口中的返回值類型和映射配置文件中的 resultType 的指定的類型一致。

Mapper 動態代理模式下的多參數處理

順序傳參法

在映射文件中,SQL 語句中的參數須要使用 arg0,arg1...或者 param1,param2...表示參數的順序。此方法可讀性低,且要求參數的順序不能出錯,在開發中不建議使用

List selectUsersOrderParam(String username,String usersex);

select * from users where username = #{arg0} and usersex= #{arg1}

select * from users where username = #{param1} and usersex=#{param2}

@Param 註解傳參法

在接口方法的參數列表中經過@Param 註解來定義參數名稱,在 SQL 語句中經過註解中所定義的參數名稱完成參數位置的指定。 此方式在參數很少的狀況仍是比較直觀的,推薦使用。

<!-- 根據用戶姓名與性別查詢用戶 , 使用 @Param 註解傳參法 -->
<select id="selectUsersAnnParam" resultType="users">
	select * from users where username = #{name} and usersex= #{sex}
</select>
複製代碼
List<Users> selectUsersAnnParam(@Param("name") String username,@Param("sex") String usersex);
複製代碼

POJO 傳參法

在 Mapper 動態代理中也可使用 POJO 做爲傳遞參數的載體,在 SQL 語句中綁定參數時使用 POJO 的屬性名做爲參數名便可。此方式推薦使用。

<!-- 根據用戶姓名與性別查詢用戶 , 使用 POJO 傳參法 -->
<select id="selectUsersPOJOParam" resultType="users">
	select * from users where username = #{username} and usersex=#{usersex}
</select>
複製代碼
List<Users> selectUsersPOJOParam(Users users);
複製代碼

Map 傳參法

在 Mapper 動態代理中也可使用 Map 做爲傳遞參數的載體,在 SQL 語句中綁定參數時使用 Map 的 Key 做爲參數名便可。此方法適合在傳遞多參數時,若是沒有 POJO 能與參數匹配,可使用該方式傳遞參數。推薦使用。

MyBatis 傳遞 map 參數時,若是傳遞參數中沒有對應的 key 值,在執行 sql 語句時默認取的是 null。

<!-- 根據用戶姓名與性別查詢用戶 , 使用 Map 傳參法 -->
<select id="selectUsersMapParam" resultType="users">
	select * from users where username = #{keyname} and usersex=#{keysex}
</select>
複製代碼
List<Users> selectUsersMapParam(Map<String,String> map);
複製代碼

使用符號實體

咱們可使用符號的實體來表示

Snipaste_2021-03-14_15-43-51

<select id="selectUsers" resultType="users">
	select * from users where userid &gt; #{userid}
</select>
複製代碼

動態 SQL


Mybatis動態sql有什麼用?執行原理?有哪些動態sql?


在 MyBatis 中提供了動態 SQL 功能。將使用 Java 代碼拼接 SQL 語句,改變爲在 XML 映射文件中使用標籤拼接 SQL 語句。

MyBatis 中動態 SQL 是編寫在 mapper.xml 中的,其語法和 JSTL 相似,可是倒是基於強大的 OGNL 表達式實現的。

OGNL對象導航圖語言(Object Graph Navigation Language),簡稱OGNL,是應用於Java中的一個開源的表達式語言(Expression Language),它被集成在Struts2等框架中,做用是對數據進行訪問,它擁有類型轉換、訪問對象方法、操做集合對象等功能。)

  1. if 標籤

if 標籤單分支判斷語句

<!-- 根據用戶給定的條件進行查詢 -->
<select id="selectUsersByProperty" resultType="users">
    select * from users where 1=1
    <if test="userid != 0">
    	and userid = #{userid}
    </if>
    <if test="username != null and username != ''">
    	and username = #{username}
    </if>
    <if test="usersex != null and usersex != ''">
    	and usersex = #{usersex}
    </if>
</select>
複製代碼
  1. choose、when、otherwise 標籤

從多個條件中選擇一個使用。

<!-- 多選一條件 -->
<select id="selectUsersByChoose" resultType="users">
    select * from users where 1=1
    <choose>
        <when test="username != null and username != ''">
        	and username = #{username}
        </when>
        <when test="usersex != null and usersex != ''">
        	and usersex = #{usersex}
        </when>
        <otherwise>
	        and userid = 1
        </otherwise>
    </choose>
</select>
複製代碼
  1. where 標籤

使用 where 標籤,就不須要提供 where 1=1 這樣的條件了。若是判斷條件不爲空則自動添加 where 關鍵字,而且會自動去掉第一個條件前面的 and 或 or

<!-- 根據用戶給定的條件進行查詢使用 where 標籤實現 -->
<select id="selectUsersByPropertyWhere" resultType="users">
    select * from users
    <where>
        <if test="userid != 0">
        	and userid = #{userid}
        </if>
        <if test="username != null and username != ''">
        	and username = #{username}
        </if>
        <if test="usersex != null and usersex != ''">
       	 	and usersex = #{usersex}
        </if>
    </where>
</select>
複製代碼
  1. bind 標籤

bind 標籤容許咱們在 OGNL 表達式之外建立一個變量,並能夠將其綁定到當前的 SQL語句中。通常應用於模糊查詢,經過 bind 綁定通配符和查詢值。

<!-- 根據用戶姓名模糊查詢 -->
<select id="selectUsersByLikeName" resultType="users">
    <bind name="likeName" value="'%'+name+'%'"/>
    select * from users where username like #{likeName}
</select>
複製代碼
  1. set 標籤

set 標籤用在 update 語句中。藉助 if 標籤,能夠只對有具體值的字段進行更新。set 標籤會自動添加 set 關鍵字,自動去掉最後一個 if 語句的多餘的逗號。

<!-- 選擇更新 -->
<update id="usersUpdate">
    update users
    <set>
        <if test="username != null and username != ''">
        	username = #{username},
        </if>
        <if test="usersex != null and usersex != ''">
        	usersex = #{usersex},
        </if>
    </set>
    where userid = #{userid}
</update>
複製代碼
  1. foreach 標籤

foreach 標籤的功能很是強大,咱們能夠將任何可迭代對象如 List、Set 、Map 或者數組對象做爲集合參數傳遞給 foreach 標籤進行遍歷。它也容許咱們指定開頭與結尾的字符串以及集合項迭代之間的分隔符。

Snipaste_2021-03-15_09-22-14

迭代 List、Set

<!-- 查詢用戶 ID 爲 1 或者 2 的用戶 -->
<select id="selectUsersByIdUseCollection" resultType="users">
    select * from users where userid in
    <foreach collection="collection" item="userid" open="(" separator="," close=")">
    	#{userid}
    </foreach>
</select>
複製代碼

迭代數組

<!-- 查詢用戶 ID 爲 1 或者 2 的用戶使用數組傳遞參數 -->
<select id="selectUsersByIdUseArray" resultType="users">
    select * from users where userid in
    <foreach collection="array" item="userid" open="(" separator="," close=")">
    	#{userid}
    </foreach>
</select>
複製代碼

Mybatis 緩存

在執行了一次SQL查詢語句時,查詢結果存儲在內存或者某種緩存介質(Mybatis的緩存介質有哪些)當中,當下次遇到相同的查詢 SQL 時候不在執行該 SQL,而是直接從緩存中獲取結果

MyBatis 緩存方式分爲一級緩存和二級緩存,同時也可配置關於緩存設置。

一級緩存是將結果緩存在 SqlSession 對象中,二級緩存是存儲在 SqlSessionFactory 對象中。默認狀況下,MyBatis 開啓一級緩存,沒有開啓二級緩存。當數據量大的時候能夠藉助一些第三方緩存技術來協助保存 Mybatis 的二級緩存數據。

一級緩存的使用

一級緩存也叫本地緩存,MyBatis 的一級緩存是在會話(SqlSession)層面進行緩存的。在SqlSession中有一個(內存區域)數據結構(HashMap)用於存儲緩存數據。不一樣的SqlSession之間的緩存數據區域(HashMap)是互相不影響的;MyBatis 的一級緩存是默認開啓的,不須要任何的配置。

image-20210314161035643

一級緩存的生命週期

  • MyBatis 在開啓一個數據庫會話時,會建立一個新的 SqlSession 對象,SqlSession 對象中會有一個新的 Executor (Executor是什麼?)對象。Executor 對象中持有一個新的PerpetualCache(PerpetualCache是什麼?) 對象;當會話結束時,SqlSession 對象及其內部的 Executor 對象還有 PerpetualCache 對象也一併釋放掉。

  • 若是 SqlSession 調用了 close()方法,會釋放掉一級緩存 PerpetualCache 對象,一級緩存 將不可用。

  • 若是 SqlSession 調用了 clearCache(),會清空 PerpetualCache 對象中的數據,可是該對象 仍可以使用。

  • 若是中間(半路中)sqlSession去執行commit操做(update()、delete()、insert()) ,都會清空SqlSession中的數據,這樣作的目的是更新緩存中的數據(PerpetualCache 對象),避免髒讀


如何判斷兩次查詢是徹底相同的查詢?

Mybatis 認爲,對於兩次查詢,若是如下條件都徹底同樣,那麼就認爲它們是徹底相同的兩次查詢。

  1. 傳入的 statementId(statementId是什麼?)。

  2. 查詢時要求的結果集中的結果範圍。

  3. 此次查詢所產生的最終要傳遞給 PreparedStatement 的 Sql 語句字符串。

  4. 傳遞的參數值

二級緩存的使用

MyBatis 的二級緩存是 Application 級別的緩存,它能夠提升對數據庫查詢的效率,以提升應用的性能。二級緩存是 SqlSessionFactory 上的緩存,能夠是由一個 SqlSessionFactory 建立的不一樣的 SqlSession 之間共享緩存數據。默認並不開啓。SqlSession 在執行 commit()或者 close()的時候將數據放入到二級緩存。

image-20210314162543853

SqlSession 共享二級緩存

image-20210314162934778

二級緩存的配置方式

二級緩存的開啓須要進行配置,實現二級緩存的時候,MyBatis 要求緩存的 POJO 必須是可序列化的, 也就是要求實現 Serializable 接口,爲了將緩存數據取出執行反序列化操做,由於二級緩存數據存儲介質多種多樣,不必定只存在內存中,有可能存在硬盤中。在映射配置文件中配置就能夠開啓緩存了。

二級緩存特色

  1. 映射語句文件中的全部 select 語句將會被緩存。
  2. 映射語句文件中的全部 insert、update 和 delete 語句會刷新緩存。
  3. 二級緩存是以 namespace(全局命名空間) 爲單位的,不一樣 namespace 下的操做互不影響
  4. 若是在加入標籤的前提下讓個別 select 元素不使用緩存,可使用 useCache

屬性,設置爲 false。 5. 緩存會使用默認的 Least Recently Used(LRU,最近最少使用的)算法來收回。 6. 根據時間表,好比 No Flush Interval,(CNFI 沒有刷新間隔),緩存不會以任什麼時候間順序 來刷新。

  1. 緩存會存儲列表集合或對象(不管查詢方法返回什麼)的 1024 個引用
  2. 緩存會被視爲是 read/write(可讀/可寫)的緩存,意味着對象檢索不是共享的,並且能夠安全的被調用者修改,不干擾其餘調用者或線程所作的潛在修改。

Mybatis 註解的使用

在 Mybatis 中若是使用註解式開發,那麼註解須要添加在 Mapper 接口中的抽象方法上,在註解中給定須要執行的 SQL 語句便可,這樣就能夠不須要映射配置文件。MyBatis 支持純註解方式,支持純映射配置文件方式,也支持註解和映射配置文件混合形式。當只有接口沒有映射配置文件時在 mybatis-cfg.xml 中對於引入映射能夠經過加載指定接口類。也可使用指定加載的包。

實例

  1. 使用註解完成查詢
@Select("select * from users")
List<Users> selectUsersAll();
複製代碼

註解式開發時的參數傳遞

順序傳參法

@Select("select * from users where username = #{param1} and usersex= #{param2}")
List<Users> selectUsersByNameAndSexOrder(String username,String usersex);
@Select("select * from users where username = #{name} and usersex = #{sex}")
List<Users> selectUsersByNameAndSexOrder2(@Param("name") String username,@Param("sex") String usersex);
複製代碼

POJO 傳參法

#{}裏面的參數名稱要與實體類的屬性名稱一致

@Select("select * from users where username = #{username} and usersex = #{usersex}")
List<Users> selectUsersByNameAndSexPOJO(Users users);
複製代碼

Map 傳參法

當key不存在時,則返回null

@Select("select * from users where username = #{keyname} and usersex = #{keysex}")
List<Users> selectUsersByNameAndSexMap(Map<String,String> map);
複製代碼

OpenSessionInView 的使用

什麼是 Open Session In View

Open Session In View 模式:

Open Session In View 是將一個數據庫會話對象綁定到當前請求線程中,在請求期間一直保持數據庫會話對象處於 Open 狀態,使數據庫會話對象在請求的整個期間均可以使用。直到產生響應後關閉當前的數據庫會話對象

image-20210314165840605

相關文章
相關標籤/搜索