1.1 框架
- 框架(Framework)是整個或部分系統(tǒng)的可重用設(shè)計(jì),表現(xiàn)為一組抽象構(gòu)件及構(gòu)件實(shí)例間交互的方法;另一種定義認(rèn)為,框架是可被應(yīng)用開發(fā)者定制的應(yīng)用骨架。
- 可以說逗扒,一個框架是一個可復(fù)用的設(shè)計(jì)構(gòu)件古戴,它規(guī)定了應(yīng)用的體系結(jié)構(gòu),闡明了整個設(shè)計(jì)矩肩、協(xié)作構(gòu)件之間的依賴關(guān)系现恼、責(zé)任分配和控制流程,表現(xiàn)為一組抽象類以及其實(shí)例之間協(xié)作的方法黍檩,它為構(gòu)件復(fù)用提供了上下文(Context)關(guān)系叉袍。
- 對于程序員來說,框架是一套資源刽酱,這套資源中會包含 Jar 包喳逛、文檔,還有些會包含源碼棵里、代碼示例等润文。這套資源從相關(guān)的官網(wǎng)上可以下載。一般是以壓縮文件的形式出現(xiàn)殿怜。
- 1.1.1 MyBatis 的下載
MyBatis 可以在 github 官網(wǎng)下載:https://github.com/mybatis
備注:大家自行下載就行
- 1.1.2 MyBatis 的 的 Jar 包
MyBatis 框架的解壓目錄中只有一個 Jar 包典蝌,它是 MyBatis 的核心 Jar 包。另外头谜,還有個lib 目錄骏掀,其中存放著 MyBatis 所依賴的 Jar 包。所以,使用MyBatis截驮,需要將其核心 Jar 包笑陈,及 lib 下的所有 Jar 包導(dǎo)入。
1.2 MyBatis 概述
MyBatis本是apache的一個開源項(xiàng)目iBatis侧纯,2010年這個項(xiàng)目由apache遷移到了google新锈,并更名為 MyBatis。2013 年遷移到 Github眶熬。
- 1.2.1 MyBatis 簡介
- MyBatis 是一個優(yōu)秀的基于 Java 的持久層框架妹笆,它內(nèi)部封裝了 JDBC,使開發(fā)者只需關(guān)注SQL 語句本身娜氏,而不用再花費(fèi)精力去處理諸如注冊驅(qū)動拳缠、創(chuàng)建 Connection、配置 Statement等繁雜過程贸弥。
- Mybatis通過xml或注解的方式將要執(zhí)行的各種statement (statement窟坐、preparedStatement等)配置起來,并通過 Java 對象和 Statement 中 SQL 的動態(tài)參數(shù)進(jìn)行映射生成最終執(zhí)行的SQL 語句绵疲,最后由 MyBatis 框架執(zhí)行 SQL 并將結(jié)果映射成 Java 對象并返回哲鸳。
- 1.2.2 MyBatis 與 與 Hibernate
- Hibernate 框架是提供了全面的數(shù)據(jù)庫封裝機(jī)制的“全自動”O(jiān)RM,即實(shí)現(xiàn)了 POJO 和數(shù)據(jù)庫表之間的映射盔憨,以及 SQL 的自動生成和執(zhí)行徙菠。
- 相對于此,MyBatis 只能算作是“半自動”O(jiān)RM郁岩。其著力點(diǎn)国觉,是在 POJO 類 與 SQL 語句之間的映射關(guān)系碗暗。也就是說,MyBatis 并不會為程序員自動生成 SQL 語句山害。具體的 SQL 需要程序員自己編寫如叼,然后通過 SQL 語句映射文件冰木,將 SQL 所需的參數(shù),以及返回的結(jié)果字段映射到指定 POJO笼恰。因此片酝,MyBatis 成為了“全自動”O(jiān)RM 的一種有益補(bǔ)充。
- 與 與 Hibernate 相比挖腰,MyBatis 具有以下幾個特點(diǎn):
① 在 XML 文件中配置 SQL 語句雕沿,實(shí)現(xiàn)了 SQL 語句與代碼的分離,給程序的維護(hù)帶來
了很大便利猴仑。
② 因?yàn)樾枰绦騿T自己去編寫 SQL 語句审轮,程序員可以結(jié)合數(shù)據(jù)庫自身的特點(diǎn)靈活控
制 SQL 語句肥哎,因此能夠?qū)崿F(xiàn)比 Hibernate 等全自動 ORM 框架更高的查詢效率,能夠完成復(fù)
雜查詢疾渣。
③ 簡單篡诽,易于學(xué)習(xí),易于使用榴捡,上手快杈女。
- 1.2.3 MyBatis 體系結(jié)構(gòu)
1.3 MyBatis 工作原理
1.4 第一個 MyBatis 程序
需求:實(shí)現(xiàn)將 Student 信息寫入到 數(shù)據(jù)庫(MySQL)中
- 1.4.1 基本程序
- 項(xiàng)目:MyFirstMyBatis
- ① 入 導(dǎo)入 Jar 包
除了需要導(dǎo)入 MyBatis 的核心 Jar 包及依賴 Jar 包外,還需要導(dǎo)入 MySql 的驅(qū)動 Jar 包吊圾,JUnit 測試的 Jar 包达椰。核心 Jar 包與依賴 Jar 包,均在 MyBatis 框架的解壓目錄下项乒。
- ② 定義實(shí)體類
package com.mybatis.bean;
/**
* 定義學(xué)生實(shí)體類
* @author 清水三千尺
*
*/
public class Student {
//屬性
private Integer id;//ID
private String name;//學(xué)生姓名
private Integer age;//學(xué)生年齡
private Double score;//學(xué)生成績
//訪問器
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
//構(gòu)造器
public Student() {
}
public Student(Integer id, String name, Integer age, Double score) {
this.id = id;
this.name = name;
this.age = age;
this.score = score;
}
public Student(String name, Integer age, Double score) {
this.name = name;
this.age = age;
this.score = score;
}
//toString()方法
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + ", score=" + score + "]";
}
}
- ③ 在 MySQL 中生成表結(jié)構(gòu)啰劲,即創(chuàng)建空表
注意:由于后面要創(chuàng)建的 MyBatis 映射文件映射的是 SQL 語句,而非像Hibernate 一樣檀何,是類到表蝇裤,屬性到字段的映射。所以频鉴,MyBatis 要求栓辜,在創(chuàng)建數(shù)據(jù)庫表時,字段名要與屬性名一致(當(dāng)然垛孔,不一致時藕甩,還可通過 resultMap 解決,后面會講)似炎。
- ④ 定義 Dao 接口
package com.mybatis.dao;
import com.mybatis.bean.Student;
/**
* 定義學(xué)生接口
* @author 清水三千尺
*
*/
public interface IStudentDao {
//添加學(xué)生
void insertStudent(Student student);
}
- ⑤ 定義映射文件
- 映射文件,簡稱為 mapper悯姊,主要完成 Dao 層中 SQL 語句的映射羡藐。具體映射的配置,后面會詳細(xì)講解悯许。映射文件名隨意仆嗦,一般放在 dao 包中。這里映射文件名稱定為 mapper.xml先壕。
映射文件的約束文件 mybatis-3-mapper.dtd 文件瘩扼,在 MyBatis 的核心 Jar 包的org.apache.ibatis.builder.xml 包中存放。當(dāng)然垃僚,主配置文件的約束 dtd 文件也在該位置存放集绰。
在映射文件中添加約束,即配置文件頭谆棺,可以從 MyBatis 框架中的文檔 mybatis-3.3.0.pdf中找到:
在 pdf 中搜索“mybatis-3-mapper.dtd”關(guān)鍵字栽燕,即可找到映射文件的約束。
- 映射文件內(nèi)容為:
<?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="test"> <insert id="insertStudent" parameterType="com.mybatis.bean.Student"> INSERT INTO student(name,age,score) VALUES (#{name},#{age},#{score}) </insert> </mapper>
- 注意,#{ }中寫入的是 Student 類的屬性名碍岔。
- 對于 parameterType 屬性浴讯,框架會自動根據(jù)用戶執(zhí)行的 SqlSession 方法中的參數(shù)自動檢測到,所以一般我們不用指定 parameterType 屬性蔼啦。一般寫為如下形式:
<mapper namespace="test"> <!-- <insert id="insertStudent" parameterType="com.mybatis.bean.Student"> INSERT INTO student(name,age,score) VALUES (#{name},#{age},#{score}) </insert> --> <insert id="insertStudent"> INSERT INTO student(name,age,score) VALUES (#{name},#{age},#{score}) </insert> </mapper>
- ⑥ 定義主配置文件
在主配置文件中添加約束榆纽,即配置文件頭,可以從 MyBatis 框架中的文檔
mybatis-3.3.0.pdf 中找到:
在 pdf 中搜索“mybatis-3-config.dtd”關(guān)鍵字捏肢,即可找到映射文件的約束奈籽。
- 主配置文件名也可以隨意命名,本例定義為 SqlMapConfig.xml猛计。而對于<dataSource/>標(biāo)簽中<property/>的 name 屬性名稱唠摹,需要從幫助文檔中查找。如上圖所示奉瘤。
<?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> <!-- 配置MyBatis運(yùn)行環(huán)境 (暫時的勾拉,以后學(xué)了Spring之后就不在使用了) --> <environments default="test"> <environment id="test"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!-- 注冊映射文件 --> <mappers> <mapper resource="com/demo/dao/StudentMapper.xml"/> </mappers> </configuration>
- ⑦ 定義 Dao 實(shí)現(xiàn)類
package com.mybatis.dao.impl;
import java.io.IOException;
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 com.mybatis.bean.Student;
import com.mybatis.dao.IStudentDao;
public class StudentDaoImpl implements IStudentDao {
private SqlSession session;
public void insertStudent(Student student) {
try {
//1.讀取主配置文件
InputStream inputStream = Resources.getResourceAsStream("config/SqlMapConfig.xml");
//2.創(chuàng)建SQLSessionFactory對象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.創(chuàng)建SqlSession對象
session = sqlSessionFactory.openSession();
//4.操作
session.insert("insertStudent",student);
//5.SQLSession提交
session.commit();
} catch (IOException e) {
e.printStackTrace();
} finally {
//6.關(guān)閉SqlSession
if(session != null){
session.close();
}
}
}
}
- ⑧ 定義測試類
package com.mybatis.test;
import static org.junit.Assert.*;
import org.junit.Test;
import com.mybatis.bean.Student;
import com.mybatis.dao.IStudentDao;
import com.mybatis.dao.impl.StudentDaoImpl;
public class MyTest {
@Test
public void testInsertStudent() throws Exception {
//準(zhǔn)備實(shí)現(xiàn)類
IStudentDao isd = new StudentDaoImpl();
//準(zhǔn)備學(xué)生對象
Student student = new Student("趙四", 18, 90.1);
//實(shí)現(xiàn)學(xué)生的添加
isd.insertStudent(student);
}
}
測試結(jié)果如下:
- ⑨ 添加日志控制文件
- MyBatis 使用 Log4j 進(jìn)行日志處理,而 Login4j2 對其支持并不好盗温,所以在 MyBatis 中需要將 log4j.properties 放入到項(xiàng)目的 src 目錄下藕赞。
- 若將日志級別設(shè)置為 debug,則可以顯示出所執(zhí)行的 SQL 語句卖局、參數(shù)值斧蜕、對 DB 的影響條數(shù)等信息。若將級別設(shè)置為 trace砚偶,則還可顯示出查詢出的每條記錄的每個字段名及值批销。
# Global logging configuration log4j.rootLogger=DEBUG, stdout # 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
1.5 主配置文件詳解
- 主配置文件名可以隨意命名,其主要完成以下幾個功能:
① 注冊存放 DB 連接四要素的屬性文件
② 注冊實(shí)體類的全限定性類名的別名
③ 配置 MyBatis 運(yùn)行環(huán)境染坯,即數(shù)據(jù)源與事務(wù)管理器
④ 注冊映射文件
- 注冊存放 DB 連接四要素的屬性文件
為了方便對數(shù)據(jù)庫連接的管理均芽,DB 連接四要素?cái)?shù)據(jù)一般都是存放在一個專門的屬性文件中的。MyBatis 主配置文件需要從這個屬性文件中讀取這些數(shù)據(jù)单鹿。⑴ 定義屬性文件
在 src 下定義屬性文件 jdbc.properties掀宋。jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8 jdbc.username=root jdbc.password=root
⑵ 修改主配置文件
對主配置文件,第一仲锄,需要注冊屬性文件劲妙。第二,需要從屬性文件中通過 key儒喊,將其 value讀取出來镣奋。<?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 resource="jdbc.properties" /> <!-- 配置MyBatis運(yùn)行環(huán)境 (暫時的,以后學(xué)了Spring之后就不在使用了) --> <environments default="test"> <environment id="test"> <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> <!-- 注冊映射文件 --> <mappers> <mapper resource="com/mybatis/dao/StudentMapper.xml"/> </mappers> </configuration>
- 注冊實(shí)體類的全限定性類名的別名
1怀愧、對于實(shí)體類的全限定性類名的別名指定方式唆途,一般使用<package/>方式富雅。這樣做的好處是會將該包中所有實(shí)體類的簡單類名指定為別名,寫法簡單方便肛搬。
<!-- 配置別名 --> <typeAliases> <package name="com.mybatis.bean"/> </typeAliases>
2没佑、不過,還有另外的指定方式:通過<typealias/>指定温赔。
type:全限定性類名
alias:別名
該方式的好處是蛤奢,可以指定別名為簡單類名以外的其它名稱。當(dāng)然陶贼,弊端是啤贩,必須逐個指定,比較繁瑣拜秧。<typeAliases> <typeAlias type="com.mybatis.bean.Student" alias="Student"/> </typeAliases>
3痹屹、除了自定義的類型的別名外,MyBatis 還提供了內(nèi)置的類型別名:
基本類型:
常用包裝類型:
- 配置 MyBatis 運(yùn)行環(huán)境枉氮,即數(shù)據(jù)源與事務(wù)管理器
配置 MyBatis 的運(yùn)行環(huán)境志衍,主要是配置數(shù)據(jù)源與事務(wù)管理器。
A 聊替、 <environments/>
在<environments/>中可以包含多個運(yùn)行環(huán)境<environment/>楼肪,但其 default 屬性指定了當(dāng)前 MyBatis 運(yùn)行時所選擇使用的環(huán)境。
<environment/>的 id 屬性為當(dāng)前定義的運(yùn)行環(huán)境的名稱惹悄,可以任意命名春叫。該名稱會作為<environments/>的 default 屬性的值出現(xiàn)。
B 泣港、 <transactionManager/>
- 該標(biāo)簽用于指定 MyBatis 所使用的事務(wù)管理器暂殖。MyBatis 支持兩種事務(wù)管理器類型:JDBC與 MANAGED。
- JDBC:使用 JDBC 的事務(wù)管理機(jī)制当纱。即呛每,通過 Connection 的 commit()方法提交,通過rollback()方法回滾惫东。但默認(rèn)情況下莉给,MyBatis 將自動提交功能關(guān)閉了毙石,改為了手動提交廉沮。即程序中需要顯式的對事務(wù)進(jìn)行提交或回滾。從日志的輸出信息中可以看到徐矩。
- MANAGED:由容器來管理事務(wù)的整個生命周期(如 Spring 容器)滞时。
C 、 <dataSource/>
- 該標(biāo)簽用于配置 MyBatis 使用的數(shù)據(jù)源類型與數(shù)據(jù)庫連接基本屬性滤灯。常見有類型有:UNPOOLED坪稽、POOLED曼玩、JDNI 等。
- UNPOOLED :不使用連接池窒百。即每次請求黍判,都會為其創(chuàng)建一個 DB 連接,使用完畢后篙梢,會馬上將此連接關(guān)閉顷帖。
- POOLED:使用數(shù)據(jù)庫連接池來維護(hù)連接。
JNDI:數(shù)據(jù)源可以定義到應(yīng)用的外部渤滞,通過 JNDI 容器獲取數(shù)據(jù)庫連接贬墩。
若要從屬性文件中讀取 DB 連接四要素信息,則使用如下方式:
注冊映射文件
指定映射文件的方式有多種妄呕。但所有的方式陶舞,都是指定在<mappers/>標(biāo)簽中的。
A 绪励、 <mapper resource=””/> 指定映射文件
若映射文件只有一個肿孵,則可直接使用如下形式:
若映射文件有多個,則可使用如下形式:
B 优炬、 <mapper url=””/>
該方式的好處是颁井,可以將映射文件放在本地或網(wǎng)絡(luò)的任意位置,通過其 url 地址即可直接訪問蠢护。但通常映射文件是存放在當(dāng)前應(yīng)用中的雅宾,所以該方式不常用。
C 葵硕、 <mapper class=””/> 指定映射文件
class 屬性值為 Dao 接口的全類名眉抬。
該方式的使用,需要滿足以下幾個要求:
(1)映射文件名要與 Dao 接口名稱相同
(2)映射文件要與接口在同一包中
(3)映射文件中<mapper/>的 namespace 屬性值為 Dao 接口的全類名
D 懈凹、 <package name=””/> 指定映射文件
當(dāng)映射文件較多時蜀变,也可以使用如下形式。其中 package 的 name 屬性指定映射文件所存放的包介评。
但库北,這種方式的使用需要滿足以下幾個條件:
(1)dao 使用 mapper 動態(tài)代理實(shí)現(xiàn)(后面講)
(2)映射文件名要與 Dao 接口名稱相同
(3)映射文件要與接口在同一包中
(4)映射文件中<mapper/>的 namespace 屬性值為 Dao 接口的全類名
1.6 API 介紹
Dao 中需要通過 SqlSession 對象來操作 DB。而 SqlSession 對象的創(chuàng)建们陆,需要其工廠對象SqlSessionFactory寒瓦。SqlSessionFactory 對象,需要通過其構(gòu)建器對象 SqlSessionFactoryBuilder的 build()方法坪仇,在加載了主配置文件的輸入流對象后創(chuàng)建杂腰。
public class StudentDaoImpl implements IStudentMapper { private SqlSession session; public void insertStudent(Student student) { try { //1.讀取主配置文件 InputStream inputStream = Resources.getResourceAsStream("config/SqlMapConfig.xml"); //2.創(chuàng)建SQLSessionFactory對象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.創(chuàng)建SqlSession對象 session = sqlSessionFactory.openSession(); //4.操作 session.insert("insertStudent",student); //5.SQLSession提交 session.commit(); } catch (IOException e) { e.printStackTrace(); } finally { //6.關(guān)閉SqlSession if(session != null){ session.close(); } } } }
(1 ) Resources 類
Resources 類,顧名思義就是資源椅文,用于讀取資源文件喂很。其有很多方法通過加載并解析資源文件惜颇,返回不同類型的 IO 流對象。
(2 ) SqlSessionFactoryBuilder 類
SqlSessionFactory 的創(chuàng)建少辣,需要使用 SqlSessionFactoryBuilder 對象的 build()方法凌摄。由于SqlSessionFactoryBuilder 對象在創(chuàng)建完工廠對象后,就完成了其歷史使命漓帅,即可被銷毀望伦。所以,一般會將該 SqlSessionFactoryBuilder 對象創(chuàng)建為一個方法內(nèi)的局部對象煎殷,方法結(jié)束屯伞,對象銷毀。
其被重載的 build()方法較多:
- (3 ) SqlSessionFactory 接口
SqlSessionFactory 接口對象是一個重量級對象(系統(tǒng)開銷大的對象)豪直,是線程安全的劣摇,所以一個應(yīng)用只需要一個該對象即可。創(chuàng)建 SqlSession 需要使用 SqlSessionFactory 接口的的openSession()方法弓乙。
① openSession(true):創(chuàng)建一個有自動提交功能的 SqlSession
② openSession(false):創(chuàng)建一個非自動提交功能的 SqlSession末融,需手動提交
③ openSession():同 openSession(false)(4 ) SqlSession 接口
SqlSession 接口對象用于執(zhí)行持久化操作。一個 SqlSession 對應(yīng)著一次數(shù)據(jù)庫會話暇韧,一次會話以 SqlSession 對象的創(chuàng)建開始勾习,以 SqlSession 對象的關(guān)閉結(jié)束。
SqlSession 接口對象是線程不安全的懈玻,所以每次數(shù)據(jù)庫會話結(jié)束前巧婶,需要馬上調(diào)用其close()方法,將其關(guān)閉涂乌。再次需要會話艺栈,再次創(chuàng)建。而在關(guān)閉時會判斷當(dāng)前的 SqlSession 是否被提交:若沒有被提交湾盒,則會執(zhí)行回滾后關(guān)閉湿右;若已被提交,則直接將 SqlSession 關(guān)閉罚勾。所以毅人,SqlSession 無需手工回滾。
SqlSession 接口常用的方法有: