考核點(diǎn):
Mybatis占位符的使用。
答:
#{}是預(yù)編譯處理,${}是字符串替換;
Mybatis在處理#{}時,會將SQL中的#{}替換為?,本質(zhì)上是調(diào)用PreparedStatement實(shí)現(xiàn)執(zhí)行命令;
Mybatis在處理${}時,就是把${}替換成變量的值,本質(zhì)上是調(diào)用Statement實(shí)現(xiàn)執(zhí)行命令;
使用#{}可以有效的防止SQL注入,提高系統(tǒng)安全性。
考核點(diǎn):ORM映射。
答:
第1種:通過在查詢的SQL語句中定義字段名的別名,讓字段名的別名和實(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種:通過resultMap標(biāo)簽來映射字段名和實(shí)體類屬性名的一一對應(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屬性來映射主鍵字段–>
<id property=”id” column=”order_id”>
<!–用result屬性來映射非主鍵字段,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語句中拼接通配符(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語句中使用Concat函數(shù)拼接通配符,支持所有數(shù)據(jù)庫:
//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接口,就是人們常說的Mapper接口;
Mybatis啟動后需要加載Mapper.xml映射文件,映射文件中每一個<select>、<insert>、<update>、<delete>標(biāo)簽,都會被解析為一個MappedStatement對象;
Mybatis會將MapperStatement對象以鍵值對的形式維護(hù)起來,MappedStatementId(采用Mapper映射文件的namespace+標(biāo)簽的ID組成)作為鍵,MapperStatement對象作為值;
調(diào)用接口中的方法時,通反射獲取Mapper接口的完整限定名+方法名確定MappedStatementId,然后使用MappedStatementId定位一個MappedStatement對象;
所以,Dao接口里的方法,是不能重載的,因?yàn)镸ybatis是使用MappedStatementId的尋找策略定位具體的MappedStatement對象,而MappedStatement對象就是實(shí)際調(diào)用的SQL語句;
Dao接口的工作原理:
Dao接口的工作原理是JDK動態(tài)代理,Mybatis運(yùn)行時會使用JDK動態(tài)代理為Dao接口生成代理proxy對象;
代理對象proxy會攔截接口方法,轉(zhuǎn)而執(zhí)行MappedStatement所代表的SQL,然后將SQL執(zhí)行結(jié)果返回。
考核點(diǎn):Mybatis ORM映射。
答:
第一種是使用ResultMap標(biāo)簽,逐一定義數(shù)據(jù)庫表的字段名和實(shí)體類的屬性名之間的映射關(guān)系;
第二種是使用SQL語句為數(shù)據(jù)庫表的字段定義別名功能,將字段別名設(shè)置為實(shí)體類的屬性名;
設(shè)置了字段名與屬性名的映射關(guān)系后,Mybatis通過反射創(chuàng)建對象,同時使用反射給實(shí)體類的屬性逐一賦值并返回,那些找不到映射關(guān)系的屬性,是無法完成賦值的。
考核點(diǎn):動態(tài)SQL與SQL語句。
答:
第一種:在Java代碼中,循環(huán)執(zhí)行指定SQL語句。效率低,不推薦。
首先,創(chuàng)建一個簡單的insert語句:
<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方法總是返回一個int值,這個值代表的是插入的行數(shù),而自動生成的鍵值在insert方法執(zhí)行完后可以被設(shè)置到傳入的參數(shù)對象中。
自增列示例:
<!--
useGeneratedKeys="true":設(shè)置使用自增列的值
keyProperty="stuId":設(shè)置自增列的值存入到JavaBean的哪個屬性
-->
<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):動態(tài)SQL。
答:
Mybatis動態(tài)SQL:可以讓我們在Xml映射文件內(nèi),以標(biāo)簽的形式編寫動態(tài)SQL,完成邏輯判斷和動態(tài)拼接SQL的功能;
Mybatis提供了10種動態(tài)SQL標(biāo)簽:trim|where|set|foreach|if|choose|when|otherwise|include|sql;
執(zhí)行原理:使用OGNL計(jì)算表達(dá)式的值,根據(jù)表達(dá)式的值動態(tài)拼接SQL,以此來完成動態(tài)SQL的功能。
考核點(diǎn):Mybatis工作原理。
答:
不同的Xml映射文件,如果配置了命名空間(namespace),那么標(biāo)簽的ID可以重復(fù);如果沒有配置命名空間,那么標(biāo)簽的ID不能重復(fù),畢竟命名空間不是必須的,只是最佳實(shí)踐而已;
原因:命名空間+標(biāo)簽的ID是作為Mybatis維護(hù)MapperStatemented對象集合的key使用的,如果沒有命名空間,就剩下標(biāo)簽的ID,導(dǎo)致無法區(qū)分具體的MapperStatemented對象;
考核點(diǎn):Mybatis關(guān)聯(lián)映射。
答:
一對一的例子:
<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>
一對多的例子:
<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的一個開源項(xiàng)目,2010年這個項(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á)式來消除其他元素,IBatis不支持;
SQL映射的語法區(qū)別:動態(tài)SQL、傳入?yún)?shù)、接收參數(shù)、存儲過程調(diào)用等語法不同。
考核點(diǎn):Mybatis工作原理。
答:
加載Mybatis全局配置文件(數(shù)據(jù)源、Mapper映射文件等),解析配置文件,Mybatis基于XML配置文件生成Configuration,和一個個MappedStatement(包括了參數(shù)映射配置、動態(tài)SQL語句、結(jié)果映射配置),其對應(yīng)著<select | update | delete | insert>標(biāo)簽項(xiàng);
SqlSessionFactoryBuilder通過Configuration對象生成SqlSessionFactory,用來開啟SqlSession;
SqlSession對象完成和數(shù)據(jù)庫的交互;
用戶程序調(diào)用Mybatis接口層API(即Mapper接口中的方法);
SqlSession通過調(diào)用API的Statement ID找到對應(yīng)的MappedStatement對象;
通過Executor(負(fù)責(zé)動態(tài)SQL的生成和查詢緩存的維護(hù))將MappedStatement對象進(jìn)行解析,SQL參數(shù)轉(zhuǎn)化、動態(tài)SQL拼接,生成JDBC Statement對象;
JDBC執(zhí)行SQL;
借助MappedStatement中的結(jié)果映射關(guān)系,將返回結(jié)果轉(zhuǎn)化成HashMap、JavaBean等存儲結(jié)構(gòu)并返回。
考核點(diǎn):Mybatis映射文件。
答:
Mybatis的Mapper映射文件中的Mapper配置節(jié)的namespace屬性是命名空間。
作用:
使用類路徑的完全限定名稱的方式區(qū)分Mapper映射文件,防止SQL標(biāo)簽的ID重名;
namespace命名空間是Mybatis中mapperStatementId的重要組成部分。
考核點(diǎn):Mybatis緩存。
答:
Mybatis的一級緩存是指SqlSession,一級緩存的作用域是SqlSession,Mybaits默認(rèn)開啟一級緩存;
在同一個SqlSession中,執(zhí)行相同的SQL查詢時;第一次會去查詢數(shù)據(jù)庫,并寫在緩存中,第二次會直接從緩存中??;
SqlSession執(zhí)行insert、update、delete等操作commit后會清空該SqlSession緩存。
二級緩存是mapper級別的,Mybatis默認(rèn)是沒有開啟二級緩存的;
第一次調(diào)用mapper下的SQL去查詢用戶的信息,查詢到的信息會存放該mapper對應(yīng)的二級緩存區(qū)域;
第二次調(diào)用namespace下的mapper映射文件中,相同的sql去查詢用戶信息,會去對應(yīng)的二級緩存內(nèi)取結(jié)果;
如果調(diào)用相同namespace下的mapepr映射文件中增刪改sql,并執(zhí)行了commit操作,此時該緩存會清空。
總結(jié):
一級緩存同會話,很少會重復(fù)查詢,實(shí)用場景少;
二級緩存同namespace下(表級別緩存),執(zhí)行更新操作,即清空緩存,所以實(shí)際應(yīng)用場景一般使用三級緩存。
考核點(diǎn):動態(tài)SQL
答:
if 標(biāo)簽:
if標(biāo)簽通常用于WHERE語句、UPDATE語句、INSERT語句中,通過判斷參數(shù)值來決定是否使用某個查詢條件、判斷是否更新某一個字段、判斷是否插入某個字段的值。
foreach標(biāo)簽:
foreach標(biāo)簽主要用于在sql中對集合進(jìn)行迭代。也常用到批量刪除、添加等操作中。
choose標(biāo)簽:
MyBatis提供了choose 元素,按順序判斷when中的條件出否成立,如果有一個成立,則choose結(jié)束。
當(dāng)choose中所有when的條件都不滿則時,則執(zhí)行 otherwise中的sql。
類似于Java 的switch 語句,choose為switch,when為case,otherwise則為default。
where標(biāo)簽:
如果where標(biāo)簽包含的標(biāo)簽中有返回值的話,它就插入一個"where"。
此外,如果標(biāo)簽返回的內(nèi)容是以AND或OR開頭的,則它會剔除掉。
set標(biāo)簽:
使用set標(biāo)簽可以將動態(tài)的配置set關(guān)鍵字,和剔除追加到條件末尾的任何不相關(guān)的逗號。
trim標(biāo)簽:
格式化輸出,也可以通過trim標(biāo)簽設(shè)定或忽略前后綴來實(shí)現(xiàn)格式化輸出。
sql標(biāo)簽:
當(dāng)多種類型的查詢語句的查詢字段或者查詢條件相同時,可以將其定義為SQL片段,方便調(diào)用。
include標(biāo)簽:
用于引用定義的SQL片段。
考核點(diǎn):動態(tài)SQL
答:
where關(guān)鍵字是SQL語句中的where子句,在Mybatis動態(tài)SQL中,若直接用where子句的話可能會導(dǎo)致SQL語法錯誤,查詢失??;
where標(biāo)簽為MyBatis的動態(tài)語句,系統(tǒng)自動生成where子句,并且會自動去掉生成語句前面多出的"and|or"子串。
考核點(diǎn):動態(tài)SQL
答:
foreach:循環(huán)標(biāo)記;
collection:設(shè)置循環(huán)的集合、注意接口方法參數(shù)需要使用@Param()指定取值的key,如果不設(shè)置,默認(rèn)key="list";
item:設(shè)置循環(huán)中取值一個元素的變量名稱;
separator:設(shè)置語句的分割符號;
open:設(shè)置語句開始部分的子串;
close:設(shè)置語句結(jié)束部分的子串;
index:取出元素的索引。
相同點(diǎn):
都屬于ORM 框架;
都是對JDBC 的封裝;
都屬于持久層的框架。
不同點(diǎn):
Hibernate 是面向?qū)ο蟮模琈ybatis是面向SQL的;
Hibernate全自動的ORM,Mybatis是半自動的ORM;
Hibernate查詢映射實(shí)體對象必須全字段查詢,Mybatis可以不用;
Hibernate有級聯(lián)操作,Mybatis則沒有;
Hibernate編寫HQL查詢數(shù)據(jù)庫大大降低了對象和數(shù)據(jù)庫的耦合性,Mybatis提供動態(tài)SQL,需要手寫SQL,與數(shù)據(jù)庫之間的耦合度取決于程序員所寫的SQL的方法,所以Hibernate的移植性要遠(yuǎn)大于Mybatis;
Hibernate有方言跨數(shù)據(jù)庫,Mybatis 依賴于具體的數(shù)據(jù)庫;
Hibernate擁有完整的日志系統(tǒng),Mybatis 則相對比較欠缺;
答:
基于SQL語句編程,相當(dāng)靈活,不會對應(yīng)用程序或者數(shù)據(jù)庫的現(xiàn)有設(shè)計(jì)造成任何影響,SQL寫在XML里,解除SQL與程序代碼的耦合,便于統(tǒng)一管理;提供XML標(biāo)簽,支持編寫動態(tài)SQL語句,并可重用;
與JDBC相比,減少了50%以上的代碼量,消除了JDBC 大量冗余的代碼,不需要手動開關(guān)連接;
很好的與各種數(shù)據(jù)庫兼容(因?yàn)镸yBatis 使用JDBC 來連接數(shù)據(jù)庫,所以只要JDBC支持的數(shù)據(jù)庫MyBatis都支持);
能夠與Spring很好的集成;
提供映射標(biāo)簽,支持對象與數(shù)據(jù)庫的ORM字段關(guān)系映射;提供對象關(guān)系映射標(biāo)簽,支持對象關(guān)系。
答:
SQL語句的編寫工作量較大,尤其當(dāng)字段多、關(guān)聯(lián)表多時,對開發(fā)人員編寫SQL語句的功底有一定要求;
SQL語句依賴于數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫移植性差,不能隨意更換數(shù)據(jù)庫。