天天看點

微服務[v1.0.0][MyBatis入門]

程式設計語言和底層資料庫的發展不協調,催生出了ORM架構,ORM架構可作為面向對象程式設計語言和資料庫之間的橋梁,确切地說,MyBatis并不完全是一種ORM架構,它的設計思想和ORM相似,隻是它允許開發人員直接編寫SQL語句,使得通路資料庫更 加靈活,更準确地說,它應該是一種“SQL Mapping”架構

對象/關系資料庫映射(ORM)

ORM的全稱是Object/Relation Mapping,即對象/關系資料庫映射。 可以将ORM了解成一種規範,它概述了這類架構的基本特征,完成面向對象的程式設計語言到關系資料庫的映射。當ORM架構完成映射後,程式員既可以利用面向對象程式設計語言的簡單易用性,又可以利用關系 資料庫的技術優勢。是以可以把ORM當成應用程式和資料庫的橋梁

當使用一種面向對象的程式設計語言來進行應用開發時,從項目一開始 就采用的是面向對象分析、面向對象設計、面向對象程式設計,但到了持久層資料庫通路時,又必須重返關系資料庫的通路方式,這是一種非常糟糕的感覺。于是人們需要一種工具,它可以把關系資料庫包裝成面向對象的模型,這個工具就是ORM

ORM架構是面向對象程式設計語言與關系資料庫發展不同步時的 中間解決方案。随着面向對象資料庫的發展,其理論逐漸完善,最終面向對象資料庫會取代關系資料庫。隻是這個過程不可一蹴而就,ORM 架構在此期間會蓬勃發展。但随着面向對象資料庫的廣泛使用,ORM 工具會逐漸消亡

對于時下所有流行的程式設計語言而言,面向對象的程式設計語言代表 了目前程式設計語言的主流和趨勢,其具備非常多的優勢。比如:

  • 面向對象的模組化、操作
  • 多态、繼承
  • 摒棄難以了解的過程,簡單易用,易了解

但資料庫的發展并未能與程式設計語言同步,而且關系資料庫系統的某些優勢也是面向對象語言目前無法比拟的。比如:

  • 大量資料查找、排序
  • 集合資料連接配接操作、映射
  • 資料庫通路的并發、事務
  • 資料庫的限制、隔離

面對這種面向對象語言與關系資料庫系統并存的局面,采用ORM 就變成一種必然。隻要依然采用面向對象程式設計語言,底層依然采用關系資料庫,中間就少不了ORM工具。采用ORM架構之後,應用程式 不再直接通路底層資料庫,而是以面向對象的方式來操作持久化對象 (例如建立、修改、删除等),而ORM架構則将這些面向對象的操作 轉換成底層的SQL操作,如下圖所示

微服務[v1.0.0][MyBatis入門]
ORM工具的唯一作用就是:把對持久化對象的儲存、修改、删除等操作,轉換成對資料庫的操作。由此,程式員可以以 面向對象的方式操作持久化對象,而ORM架構則負責将相關操作轉換 成對應的SQL(結構化查詢語言)操作

基本映射方式

ORM工具提供了持久化類和資料表之間的映射關系,通過這種映 射關系的過渡,程式員可以很友善地通過持久化類實作對資料表的操 作。實際上,所有的ORM工具大緻都遵循相同的映射思路。ORM有如 下幾條基本映射關系:

資料表映射類:持久化類被映射到一個資料表。程式使用這個持 久化類來建立執行個體、修改屬性、删除執行個體時,系統自動會轉換為對這個 表進行CRUD操作,如下圖所示

微服務[v1.0.0][MyBatis入門]
受ORM管理的持久化類(就是一個普通Java類)對應一個資料表,隻要程式對這個持久化類進行操作,系統就可以将其 轉換成對對應資料庫表的操作

資料表的行映射對象(即執行個體):持久化類會生成很多執行個體,每 個執行個體就對應資料表中的一行記錄。當程式在應用中修改持久化類的某 個執行個體時,ORM工具會将其轉換成對對應資料表中特定行的操作。每個持久化對象對應資料表的一行記錄的示意圖,如下圖所示

微服務[v1.0.0][MyBatis入門]

資料表的列(字段)映射對象的屬性:當程式修改某個持久化對象的指定屬性時(持久化執行個體映射到資料行),ORM會将其轉換成對 對應資料表中指定資料行、指定列的操作。資料表的列被映射到對象屬 性的示意圖,如下圖所示

微服務[v1.0.0][MyBatis入門]

基于這種基本的映射方式,ORM工具可完成對象模型和關系模型 之間的互相映射。由此可見,在ORM架構中,持久化對象是一種媒 介,應用程式隻需操作持久化對象,ORM架構則負責将這種操作轉換 為底層資料庫操作。這種轉換對開發者透明,開發者無須關心内部細 節,進而将開發者從關系模型中解放出來,使得開發者能以面向對象的 思維操作關系資料庫

流行的ORM架構簡介

  • JPA:JPA本身隻是一種ORM規範,并不是ORM産品。它是Java EE規範制定者向開源世界學習的結果。相對于其他開源 ORM 架構, JPA 的最大優勢在于它是官方标準,是以具有通用性。如果應用程式是 面向JPA程式設計,那麼應用程式就可以在各種ORM架構之間自由切換
  • Hibernate:目前最流行的開源ORM架構,已經被選為JBoss的持 久層解決方案。整個Hibernate項目也一并投入了JBoss的懷抱,而JBoss 又加入了Red Hat組織。是以,Hibernate屬于Red Hat組織的一部分。 Hibernate靈巧的設計、優秀的性能,以及豐富的文檔,都是其風靡全球 的重要因素
  • MyBatis(早期名稱是iBATIS):Apache 軟體基金組織的子項 目。與其稱它是一種ORM架構,不如稱它是一種“SQL Mapper”架構, 它是一種“半自動化”的ORM的實作,曾經在Java EE開發中扮演非常重 要的角色,但是其并不支援純粹的面向對象操作,它允許開發人員直接 編寫SQL語句,更加靈活

MyBatis概述

MyBatis是一個支援普通SQL查詢、存儲過程和進階映射的優秀持久層架構,它去掉了幾乎所有的JDBC代碼和參數的手工設定以及對結果集的檢索封裝,MyBatis可以使用簡單的XML或注解進行配置和原始映射,将Java的POJO(Plain Old Java Objects,普通的Java對象)映射成資料庫中的記錄

MyBatis作為持久層架構,其主要思想是将程式中的大量SQL語句剝離出來,配置在配置檔案中,以實作SQL的靈活配置。這樣做的好處是将SQL與程式代碼分離,做到可以在不修改程式代碼的情況下,直接 在配置檔案中修改SQL

實際上,目前主流的ORM,無論Hibernate還是JPA,都對資料庫結構提供了較為完整的封裝,提供了從POJO(Plain Old Java Objects)到資料庫表的全套映射機制,開發者隻需定義好POJO到資料庫表的映射 關系,即可通過Hibernate或者JPA 提供的方法完成持久層操作,甚至不需要熟練掌握SQL,Hibernate/JPA會根據制定的存儲邏輯,自動生成對應的SQL并調用JDBC接口加以執行

大多數情況下(特别是對新項目、新系統的開發而言),這樣的機制無往不利,但在一些特定的環境下, Hibernate這種一站式的解決方案卻未必适合。例如:系統的部分或全部資料來自現有資料庫,出于安全考慮,隻對開發團隊提供幾條Select SQL(或存儲過程)以擷取所需資料,具體的表結構不予公開

開發規範中要求,所有牽涉業務邏輯部分的資料庫操作,必須在資料庫層由存儲過程實作(就金融行業而言,工商銀行、中國銀行、交通 銀行等商業銀行都曾在開發規範中嚴格指定)

系統資料處理量巨大,性能要求極為苛刻,這往往意味着我們必須通過經過高度優化的SQL語句(或存儲過程)才能達到系統性能設計名額。

面對這樣的需求,Hibernate不再适合解決上述問題,甚至無法使用它。此時,直接使用JDBC進行資料庫操作實際上也是不錯的選擇,隻是拖沓的資料庫通路代碼、乏味的字段讀取操作令人厭煩,而“半自動 化”的MyBatis,卻正好解決了這個問題

