考核點(diǎn):
Mybatis占位符的使用。
答:
#{}是預(yù)編譯處理,${}是字符串替換;
Mybatis在處理#{}時(shí),會(huì)將SQL中的#{}替換為?,本質(zhì)上是調(diào)用PreparedStatement實(shí)現(xiàn)執(zhí)行命令;
Mybatis在處理${}時(shí),就是把${}替換成變量的值,本質(zhì)上是調(diào)用Statement實(shí)現(xiàn)執(zhí)行命令;
使用#{}可以有效的防止SQL注入,提高系統(tǒng)安全性。
考核點(diǎn):ORM映射。
答:
第1種:通過(guò)在查詢的SQL語(yǔ)句中定義字段名的別名,讓字段名的別名和實(shí)體類的屬性名一致:
<select id=”selectorder” parametertype=”int” resultetype=”me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};
</select>
第2種:通過(guò)resultMap標(biāo)簽來(lái)映射字段名和實(shí)體類屬性名的一一對(duì)應(yīng)的關(guān)系:
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用id屬性來(lái)映射主鍵字段–>
<id property=”id” column=”order_id”>
<!–用result屬性來(lái)映射非主鍵字段,property為實(shí)體類屬性名,column為數(shù)據(jù)表中的屬性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
考核點(diǎn):模糊查詢
答:
第1種:在Java代碼中添加SQL通配符;
//Java代碼中:
String wildcardname = ”%smi%”;
list<name> names = mapper.selectlike(wildcardname);
//Mapper映射文件中:
<select id=”selectlike”>
select name from foo where bar like #{value}
</select>
第2種:在SQL語(yǔ)句中拼接通配符(MYSQL):
//Java代碼中:
String wildcardname = ”smi”;
List<name> names = mapper.selectlike(wildcardname);
//Mapper映射文件中:
<select id=”selectlike”>
select name from foo where bar like ‘%’ #{value} ‘%’
</select>
第3種:在SQL語(yǔ)句中使用Concat函數(shù)拼接通配符,支持所有數(shù)據(jù)庫(kù):
//Java代碼中:
String wildcardname = ”smi”;
List<name> names = mapper.selectlike(wildcardname);
//Mapper映射文件中:
<select id=”selectlike”>
select * from foo where bar like concat("%",concat(#{value},"%"))
</select>
考核點(diǎn):Mybatis工作原理
答:
Dao接口里的方法為什么不能重載:
Dao接口,就是人們常說(shuō)的Mapper接口;
Mybatis啟動(dòng)后需要加載Mapper.xml映射文件,映射文件中每一個(gè)<select>、<insert>、<update>、<delete>標(biāo)簽,都會(huì)被解析為一個(gè)MappedStatement對(duì)象;
Mybatis會(huì)將MapperStatement對(duì)象以鍵值對(duì)的形式維護(hù)起來(lái),MappedStatementId(采用Mapper映射文件的namespace+標(biāo)簽的ID組成)作為鍵,MapperStatement對(duì)象作為值;
調(diào)用接口中的方法時(shí),通反射獲取Mapper接口的完整限定名+方法名確定MappedStatementId,然后使用MappedStatementId定位一個(gè)MappedStatement對(duì)象;
所以,Dao接口里的方法,是不能重載的,因?yàn)镸ybatis是使用MappedStatementId的尋找策略定位具體的MappedStatement對(duì)象,而MappedStatement對(duì)象就是實(shí)際調(diào)用的SQL語(yǔ)句;
Dao接口的工作原理:
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í)行MappedStatement所代表的SQL,然后將SQL執(zhí)行結(jié)果返回。
考核點(diǎn):Mybatis ORM映射。
答:
第一種是使用ResultMap標(biāo)簽,逐一定義數(shù)據(jù)庫(kù)表的字段名和實(shí)體類的屬性名之間的映射關(guān)系;
第二種是使用SQL語(yǔ)句為數(shù)據(jù)庫(kù)表的字段定義別名功能,將字段別名設(shè)置為實(shí)體類的屬性名;
設(shè)置了字段名與屬性名的映射關(guān)系后,Mybatis通過(guò)反射創(chuàng)建對(duì)象,同時(shí)使用反射給實(shí)體類的屬性逐一賦值并返回,那些找不到映射關(guān)系的屬性,是無(wú)法完成賦值的。
考核點(diǎn):動(dòng)態(tài)SQL與SQL語(yǔ)句。
答:
第一種:在Java代碼中,循環(huán)執(zhí)行指定SQL語(yǔ)句。效率低,不推薦。
首先,創(chuàng)建一個(gè)簡(jiǎn)單的insert語(yǔ)句:
<insert id=”insertname”>
insert into names (name) values (#{value})
</insert>
然后在Java代碼中像下面這樣執(zhí)行批處理插入:
list<string> names = new arraylist();
names.add(“fred”);
names.add(“barney”);
sqlsession sqlsession = sqlsessionfactory.opensession(true);
try {
namemapper mapper = sqlsession.getmapper(namemapper.class);
for (string name : names) { mapper.insertname(name); }
sqlsession.commit();
} finally { sqlsession.close(); }
第二種:支持MYSQL版本
<insert id=”insertname”>
insert into names (name) values
<foreach collections="names" item="item" separator=","> (#{item}) </foreach>
</insert>
第三種:支持Oracle并支持序列
<insert id=”insertname”>
begin
<foreach collections="names" item="item" >
insert into names (name) values (#{item});
</foreach>
end;
</insert>
第四種:通用版本,但是不支持Oracle序列
<insert id=”insertname”>
insert into names (name,gender)
<foreach collections="names" item="item" separator="union">
select #{item.name} , #{item.gender}
</foreach>
</insert>
考核點(diǎn):獲取插入后主鍵值。
答:
insert方法總是返回一個(gè)int值,這個(gè)值代表的是插入的行數(shù),而自動(dòng)生成的鍵值在insert方法執(zhí)行完后可以被設(shè)置到傳入的參數(shù)對(duì)象中。
自增列示例:
<!--
useGeneratedKeys="true":設(shè)置使用自增列的值
keyProperty="stuId":設(shè)置自增列的值存入到JavaBean的哪個(gè)屬性
-->
<insert id="insert" useGeneratedKeys="true" keyProperty="stuId" parameterType="Student">
insert into student (stuName,age,gender,address) values (#{stuName},#{age},#{gender},#{address})
</insert>
序列示例:
<insert id="insert" parameterType="Student">
<selectKey order="BEFORE" resultType="integer" keyProperty="stuId" >
select seq.nextval from dual
</selectKey>
insert into student (stuId,stuName,age,gender,address)
values (seq.currval,#{stuName},#{age},#{gender},#{address})
</insert>
或
<insert id="insert" parameterType="Student">
<selectKey order="AFTER" resultType="integer" keyProperty="stuId" >
select seq.currval from dual
</selectKey>
insert into student (stuId,stuName,age,gender,address)
values (seq.nextval,#{stuName},#{age},#{gender},#{address})
</insert>
考核點(diǎn):Mybatis參數(shù)映射。
答:
第1種:使用Mybatis默認(rèn)參數(shù)別名之“paramn”
//Mapper接口中代碼:
Public UserselectUser(String name,String area);
//Mapper.xml映射文件中代碼:
<select id="selectUser"resultMap="BaseResultMap">
select * from user_user_t where user_name = #{param1} anduser_area=#{param2}
</select>
第2種:使用Mybatis默認(rèn)參數(shù)別名之“argn”
//Mapper接口中代碼:
Public UserselectUser(String name,String area);
//Mapper.xml映射文件中代碼:
<select id="selectUser"resultMap="BaseResultMap">
select * from user_user_t where user_name = #{arg0} anduser_area=#{arg1}
</select>
第3種:使用@param注解設(shè)置別名
//Mapper接口中代碼:
public user selectuser(@param(“username”) String username, @param(“hashedpassword”)
String hashedpassword);
//Mapper.xml映射文件中代碼:
<select id=”selectuser” resulttype=”user”>
select id, username, hashedpassword from some_table
where username = #{username} and hashedpassword = #{hashedpassword}
</select>
考核點(diǎn):動(dòng)態(tài)SQL。
答:
Mybatis動(dòng)態(tài)SQL:可以讓我們?cè)赬ml映射文件內(nèi),以標(biāo)簽的形式編寫動(dòng)態(tài)SQL,完成邏輯判斷和動(dòng)態(tài)拼接SQL的功能;
Mybatis提供了10種動(dòng)態(tài)SQL標(biāo)簽:trim|where|set|foreach|if|choose|when|otherwise|include|sql;
執(zhí)行原理:使用OGNL計(jì)算表達(dá)式的值,根據(jù)表達(dá)式的值動(dòng)態(tài)拼接SQL,以此來(lái)完成動(dòng)態(tài)SQL的功能。
考核點(diǎn):Mybatis工作原理。
答:
不同的Xml映射文件,如果配置了命名空間(namespace),那么標(biāo)簽的ID可以重復(fù);如果沒有配置命名空間,那么標(biāo)簽的ID不能重復(fù),畢竟命名空間不是必須的,只是最佳實(shí)踐而已;
原因:命名空間+標(biāo)簽的ID是作為Mybatis維護(hù)MapperStatemented對(duì)象集合的key使用的,如果沒有命名空間,就剩下標(biāo)簽的ID,導(dǎo)致無(wú)法區(qū)分具體的MapperStatemented對(duì)象;
考核點(diǎn):Mybatis關(guān)聯(lián)映射。
答:
一對(duì)一的例子:
<select id="getClass" parameterType="int" resultMap="ClassesResultMap">
select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column=” teacher_id” javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
一對(duì)多的例子:
<select id="getClass2" parameterType="int" resultMap="ClassesResultMap2">
select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<collection property="students" column=” c_id” ofType="com.lcb.user.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
考核點(diǎn):Mybatis的發(fā)展歷史。
答:
維護(hù)組織:Ibatis本是apache的一個(gè)開源項(xiàng)目,2010年這個(gè)項(xiàng)目由apache software foundation 遷移到了google code,并且改名為mybatis;
接口式綁定:Mybatis實(shí)現(xiàn)了接口綁定,使用更加方便,而iBatis不支持;
關(guān)系映射的實(shí)現(xiàn)方式:IBatis實(shí)現(xiàn)關(guān)系映射使用的是子查詢,而Mybatis不但支持子查詢還增加了分步查詢,效率更高;
OGNL表達(dá)式的支持:MyBatis采用功能強(qiáng)大的基于OGNL的表達(dá)式來(lái)消除其他元素,IBatis不支持;
SQL映射的語(yǔ)法區(qū)別:動(dòng)態(tài)SQL、傳入?yún)?shù)、接收參數(shù)、存儲(chǔ)過(guò)程調(diào)用等語(yǔ)法不同。
考核點(diǎn):Mybatis工作原理。
答:
加載Mybatis全局配置文件(數(shù)據(jù)源、Mapper映射文件等),解析配置文件,Mybatis基于XML配置文件生成Configuration,和一個(gè)個(gè)MappedStatement(包括了參數(shù)映射配置、動(dòng)態(tài)SQL語(yǔ)句、結(jié)果映射配置),其對(duì)應(yīng)著<select | update | delete | insert>標(biāo)簽項(xiàng);
SqlSessionFactoryBuilder通過(guò)Configuration對(duì)象生成SqlSessionFactory,用來(lái)開啟SqlSession;
SqlSession對(duì)象完成和數(shù)據(jù)庫(kù)的交互;
用戶程序調(diào)用Mybatis接口層API(即Mapper接口中的方法);
SqlSession通過(guò)調(diào)用API的Statement ID找到對(duì)應(yīng)的MappedStatement對(duì)象;
通過(guò)Executor(負(fù)責(zé)動(dòng)態(tài)SQL的生成和查詢緩存的維護(hù))將MappedStatement對(duì)象進(jìn)行解析,SQL參數(shù)轉(zhuǎn)化、動(dòng)態(tài)SQL拼接,生成JDBC Statement對(duì)象;
JDBC執(zhí)行SQL;
借助MappedStatement中的結(jié)果映射關(guān)系,將返回結(jié)果轉(zhuǎn)化成HashMap、JavaBean等存儲(chǔ)結(jié)構(gòu)并返回。
考核點(diǎn):Mybatis映射文件。
答:
Mybatis的Mapper映射文件中的Mapper配置節(jié)的namespace屬性是命名空間。
作用:
使用類路徑的完全限定名稱的方式區(qū)分Mapper映射文件,防止SQL標(biāo)簽的ID重名;
namespace命名空間是Mybatis中mapperStatementId的重要組成部分。
考核點(diǎn):Mybatis緩存。
答:
Mybatis的一級(jí)緩存是指SqlSession,一級(jí)緩存的作用域是SqlSession,Mybaits默認(rèn)開啟一級(jí)緩存;
在同一個(gè)SqlSession中,執(zhí)行相同的SQL查詢時(shí);第一次會(huì)去查詢數(shù)據(jù)庫(kù),并寫在緩存中,第二次會(huì)直接從緩存中?。?/p>
SqlSession執(zhí)行insert、update、delete等操作commit后會(huì)清空該SqlSession緩存。
二級(jí)緩存是mapper級(jí)別的,Mybatis默認(rèn)是沒有開啟二級(jí)緩存的;
第一次調(diào)用mapper下的SQL去查詢用戶的信息,查詢到的信息會(huì)存放該mapper對(duì)應(yīng)的二級(jí)緩存區(qū)域;
第二次調(diào)用namespace下的mapper映射文件中,相同的sql去查詢用戶信息,會(huì)去對(duì)應(yīng)的二級(jí)緩存內(nèi)取結(jié)果;
如果調(diào)用相同namespace下的mapepr映射文件中增刪改sql,并執(zhí)行了commit操作,此時(shí)該緩存會(huì)清空。
總結(jié):
一級(jí)緩存同會(huì)話,很少會(huì)重復(fù)查詢,實(shí)用場(chǎng)景少;
二級(jí)緩存同namespace下(表級(jí)別緩存),執(zhí)行更新操作,即清空緩存,所以實(shí)際應(yīng)用場(chǎng)景一般使用三級(jí)緩存。
考核點(diǎn):動(dòng)態(tài)SQL
答:
if 標(biāo)簽:
if標(biāo)簽通常用于WHERE語(yǔ)句、UPDATE語(yǔ)句、INSERT語(yǔ)句中,通過(guò)判斷參數(shù)值來(lái)決定是否使用某個(gè)查詢條件、判斷是否更新某一個(gè)字段、判斷是否插入某個(gè)字段的值。
foreach標(biāo)簽:
foreach標(biāo)簽主要用于在sql中對(duì)集合進(jìn)行迭代。也常用到批量刪除、添加等操作中。
choose標(biāo)簽:
MyBatis提供了choose 元素,按順序判斷when中的條件出否成立,如果有一個(gè)成立,則choose結(jié)束。
當(dāng)choose中所有when的條件都不滿則時(shí),則執(zhí)行 otherwise中的sql。
類似于Java 的switch 語(yǔ)句,choose為switch,when為case,otherwise則為default。
where標(biāo)簽:
如果where標(biāo)簽包含的標(biāo)簽中有返回值的話,它就插入一個(gè)"where"。
此外,如果標(biāo)簽返回的內(nèi)容是以AND或OR開頭的,則它會(huì)剔除掉。
set標(biāo)簽:
使用set標(biāo)簽可以將動(dòng)態(tài)的配置set關(guān)鍵字,和剔除追加到條件末尾的任何不相關(guān)的逗號(hào)。
trim標(biāo)簽:
格式化輸出,也可以通過(guò)trim標(biāo)簽設(shè)定或忽略前后綴來(lái)實(shí)現(xiàn)格式化輸出。
sql標(biāo)簽:
當(dāng)多種類型的查詢語(yǔ)句的查詢字段或者查詢條件相同時(shí),可以將其定義為SQL片段,方便調(diào)用。
include標(biāo)簽:
用于引用定義的SQL片段。
考核點(diǎn):動(dòng)態(tài)SQL
答:
where關(guān)鍵字是SQL語(yǔ)句中的where子句,在Mybatis動(dòng)態(tài)SQL中,若直接用where子句的話可能會(huì)導(dǎo)致SQL語(yǔ)法錯(cuò)誤,查詢失?。?/p>
where標(biāo)簽為MyBatis的動(dòng)態(tài)語(yǔ)句,系統(tǒng)自動(dòng)生成where子句,并且會(huì)自動(dòng)去掉生成語(yǔ)句前面多出的"and|or"子串。
考核點(diǎn):動(dòng)態(tài)SQL
答:
foreach:循環(huán)標(biāo)記;
collection:設(shè)置循環(huán)的集合、注意接口方法參數(shù)需要使用@Param()指定取值的key,如果不設(shè)置,默認(rèn)key="list";
item:設(shè)置循環(huán)中取值一個(gè)元素的變量名稱;
separator:設(shè)置語(yǔ)句的分割符號(hào);
open:設(shè)置語(yǔ)句開始部分的子串;
close:設(shè)置語(yǔ)句結(jié)束部分的子串;
index:取出元素的索引。
相同點(diǎn):
都屬于ORM 框架;
都是對(duì)JDBC 的封裝;
都屬于持久層的框架。
不同點(diǎn):
Hibernate 是面向?qū)ο蟮?,Mybatis是面向SQL的;
Hibernate全自動(dòng)的ORM,Mybatis是半自動(dòng)的ORM;
Hibernate查詢映射實(shí)體對(duì)象必須全字段查詢,Mybatis可以不用;
Hibernate有級(jí)聯(lián)操作,Mybatis則沒有;
Hibernate編寫HQL查詢數(shù)據(jù)庫(kù)大大降低了對(duì)象和數(shù)據(jù)庫(kù)的耦合性,Mybatis提供動(dòng)態(tài)SQL,需要手寫SQL,與數(shù)據(jù)庫(kù)之間的耦合度取決于程序員所寫的SQL的方法,所以Hibernate的移植性要遠(yuǎn)大于Mybatis;
Hibernate有方言跨數(shù)據(jù)庫(kù),Mybatis 依賴于具體的數(shù)據(jù)庫(kù);
Hibernate擁有完整的日志系統(tǒng),Mybatis 則相對(duì)比較欠缺;
答:
基于SQL語(yǔ)句編程,相當(dāng)靈活,不會(huì)對(duì)應(yīng)用程序或者數(shù)據(jù)庫(kù)的現(xiàn)有設(shè)計(jì)造成任何影響,SQL寫在XML里,解除SQL與程序代碼的耦合,便于統(tǒng)一管理;提供XML標(biāo)簽,支持編寫動(dòng)態(tài)SQL語(yǔ)句,并可重用;
與JDBC相比,減少了50%以上的代碼量,消除了JDBC 大量冗余的代碼,不需要手動(dòng)開關(guān)連接;
很好的與各種數(shù)據(jù)庫(kù)兼容(因?yàn)镸yBatis 使用JDBC 來(lái)連接數(shù)據(jù)庫(kù),所以只要JDBC支持的數(shù)據(jù)庫(kù)MyBatis都支持);
能夠與Spring很好的集成;
提供映射標(biāo)簽,支持對(duì)象與數(shù)據(jù)庫(kù)的ORM字段關(guān)系映射;提供對(duì)象關(guān)系映射標(biāo)簽,支持對(duì)象關(guān)系。
答:
SQL語(yǔ)句的編寫工作量較大,尤其當(dāng)字段多、關(guān)聯(lián)表多時(shí),對(duì)開發(fā)人員編寫SQL語(yǔ)句的功底有一定要求;
SQL語(yǔ)句依賴于數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)移植性差,不能隨意更換數(shù)據(jù)庫(kù)。