- '#{}' 和'${}'的區(qū)別是什么誊垢?
${}是Properties文件中的變量占位符悔捶,它可以用于標(biāo)簽屬性值和sql內(nèi)部响迂,屬于靜態(tài)文本替換拜马,比如${driver}
會(huì)被靜態(tài)替換為 com.mysql.jdbc.Driver渗勘。
#{}是sql的參數(shù)占位符矾飞,MyBatis會(huì)將sql中的#{}替換為?號(hào)呀邢,sql執(zhí)行前會(huì)使用PerparedStatement的參數(shù)設(shè)置
方法,按序給sql的豹绪?號(hào)占位符設(shè)置參數(shù)值价淌。比如 #{item.name}的取值方式為使用反射從參數(shù)對(duì)象中獲取item
對(duì)象的name屬性值,相當(dāng)于param.getItem().getName()瞒津。#{}只能用于sql拼接中的參數(shù)蝉衣,將?的參數(shù)值替換為#{value}
#{} 和 ${} 在預(yù)編譯中的處理是不一樣的巷蚪。
#{} 在預(yù)處理時(shí)病毡,會(huì)把參數(shù)部分用一個(gè)占位符 ? 代替, ${} 則只是簡(jiǎn)單的字符串替換屁柏。
在使用過(guò)程中我們應(yīng)該使用哪種方式呢啦膜?
答案是:優(yōu)先使用 #{}。因?yàn)?${} 會(huì)導(dǎo)致 sql 注入的問(wèn)題淌喻。
2.XML映射文件的標(biāo)簽
MyBatis常見(jiàn)的標(biāo)簽僧家,除了<select><insert><update><delete>外,還有很多其他的標(biāo)簽裸删,如<resultMap><parameterMap>八拱、
<sql>、<include>涯塔、<selectKey>加上動(dòng)態(tài)sql的9個(gè)標(biāo)簽trim|where|set|foreach|if|choose|when|otherwise|bind等肌稻,其中通過(guò)
<include>標(biāo)簽引入sql片段,<selectKey>為不支持自增的主鍵生成策略標(biāo)簽匕荸。
3.通常一個(gè)XML映射文件爹谭,都會(huì)寫(xiě)一個(gè)Dao接口與之對(duì)應(yīng),這個(gè)Dao接口的工作原理是什么每聪?Dao接口里的方法旦棉,參數(shù)不同時(shí),方法能重載嗎药薯?
Dao接口绑洛,也就是Mapper接口,接口的全限定名童本,就是映射文件中的namespace的值真屯,接口的方法名,就是映射文件中
MappedStatement的id值穷娱,接口方法內(nèi)的參數(shù)绑蔫,就是傳遞給sql的參數(shù)运沦。Mapper接口是沒(méi)有實(shí)現(xiàn)類的,當(dāng)調(diào)用接口方法的時(shí)候配深,接
口全限名+方法名拼接字符串作為key值携添,可唯一定位一個(gè)MappedStatement。在MyBatis中篓叶,每一個(gè)<select>烈掠、<insert>、
<update>缸托、<delete>標(biāo)簽左敌,都會(huì)被解析成一個(gè)MappedStatement對(duì)象。
Dao 接口里的方法可以重載俐镐,但是Mybatis的XML里面的ID不允許重復(fù)矫限。
/**
* Mapper接口里面方法重載
*/
public interface StuMapper {
List<Student> getAllStu();
List<Student> getAllStu(@Param("id") Integer id);
}
//然后在 StuMapper.xml 中利用Mybatis的動(dòng)態(tài)sql就可以實(shí)現(xiàn)。
<select id="getAllStu" resultType="com.pojo.Student">
select * from student
<where>
<if test="id != null">
id = #{id}
</if>
</where>
</select>
Dao接口的工作原理是JDK動(dòng)態(tài)代理佩抹,MyBatis運(yùn)行時(shí)會(huì)使用JDK動(dòng)態(tài)代理為Dao接口生成代理proxy對(duì)象叼风,代理對(duì)象proxy會(huì)攔截
接口方法,轉(zhuǎn)而執(zhí)行Mapped所代表的sql棍苹,然后將sql執(zhí)行結(jié)果返回咬扇。
5.簡(jiǎn)述Mybatis的插件運(yùn)行原理,以及如何編寫(xiě)一個(gè)插件
Mybatis僅可以編寫(xiě)針對(duì)ParameterHandler廊勃、ResultSetHandler懈贺、StatementHandler、Executor這四種接口的插件坡垫,Mybatis使用
jdk的動(dòng)態(tài)代理梭灿,為需要攔截的接口生成代理對(duì)象,以實(shí)現(xiàn)接口方法攔截功能冰悠,每當(dāng)執(zhí)行這4種接口對(duì)象的方法時(shí)堡妒,就會(huì)進(jìn)入攔截
方法,具體就是IvocationHandler的invoke()方法溉卓。當(dāng)然皮迟,只會(huì)攔截哪些你指定需要攔截的方法。
實(shí)現(xiàn)MyBatis中的Interceptor接口并復(fù)寫(xiě)intercept()方法桑寨,然后給插件編寫(xiě)注解伏尼,指定要攔截哪一個(gè)接口的方法,最后在配置文件
中配置編寫(xiě)的插件尉尾。
8.Mybatis是如何將sql執(zhí)行結(jié)果封裝為目標(biāo)對(duì)象并返回的爆阶?都有哪些映射形式?
第一種是使用<resultMap>標(biāo)簽,逐一定義列名和對(duì)象屬性名之間的映射關(guān)系辨图。第二種是使用sql列的別名功能班套,將列別名書(shū)寫(xiě)為
對(duì)象屬性名。Mybatis會(huì)忽略列名大小寫(xiě)故河,找到與之對(duì)應(yīng)對(duì)象屬性名吱韭。
有了列名與屬性名映射關(guān)系后,mybatis通過(guò)反射創(chuàng)建對(duì)象鱼的,用反射給對(duì)象的屬性賦值并返回杉女,找不到映射關(guān)系的屬性,無(wú)法賦值鸳吸。
9.Mybatis能執(zhí)行一對(duì)一、一對(duì)多查詢嗎速勇?有哪些實(shí)現(xiàn)方式晌砾,以及它們之間的區(qū)別。
能烦磁,Mybatis不僅可以執(zhí)行一對(duì)一养匈、一對(duì)多關(guān)聯(lián)查詢,還可以執(zhí)行多對(duì)一都伪,多對(duì)多的關(guān)聯(lián)查詢呕乎。多對(duì)一查詢,其實(shí)就是一對(duì)一查
詢陨晶,只需要把selectOne()修改為selectList()即可猬仁;多對(duì)多查詢,其實(shí)就是一對(duì)多查詢先誉,只需要把selectOne()修改為selectList()即
可湿刽。
關(guān)聯(lián)對(duì)象查詢有兩種實(shí)現(xiàn)方式,一種是單獨(dú)發(fā)送一個(gè)sql去查詢關(guān)聯(lián)對(duì)象褐耳,賦給主對(duì)象诈闺,然后返回主對(duì)象。另一種是使用嵌套查
詢铃芦,嵌套查詢的含義為使用join查詢雅镊,一部分A對(duì)象的屬性值,另一部分是關(guān)聯(lián)對(duì)象的屬性值刃滓,好處是只發(fā)一個(gè)sql查詢仁烹,就可以把
主對(duì)象和其關(guān)聯(lián)對(duì)象查出來(lái)。
10.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查詢上來(lái)贪薪,然后調(diào)用a.setB(b),于是a
的對(duì)象b屬性就有值了媳禁,接著完成a.getB().getName()。
11画切、Mybatis都有哪些Executor執(zhí)行器竣稽?它們之間的區(qū)別是什么?
Mybatis有三種基本的Executor執(zhí)行器霍弹,SimpleExecutor毫别、ReuseExecutor、BatchExecutor典格。
- SimpleExecutor:每執(zhí)行一次update或select岛宦,就開(kāi)啟一個(gè)statement對(duì)象,用完立即關(guān)閉Statement對(duì)象耍缴。
- ReuseExecutor:執(zhí)行update或select砾肺,以sql作為key查找statement對(duì)象,存在就使用防嗡,不存在就創(chuàng)建债沮,用完后不關(guān)閉Statement
對(duì)象,而是放置在Map<String,Statement>中本鸣,供下一次使用疫衩。
- BatchExecuotr:執(zhí)行update(沒(méi)有select,JDBC批處理不支持select)荣德,將所有sql都添加到批處理中(addBatch())闷煤,等待統(tǒng)一
執(zhí)行(executeBatch()),它緩存了多個(gè)Statement對(duì)象,每個(gè)statement對(duì)象都是addBatch()完畢后涮瞻,等待逐一執(zhí)行executeBatch()批處理鲤拿。
12.MyBatis如何制定使用哪一種Executor執(zhí)行器?
在MyBatis配置文件中署咽,可以指定默認(rèn)的ExecutorType執(zhí)行器類型近顷,也可以手動(dòng)給DefaultSqlSessionFactory的創(chuàng)建SqlSession的
方法傳遞ExecutorType類型參數(shù)生音。
13.mybatis工作原理
(1)讀取核心配置文件并返回InputStream流對(duì)象。
(2)根據(jù)InputStream流對(duì)象解析出Configuration對(duì)象窒升,然后創(chuàng)建SqlSessionFactory工廠對(duì)象
(3)根據(jù)一系列屬性從SqlSessionFactory工廠中創(chuàng)建SqlSession
(4)從SqlSession中調(diào)用Executor執(zhí)行數(shù)據(jù)庫(kù)操作缀遍,生成具體sql指令。
(5)對(duì)執(zhí)行結(jié)果進(jìn)行二次封裝
(6)提交與事務(wù)
14.MyBatis 是否可以映射 Enum 枚舉類饱须?
MyBatis 可以映射枚舉類域醇,不單可以映射枚舉類,MyBatis 可以映射任何對(duì)象到表的一列上蓉媳。
映射方式為自定義一個(gè) `TypeHandler`譬挚,實(shí)現(xiàn) `TypeHandler` 的 `setParameter()`和 `getResult()`接口方法。
`TypeHandler` 有兩個(gè)作用酪呻,一是完成從 javaType 至 jdbcType 的轉(zhuǎn)換减宣,二是完成 jdbcType 至 javaType 的轉(zhuǎn)
換,體現(xiàn)為 `setParameter()`和 `getResult()`兩個(gè)方法玩荠,分別代表設(shè)置 sql 問(wèn)號(hào)占位符參數(shù)和獲取列查詢結(jié)果漆腌。
15.MyBatis 映射文件中,如果 A 標(biāo)簽通過(guò) include 引用了 B 標(biāo)簽的內(nèi)容姨蟋,請(qǐng)問(wèn),B 標(biāo)簽?zāi)芊穸x在 A 標(biāo)簽的后面立帖,還是說(shuō)必須定義在 A 標(biāo)簽的前面眼溶?
雖然 MyBatis 解析 Xml 映射文件是按照順序解析的,但是晓勇,被引用的 B 標(biāo)簽依然可以定義在任何地方堂飞,MyBatis 都可以正確識(shí)別。
原理是绑咱,MyBatis 解析 A 標(biāo)簽绰筛,發(fā)現(xiàn) A 標(biāo)簽引用了 B 標(biāo)簽,但是 B 標(biāo)簽尚未解析到描融,尚不存在铝噩,此時(shí),
MyBatis 會(huì)將 A 標(biāo)簽標(biāo)記為未解析狀態(tài)窿克,然后繼續(xù)解析余下的標(biāo)簽骏庸,包含 B 標(biāo)簽,待所有標(biāo)簽解析完畢年叮,
MyBatis 會(huì)重新解析那些被標(biāo)記為未解析的標(biāo)簽具被,此時(shí)再解析 A 標(biāo)簽時(shí),B 標(biāo)簽已經(jīng)存在只损,A 標(biāo)簽也就可以正常解析完成了一姿。
16.簡(jiǎn)述 MyBatis 的 Xml 映射文件和 MyBatis 內(nèi)部數(shù)據(jù)結(jié)構(gòu)之間的映射關(guān)系?
MyBatis 將所有 Xml 配置信息都封裝到 All-In-One 重量級(jí)對(duì)象 Configuration 內(nèi)部。在 Xml 映射文件中叮叹,
<parameterMap>標(biāo)簽會(huì)被解析為 ParameterMap 對(duì)象艾栋,其每個(gè)子元素會(huì)被解析為 ParameterMapping 對(duì)
象。<resultMap>標(biāo)簽會(huì)被解析為 ResultMap 對(duì)象衬横,其每個(gè)子元素會(huì)被解析為 ResultMapping 對(duì)象裹粤。每一個(gè)
<select>、<insert>蜂林、<update>遥诉、<delete>標(biāo)簽均會(huì)被解析為 MappedStatement 對(duì)象,標(biāo)簽內(nèi)的 sql 會(huì)被解析為 BoundSql 對(duì)象噪叙。
17.為什么說(shuō) MyBatis 是半自動(dòng) ORM 映射工具矮锈?它與全自動(dòng)的區(qū)別在哪里?
Hibernate 屬于全自動(dòng) ORM 映射工具睁蕾,使用 Hibernate 查詢關(guān)聯(lián)對(duì)象或者關(guān)聯(lián)集合對(duì)象時(shí)苞笨,可以根據(jù)對(duì)象關(guān)
系模型直接獲取,所以它是全自動(dòng)的子眶。而 MyBatis 在查詢關(guān)聯(lián)對(duì)象或關(guān)聯(lián)集合對(duì)象時(shí)瀑凝,需要手動(dòng)編寫(xiě) sql 來(lái)
完成,所以臭杰,稱之為半自動(dòng) ORM 映射工具粤咪。
18.MyBatis的兩種映射方式:
1.通過(guò)XML映射
2.通過(guò)注解
19.#{} 和 ${}的區(qū)別
#{}是預(yù)編譯處理,${}是字符串替換渴杆。
Mybatis在處理#{}時(shí)寥枝,會(huì)將sql中的#{}替換為?號(hào),調(diào)用PreparedStatement的set方法來(lái)賦值磁奖;
Mybatis在處理時(shí)就是把${}替換成變量的值囊拜。
使用#{}可以有效的防止SQL注入,提高系統(tǒng)安全性比搭。
20.自增主鍵回填以及實(shí)現(xiàn)方法
新增一條數(shù)據(jù)成功后冠跷,將這條數(shù)據(jù)的主鍵封裝到實(shí)體類中,并查看主鍵的值身诺。
實(shí)現(xiàn)一:使用insert標(biāo)簽的子標(biāo)簽selectKey實(shí)現(xiàn)蔽莱;
實(shí)現(xiàn)二:使用insert標(biāo)簽的屬性u(píng)seGeneratedKeys,keyProperty戚长,keyColumn實(shí)現(xiàn)盗冷;
21.Mybatis的一級(jí)、二級(jí)緩存
一級(jí)緩存:(本地緩存)作用域:SqlSession級(jí)別
mybatis第一次查詢到數(shù)據(jù)后同廉,會(huì)將數(shù)據(jù)存入到一級(jí)緩存中仪糖。當(dāng)再次查詢相同的數(shù)據(jù)時(shí)柑司,mybatis會(huì)將緩存中的數(shù)據(jù)直接拿出來(lái)返回,不再?gòu)臄?shù)據(jù)庫(kù)中查詢锅劝;
二級(jí)緩存:(全局緩存) 作用域:namespace級(jí)別
在一個(gè)sqlSession攒驰,進(jìn)行了一次查詢,會(huì)把查詢結(jié)果存入一級(jí)緩存故爵;
當(dāng)sqlSession關(guān)閉之后玻粪,mybatis會(huì)把一級(jí)緩存中的數(shù)據(jù)存入二級(jí)緩存中;
當(dāng)我們?cè)俅伟l(fā)生相同的查詢時(shí)诬垂,會(huì)從二級(jí)緩存中命中劲室;
二級(jí)緩存作用域更大
二級(jí)緩存的開(kāi)啟需要進(jìn)行配置,實(shí)現(xiàn)二級(jí)緩存的時(shí)候结窘,MyBatis要求返回的POJO必須是可序列化的很洋。
22.MyBatis實(shí)現(xiàn)一對(duì)多查詢有幾種方式,怎么操作的?
關(guān)聯(lián)對(duì)象查詢隧枫,有兩種實(shí)現(xiàn)方式喉磁,一種是單獨(dú)發(fā)送一個(gè) sql 去查詢關(guān)聯(lián)對(duì)象,賦給主對(duì)象官脓,然后返回主對(duì)象协怒。
另一種是使用嵌套查詢,嵌套查詢的含義為使用 join 查詢卑笨,一部分列是 A 對(duì)象的屬性值孕暇,另外一部分列是關(guān)
聯(lián)對(duì)象 B 的屬性值,好處是只發(fā)一個(gè) sql 查詢湾趾,就可以把主對(duì)象和其關(guān)聯(lián)對(duì)象查出來(lái)芭商。