這裡的“半自動化”是相對Hibernate等提供了全面的資料庫封裝機制 的“全自動化”ORM實作而言的,“全自動”ORM 實作了POJO和資料庫表之間的映射,以及 SQL 的自動生成和執行。而MyBatis的着力點,則 在于POJO與SQL之間的映射關系。也就是說,使用MyBatis提供的ORM機制,對業務邏輯實作人員而言,面對的是純粹的 Java 對象,這 一點與通過Hibernate實作ORM而言基本一緻。而對于具體的資料操

作,Hibernate會自動生成SQL 語句,而MyBatis則并不會為程式員在運作期間自動生成SQL。具體的SQL需要程式員編寫,然後通過映射配置檔案,将SQL所需的參數及傳回的結果字段映射到指POJO

相對Hibernate等“全自動”ORM機制而言,MyBatis以 SQL開發的工作量和資料庫移植性上的讓步,為系統設計提供了更大的自由空間。作為“全自動”ORM實作的一種有益補充,MyBatis的存在具有特别的意

MyBatis初探

MyBatis的用法非常簡單,我們隻要在Java項目中引入MyBatis框 架,就能以面向對象的方式操作關系資料庫

下載下傳與安裝

MyBatis站點,即可在頁面上找到下載下傳的超連結,單擊該超連結即可開始下載下傳MyBatis的壓縮包,或者直接點選mybatis-3.5.6直接下載下傳3.5.6版本,解壓縮剛下載下傳的壓縮包,mybatis-x.x.x的檔案 夾,該檔案夾下包含如下檔案結構:

  • mybatis-x.x.x.jar:MyBatis的核心類庫
  • mybatis-x.x.x.pdf:MyBatis的參考文檔
  • mybatis-x.x.x-javadoc.jar:MyBatis的API文檔
  • mybatis-x.x.x-sources.jar:MyBatis的源代碼
  • lib:MyBatis所依賴的第三方jar包

将解壓縮路徑中的 mybatis-x.x.x.jar 包添加到應用程式的類加 載路徑中,既可以通過添加環境變量的方式來添加,也可以使用Ant或 IDE工具來管理應用程式的類加載路徑,如果直接在控制台編譯使用了MyBatis API的類,則需要将mybatis-x.x.x.jar包位置添加到CLASSPATH裡。如果使用Ant或者Eclipse 等IDE工具,則無須修改環境變量

由于 MyBatis 的底層依然是基于 JDBC 的,是以在應用程式中使用MyBatis執行持久化時同樣少不了JDBC驅動,例如程式底層采用了MySQL資料庫,是以還需要将MySQL資料庫驅動添加到應用程式的類 加載路徑中

Mybatis實操

建立一個項目MyBatisQs,為了讓Web應用具有MyBatis支援的功 能,将 mybatis-x.x.x解壓檔案夾下mybatis-x.x.x.jar和lib檔案夾下所有 MyBatis架構所依賴的第三方jar包複制到Web應用的lib檔案夾下,也就是

MyBatisQs\WebContent\WEB-INF\lib

路徑下,然後在MySQL資料庫中建立一個新的資料庫mybatis并建立一個tb_user表,建庫見表語句大緻如下

create database mybatis;
user mybatis;
DROP TABLE IF EXISTS tb_user;
CREATE TABLE tb_user(
	ID INT(11) PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(18) DEFAULT NULL,
	SEX CHAR(2) DEFAULT NULL,
	AGE INT(11) DEFAULT NULL,
);
           

在所有的 ORM 架構中都有一個非常重要的媒介:PO(持久化對象),持久化對象的作用就是完成持久化操作,簡單地說,就是通過該對象對資料庫執行增、删、改的操作,以面向對象 的方式操作資料庫;應用程式無須直接通路資料庫,甚至無須理會底層資料庫采用何種 資料庫,這一切對應用程式完全透明,應用程式隻需建立、修改、删除 持久化對象即可;與此同時,MyBatis則負責把這種操作轉換為對指定

資料庫表的操作

MyBatis中的PO是非常簡單的,其是非侵入式的設計,完全采用普通的Java對象作為持久化對象使用。下面即是一個POJO(普通的、傳統的Java對象)類,如下代碼所示

package org.davieyang.domain;

import java.io.Serializable;


public class User implements Serializable{

	private static final long serialVersionUID = 1L;
	
	// 使用者辨別
	private Integer id;
	// 使用者姓名
	private String name;
	// 使用者性别
	private String sex;
	// 使用者年齡
	private Integer age;
	
