1蒸辆、什么是Mybatis?
(1)Mybatis是一個(gè)半ORM(對(duì)象關(guān)系映射)框架析既,它內(nèi)部封裝了JDBC躬贡,開發(fā)時(shí)只需要關(guān)注SQL語句本身,不需要花費(fèi)精力去處理加載驅(qū)動(dòng)眼坏、創(chuàng)建連接拂玻、創(chuàng)建statement等繁雜的過程。程序員直接編寫原生態(tài)sql空骚,可以嚴(yán)格控制sql執(zhí)行性能,靈活度高擂仍。
(2)MyBatis 可以使用 XML 或注解來配置和映射原生信息囤屹,將 POJO映射成數(shù)據(jù)庫中的記錄,避免了幾乎所有的 JDBC 代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集逢渔。
(3)通過xml 文件或注解的方式將要執(zhí)行的各種 statement 配置起來肋坚,并通過java對(duì)象和 statement中sql的動(dòng)態(tài)參數(shù)進(jìn)行映射生成最終執(zhí)行的sql語句,最后由mybatis框架執(zhí)行sql并將結(jié)果映射為java對(duì)象并返回肃廓。(從執(zhí)行sql到返回result的過程)智厌。
2、Mybaits的優(yōu)點(diǎn):
(1)基于SQL語句編程盲赊,相當(dāng)靈活汰具,不會(huì)對(duì)應(yīng)用程序或者數(shù)據(jù)庫的現(xiàn)有設(shè)計(jì)造成任何影響搞动,SQL寫在XML里,解除sql與程序代碼的耦合,便于統(tǒng)一管理巷挥;提供XML標(biāo)簽,支持編寫動(dòng)態(tài)SQL語句纪岁,并可重用毁欣。
(2)與JDBC相比,減少了50%以上的代碼量缀台,消除了JDBC大量冗余的代碼棠赛,不需要手動(dòng)開關(guān)連接;
(3)很好的與各種數(shù)據(jù)庫兼容(因?yàn)镸yBatis使用JDBC來連接數(shù)據(jù)庫膛腐,所以只要JDBC支持的數(shù)據(jù)庫MyBatis都支持)睛约。
(4)能夠與Spring很好的集成;
(5)提供映射標(biāo)簽哲身,支持對(duì)象與數(shù)據(jù)庫的ORM字段關(guān)系映射痰腮;提供對(duì)象關(guān)系映射標(biāo)簽,支持對(duì)象關(guān)系組件維護(hù)律罢。
3膀值、MyBatis框架的缺點(diǎn):
(1)SQL語句的編寫工作量較大棍丐,尤其當(dāng)字段多、關(guān)聯(lián)表多時(shí)沧踏,對(duì)開發(fā)人員編寫SQL語句的功底有一定要求歌逢。
(2)SQL語句依賴于數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫移植性差翘狱,不能隨意更換數(shù)據(jù)庫秘案。
4、MyBatis框架適用場(chǎng)合:
(1)MyBatis專注于SQL本身潦匈,是一個(gè)足夠靈活的DAO層解決方案阱高。
(2)對(duì)性能的要求很高,或者需求變化較多的項(xiàng)目茬缩,如互聯(lián)網(wǎng)項(xiàng)目赤惊,MyBatis將是不錯(cuò)的選擇。
5凰锡、MyBatis與Hibernate有哪些不同未舟?
(1)Mybatis和hibernate不同,它不完全是一個(gè)ORM框架掂为,因?yàn)镸yBatis需要程序員自己編寫Sql語句裕膀。
(2)Mybatis直接編寫原生態(tài)sql,可以嚴(yán)格控制sql執(zhí)行性能勇哗,靈活度高昼扛,非常適合對(duì)關(guān)系數(shù)據(jù)模型要求不高的軟件開發(fā),因?yàn)檫@類軟件需求變化頻繁欲诺,一但需求變化要求迅速輸出成果野揪。但是靈活的前提是mybatis無法做到數(shù)據(jù)庫無關(guān)性,如果需要實(shí)現(xiàn)支持多種數(shù)據(jù)庫的軟件瞧栗,則需要自定義多套sql映射文件斯稳,工作量大。
(3)Hibernate對(duì)象/關(guān)系映射能力強(qiáng)迹恐,數(shù)據(jù)庫無關(guān)性好挣惰,對(duì)于關(guān)系模型要求高的軟件,如果用hibernate開發(fā)可以節(jié)省很多代碼殴边,提高效率憎茂。
6、#{}和${}的區(qū)別是什么锤岸?
#{}是預(yù)編譯處理竖幔,${}是字符串替換。
Mybatis在處理#{}時(shí)是偷,會(huì)將sql中的#{}替換為?號(hào)拳氢,調(diào)用PreparedStatement的set方法來賦值募逞;
Mybatis在處理{}替換成變量的值馋评。
使用#{}可以有效的防止SQL注入放接,提高系統(tǒng)安全性。
7留特、請(qǐng)寫出Mybatis核心配置文件MyBatis-config.xml的內(nèi)容纠脾?
<?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="jdbc.properties"/>
<settings>
<!-- 全局性地啟用或禁用延遲加載。當(dāng)禁用時(shí)蜕青,所有關(guān)聯(lián)的配置都會(huì)立即加載苟蹈。 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!--當(dāng)啟用后,一個(gè)有延遲加載屬性的對(duì)象的任何一個(gè)延遲屬性被加載時(shí)右核,該對(duì)象
的所有的屬性都會(huì)被加載慧脱。否則,所有屬性都是按需加載蒙兰。 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!--全局關(guān)閉2級(jí)緩存 -->
<!--<setting name="cacheEnabled" value="false"/>-->
</settings>
<!--創(chuàng)建類的別名-->
<typeAliases>
<!--只要是在mapper.xml文件中使用了cn.pb.bean包下面的任意類的時(shí)候磷瘤,無需再用全類名
使用簡寫的類名
之前應(yīng)該 cn.pb.bean.Student
現(xiàn)在 Student
-->
<package name="cn.pb.bean"/>
</typeAliases>
<!--設(shè)置mybatis運(yùn)行環(huán)境 default默認(rèn)的運(yùn)行環(huán)境====environment id的屬性值-->
<environments default="mysql">
<environment id="mysql">
<!--配置事務(wù)管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置數(shù)據(jù)源 POOLED:mybatis自帶的數(shù)據(jù)源-->
<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>
<!--配置需要的mapper文件-->
<mappers>
<mapper resource="mapper/StudentMapper.xml"/>
</mappers>
</configuration>
8芒篷、什么是數(shù)據(jù)持久化以及ORM搜变?
01.數(shù)據(jù)持久化的概念
數(shù)據(jù)持久化就是將內(nèi)在中的數(shù)據(jù)模型轉(zhuǎn)換為存儲(chǔ)模型,以及將存儲(chǔ)模型轉(zhuǎn)換為內(nèi)在中的數(shù)據(jù)模型的統(tǒng)稱,數(shù)據(jù)模型可以是任何數(shù)據(jù)結(jié)構(gòu)或?qū)ο竽P?例如JavaBean對(duì)象;存儲(chǔ)模型可以是關(guān)系型數(shù)據(jù)庫表,XML文件,二進(jìn)制文件等.02.什么是ORM
ORM(Object/Relational Mapping)中文翻譯為對(duì)象/關(guān)系型數(shù)據(jù)映射,它也可以理解為一種數(shù)據(jù)持久化技術(shù),其主要是把對(duì)象模型,例如JavaBean對(duì)象和關(guān)系型數(shù)據(jù)庫的表建立對(duì)應(yīng)關(guān)系,并且提供了一個(gè)通過JavaBean對(duì)象去操作數(shù)據(jù)庫表的機(jī)制.03.使用ORM技術(shù)的好處
在實(shí)際開發(fā)中,程序員使用面向?qū)ο蟮募夹g(shù)操作數(shù)據(jù),而當(dāng)要把數(shù)據(jù)存儲(chǔ)起來時(shí),使用的卻是關(guān)系型數(shù)據(jù)庫,這樣就造成了很多的不便,ORM在對(duì)象模型和關(guān)系數(shù)據(jù)庫的表之間建立了一座橋梁,有了它,程序員就不需要再使用SQL語句操作數(shù)據(jù)庫中的表,直接操作JavaBean對(duì)象就可以實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ),查詢,更改和刪除等操作,Hibernate就是這樣一種技術(shù).
9、請(qǐng)寫出MybatisUtil工具類
package cn.pb.util;
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 java.io.IOException;
import java.io.InputStream;
public class SessionFactoryUtil {
//01.創(chuàng)建需要單例的對(duì)象實(shí)例
private static SqlSessionFactory sessionFactory;
//02.私有化構(gòu)造
private SessionFactoryUtil(){}
/**
* 03.對(duì)外提供訪問的接口
* 001.SqlSession的創(chuàng)建依賴SqlSessionFactory
* 002.SqlSessionFactory依賴于SqlSessionFactoryBuilder
* 003.SqlSessionFactoryBuilder依賴于配置文件
* 004.獲取配置文件
*/
public static synchronized SqlSession getSession(){
//給我一個(gè)文件 返回一個(gè)輸入流 到 內(nèi)存中
try {
InputStream stream = Resources.getResourceAsStream("mybatis.xml");
//判斷SqlSessionFactory是否為空
if (sessionFactory==null){
sessionFactory=new SqlSessionFactoryBuilder().build(stream);
}
} catch (IOException e) {
e.printStackTrace();
}
/**
* 之前還需要寫一個(gè)finally用來關(guān)閉流针炉! 現(xiàn)在不需要 為什么不需要??
* 01.查詢?cè)创abuild(stream)
* 02.SqlSessionFactoryBuilder類中已經(jīng)關(guān)閉reader.close()
* 03.所以我們?nèi)绻P(guān)閉流 會(huì)報(bào)錯(cuò)挠他!
*/
return sessionFactory.openSession(); //創(chuàng)建session返回
}
}
10、請(qǐng)使用association節(jié)點(diǎn)實(shí)現(xiàn)根據(jù)用戶id查詢用戶信息以及對(duì)應(yīng)角色信息(Role實(shí)體類中有一個(gè)對(duì)象User,只寫SQL映射文件)篡帕?
<!-- 01. 根據(jù)角色id 查詢出角色信息-->
<select id="selectRoleById" resultMap="roleMap">
select id,name,userid from role where id=#{xxx}
</select>
<!-- 02. 根據(jù)角色表中查詢結(jié)果中的userid 查詢用戶信息
xxx就是resultmap中傳遞來的 userid-->
<select id="selectUserByUserId" resultType="User">
select userid,name from user where userid=#{xxx}
</select>
<!--對(duì)應(yīng)的roleMap 這種方式 推薦使用 因?yàn)槭褂醚舆t加載-->
<resultMap id="rolrMap" type="Role">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!-- Role有一個(gè)屬性的類型是 user 域?qū)傩?javaType:域?qū)傩詫?duì)應(yīng)的類型 -->
<association property="user" javaType="User" select="selectUserByUserId"
column="userid"/>
</resultMap>
11殖侵、請(qǐng)使用collection節(jié)點(diǎn)實(shí)現(xiàn)獲取指定用戶的相關(guān)信息和地址列表(User實(shí)體類中有一個(gè)復(fù)雜類型的Address集合,只寫SQL映射文件)镰烧?
<!-- 01. 根據(jù)用戶id 查詢出用戶信息-->
<select id="selectUserById" resultMap="userMap">
select id,name from user where id=#{xxx}
</select>
<!-- 02. 根據(jù)用戶表中查詢結(jié)果中的userid 查詢地址信息
xxx就是resultmap中傳遞來的 userid-->
<select id="selectAddressByUserId" resultType="Address">
select id,name,userid from address where userid=#{xxx}
</select>
<!--對(duì)應(yīng)的userMap 這種方式 推薦使用 因?yàn)槭褂醚舆t加載-->
<resultMap id="userMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!-- User有一個(gè)屬性的類型是 list
javaType:域?qū)傩詫?duì)應(yīng)的類型 -->
<collection property="addresses" javaType="Address" select="selectAddressByUserId"
column="userid"/>
</resultMap>
12拢军、MyBatis實(shí)現(xiàn)一對(duì)一有幾種方式?具體怎么操作的?
有聯(lián)合查詢和嵌套查詢,聯(lián)合查詢是幾個(gè)表聯(lián)合查詢,只查詢一次, 通過在resultMap里面配置association節(jié)點(diǎn)配置一對(duì)一的類就可以完成怔鳖;
嵌套查詢是先查一個(gè)表茉唉,根據(jù)這個(gè)表里面的結(jié)果的 外鍵id,去再另外一個(gè)表里面查詢數(shù)據(jù),也是通過association配置结执,但另外一個(gè)表的查詢通過select屬性配置度陆。
13、MyBatis實(shí)現(xiàn)一對(duì)多有幾種方式,怎么操作的献幔?
有聯(lián)合查詢和嵌套查詢懂傀。聯(lián)合查詢是幾個(gè)表聯(lián)合查詢,只查詢一次,通過在resultMap里面的collection節(jié)點(diǎn)配置一對(duì)多的類就可以完成;嵌套查詢是先查一個(gè)表,根據(jù)這個(gè)表里面的 結(jié)果的外鍵id,去再另外一個(gè)表里面查詢數(shù)據(jù),也是通過配置collection,但另外一個(gè)表的查詢通過select節(jié)點(diǎn)配置蜡感。
14蹬蚁、Mybatis是否支持延遲加載恃泪?如果支持,它的實(shí)現(xiàn)原理是什么缚忧?
答:Mybatis僅支持association關(guān)聯(lián)對(duì)象和collection關(guān)聯(lián)集合對(duì)象的延遲加載悟泵,association指的就是一對(duì)一,collection指的就是一對(duì)多查詢闪水。在Mybatis配置文件中糕非,可以配置是否啟用延遲加載lazyLoadingEnabled=true|false。
它的原理是球榆,使用CGLIB創(chuàng)建目標(biāo)對(duì)象的代理對(duì)象朽肥,當(dāng)調(diào)用目標(biāo)方法時(shí),進(jìn)入攔截器方法持钉,比如調(diào)用a.getB().getName()衡招,攔截器invoke()方法發(fā)現(xiàn)a.getB()是null值,那么就會(huì)單獨(dú)發(fā)送事先保存好的查詢關(guān)聯(lián)B對(duì)象的sql每强,把B查詢上來始腾,然后調(diào)用a.setB(b),于是a的對(duì)象b屬性就有值了空执,接著完成a.getB().getName()方法的調(diào)用浪箭。這就是延遲加載的基本原理。
當(dāng)然了辨绊,不光是Mybatis奶栖,幾乎所有的包括Hibernate,支持延遲加載的原理都是一樣的门坷。
15宣鄙、Mybatis的一級(jí)、二級(jí)緩存:
1)一級(jí)緩存: 基于 PerpetualCache 的 HashMap 本地緩存默蚌,其存儲(chǔ)作用域?yàn)?Session冻晤,當(dāng) Session flush 或 close 之后,該 Session 中的所有 Cache 就將清空绸吸,默認(rèn)打開一級(jí)緩存鼻弧。
2)二級(jí)緩存與一級(jí)緩存其機(jī)制相同,默認(rèn)也是采用 PerpetualCache惯裕,HashMap 存儲(chǔ)温数,不同在于其存儲(chǔ)作用域?yàn)?Mapper(Namespace),并且可自定義存儲(chǔ)源蜻势,如 Ehcache撑刺。默認(rèn)不打開二級(jí)緩存,要開啟二級(jí)緩存握玛,使用二級(jí)緩存屬性類需要實(shí)現(xiàn)Serializable序列化接口(可用來保存對(duì)象的狀態(tài)),可在它的映射文件中配置<cache/> 够傍;
3)對(duì)于緩存數(shù)據(jù)更新機(jī)制甫菠,當(dāng)某一個(gè)作用域(一級(jí)緩存 Session/二級(jí)緩存Namespaces)的進(jìn)行了C/U/D 操作后,默認(rèn)該作用域下所有 select 中的緩存將被 clear冕屯。
16寂诱、什么是MyBatis的接口綁定?有哪些實(shí)現(xiàn)方式安聘?
接口綁定痰洒,就是在MyBatis中任意定義接口,然后把接口里面的方法和SQL語句綁定, 我們直接調(diào)用接口方法就可以,這樣比起原來了SqlSession提供的方法我們可以有更加靈活的選擇和設(shè)置。
接口綁定有兩種實(shí)現(xiàn)方式,一種是通過注解綁定浴韭,就是在接口的方法上面加上 @Select丘喻、@Update等注解,里面包含Sql語句來綁定念颈;另外一種就是通過xml里面寫SQL來綁定, 在這種情況下,要指定xml映射文件里面的namespace必須為接口的全路徑名泉粉。當(dāng)Sql語句比較簡單時(shí)候,用注解綁定, 當(dāng)SQL語句比較復(fù)雜時(shí)候,用xml綁定,一般用xml綁定的比較多。
17榴芳、使用MyBatis的mapper接口調(diào)用時(shí)有哪些要求嗡靡?
① Mapper接口方法名和mapper.xml中定義的每個(gè)sql的id相同;
② Mapper接口方法的輸入?yún)?shù)類型和mapper.xml中定義的每個(gè)sql 的parameterType的類型相同窟感;
③ Mapper接口方法的輸出參數(shù)類型和mapper.xml中定義的每個(gè)sql的resultType的類型相同讨彼;
④ Mapper.xml文件中的namespace即是mapper接口的類路徑。