	// 無參數構造器
	public User() {
		super();
	}
	// 有參數構造器
	public User( String name, String sex, Integer age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}
	 // setter和getter方法
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + "]";
	}
}

           

這個類與普通的JavaBean沒有任何差別。實際上,MyBatis直接采用了POJO(普通的、傳統的Java對 象)作為持久化類,這就是MyBatis被稱非低侵入式設計的原因。 MyBatis不要求持久化類繼承任何父類,或者實作任何接口,這樣可保證代碼不被污染

對于MyBatis來說,現在還不了解持久化類User和資料庫表之間的 對應關系,也不了解持久化類的屬性與資料表的各個列之間的對應關 系。MyBatis是通過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">
<!-- namespace指使用者自定義的命名空間。 -->
<mapper namespace="org.davieyang.mapper.UserMapper">

<!-- 
	id="save"是唯一的标示符
	parameterType屬性指明插入時使用的參數類型
	useGeneratedKeys="true"表示使用資料庫的自動增長政策
 -->
  <insert id="save" parameterType="org.fkit.domain.User" useGeneratedKeys="true">
  	INSERT INTO TB_USER(name,sex,age) 
  	VALUES(#{name},#{sex},#{age})
  </insert>
  

</mapper>
           

上面的XML配置中定義了一條insert語句,詳細解釋如下:

  • <mapper namespace="org.davieyang.mapper.UserMapper">

    ,為這個mapper指定一個唯一的namespace,namespace的值習慣上設定成包 名+SQL映射檔案名,這樣就能夠保證namespace的值是唯一的,例如

    namespace=“org.davieyang.mapper.UserMapper”

    就是

    org.davieyang.mapper(包名) +UserMapper (UserMapper.xml檔案去除字尾)

  • 在insert标簽中編寫了SQL插入語句,設定insert标簽的id屬性值為save,id屬性值必須是唯一的,不能夠重複
  • 使用parameterType屬性指明插入時使用的參數類型
  • 使用useGeneratedKeys="true"表示使用資料庫的自動增長政策,這需要底層資料庫的支援
  • insert标簽中隻有一條标準的insert語句,用來向TB_USER表插入一條資料,#{name}表示取參數中的對象的name屬性值

接下來,通過這個持久化類來完成對資料庫的操作:插入一條資料,對于MyBatis來說,現在還不知道需要連接配接哪個資料庫,以及連接配接 資料庫時所用的連接配接池、使用者名和密碼等詳細資訊。這些資訊對于所有

的持久化類都是通用的,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">
  <!--  XML 配置檔案包含對 MyBatis 系統的核心設定 -->
<configuration>
	<!-- 指定 MyBatis 所用日志的具體實作 -->
	<settings>
		<setting name="logImpl" value="LOG4J"/>
	</settings>
	<environments default="mysql">
	<!-- 環境配置,即連接配接的資料庫。 -->
    <environment id="mysql">
    <!--  指定事務管理類型,type="JDBC"指直接簡單使用了JDBC的送出和復原設定 -->
      <transactionManager type="JDBC"/>
      <!--  dataSource指資料源配置,POOLED是JDBC連接配接對象的資料源連接配接池的實作。 -->
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
  <!-- mappers告訴了MyBatis去哪裡找持久化類的映射檔案 -->
  <mappers>
  	<mapper resource="org/davieyang/mapper/UserMapper.xml"/>
  </mappers>
</configuration>
           
  • MyBatis根配置檔案預設被命名為

    mybatis-config.xml

    ,應用程式運作時需要先加載該檔案,該檔案第一行是XML檔案聲 明,指定該XML檔案的版本和存儲該檔案所用的字元集
  • MyBatis配置檔案的根元素是

    <configuration.../>

    ,根元素中有

    <settings.../>

    子元素,該元素有很多子元素,本示例隻是配置了日志資訊,之後可以在控制台看到輸出的SQL語句,其在調試中非常有用。根 元素中還有

    <environments.../>

    子元素,用來配置MyBatis的環境,即連接配接的資料庫,該子元素用于将 SQL映射應用于多種資料庫中。每個資料庫對應一個

    SqlSessionFactory

    ,可以配置多種環境,但隻能為

    SqlSessionFactory

    執行個體選擇一個環境,default屬性表示選擇的環境。
  • < environment.../>

    子元素用于配置一個環境,

    <transactionManager.../>

    子元素用來配置MyBatis當中的事務管理,JDBC屬性表示直接簡單使用JDBC的送出和復原設定。

    <dataSource.../>

    子元素用來配置資料源, MyBatis并不推薦采用DriverManager來連接配接資料庫,而是推薦使用資料源來管理資料庫連接配接,這樣能保證最好的性能。該元素依次有很多

    < property.../>

    子元素,這些

    <property.../>

    子元素用于配置MyBatis連接配接 資料庫的必要資訊,如連接配接資料庫的驅動、URL、使用者名、密碼等資訊
資料源是一種用來提高資料庫連接配接性能的正常手段,資料源會負責維持一個資料庫連接配接池,當程式建立資料源執行個體時,系統會一次性地創 建多個資料庫連接配接,并把這些資料庫連接配接儲存在連接配接池中。當程式需要 進行資料庫通路時,無須重新獲得資料庫連接配接,而是從連接配接池中取出一 個空閑的資料庫連接配接,當程式使用資料庫連接配接通路資料庫結束後,無須 關閉資料庫連接配接,而是将資料庫連接配接歸還給連接配接池即可。通過這種方式,就可避免頻繁地擷取資料庫連接配接、關閉資料庫連接配接所導緻的性能下降
根元素中還有

<mappers.../>

子元素,它可以支援多個

<mapper.../ >

子元素,每個

<mapper.../>

子元素用于指定一個持久化配置檔案
package org.fkit.test;

import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.fkit.domain.User;

public class MyBatisTest {

	public static void main(String[] args) {
		// 建立Session執行個體
		SqlSession sqlSession = null;
		try (// 讀取mybatis-config.xml檔案
				InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
			){
			// 初始化mybatis,建立SqlSessionFactory類的執行個體
			SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
					.build(is);
			sqlSession = sqlSessionFactory.openSession();
			// 建立User對象
			User user = new User("admin", "男", 26);
			// 插入資料
			sqlSession.insert("org.fkit.mapper.UserMapper.save", user);
			// 送出事務
			sqlSession.commit();
		} catch (Exception e) {
			// 復原事務
			sqlSession.rollback();
			e.printStackTrace();
		}finally{
			try {
				// 關閉sqlSession
				if(sqlSession != null) sqlSession.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}

}

           

上面持久化操作的代碼非常簡單。程式先建立一個User對象,再使 用SqlSession的insert()方法來儲存User對象即可,這是完全對象化的操作方式,可以說非常簡單明了。當Java程式以面向對象的方式來操作 持久化對象時,MyBatis負責将這種操作轉換為底層SQL操作。

執行持久化操作之前,為了檢視控制台輸出的SQL語句,需要加入 日志架構LOG4J的相關jar包,該jar包在mybatis-x.x.x解壓檔案夾下的lib 檔案夾中可以找到。并在CLASSPATH下增加一個log4j.properties檔案,如下代碼所示

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.fkit.mapper.UserMapper=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] %m%n
           

運作MyBatisTest 類的main()方法,運作完成後,可以看到 mybatis資料庫中的TB_USER表中包含了User執行個體對應的記錄

微服務[v1.0.0][MyBatis入門]

同時,在控制台可以觀察到執行時的日志資訊,其中包括了MyBatis所執行的SQL語句

DEBUG [main]==>Preparing:INSERT INTO TB_USER(name, sex, age) VALUES(?,?,?)
DEBUG [main]==>Parameters:admin(String), 男(String), 26(Integer)
DEBUG [main]==>Updates:1
           
  • 開發持久化類PO和編寫持久化操作的Mapper.xml,在其中定義要執行的SQL語句
  • 擷取SqlSessionFactory
  • 擷取SqlSession
  • 用面向對象的方式操作資料庫
  • 關閉事務,關閉SqlSession
  • 隻需要在Mapper.xml配置檔案中編寫SQL語句,在應用程式中就可 以采用OO方式來通路資料庫
  • 在JDBC通路過程中大量的checked異常被包裝成MyBatis的Runtime 異常,進而不再要求程式必須處理所有異常

繼續閱讀