mybatis动态代理
文章目錄
- 動態(tài)SQL
- if關(guān)鍵字
- where 標(biāo)簽
- where和if聯(lián)合使用
- set標(biāo)簽
- trim標(biāo)簽
- foreach標(biāo)簽
- 動態(tài)代理
- JDK自帶動態(tài)代理
- CGLib代理
- 演示
- MyBatis中的動態(tài)代理
動態(tài)SQL
采用OGNL表達(dá)式來進行SQL的淘汰不需要的元素。根據(jù)不同的添加進行動態(tài)的SQL的組裝和拼接
if關(guān)鍵字
if標(biāo)簽:包含test表達(dá)式 必填,通過ognl表達(dá)式進行判斷,true和false,
如果為真,會執(zhí)行if中的SQL
如果為假,則不執(zhí)行if中的SQL
where 標(biāo)簽
where標(biāo)簽作用:如果where標(biāo)簽包含了具有返回值時,就會插入一個where,如果where后面的字符串以and 和or開頭的,則將他剔除
where和if聯(lián)合使用
where表達(dá)式一般和if表達(dá)式一塊使用,如果一個條件都不滿足,則不拼接where到SQL中,如果有一個或者多個if表達(dá)式成立,where會直接拼接在SQL上,并且緊隨where的表達(dá)式的and或者or會被忽略
<select id="selectClass" resultType="org.example.pojo.Class">select * from<where><if test="c_id!=null">and c_id=#{c_id}</if><if test="c_name!=c_name">and c_name=#{c_name}</if></where>如果傳入c_id則SQL語句為: select * from wherec_id=#{c_id}
兩個都傳入則SQL語句為:select * from c_id=#{c_id}
set標(biāo)簽
set標(biāo)簽的作用,如果set標(biāo)簽中的元素有返回值,就插入一個set,如果set后的字符串以逗號為結(jié)尾,則將最后的逗號剔除
set標(biāo)簽和if表達(dá)式一塊使用,如果有條件滿足時,會直接拼接一個set到SQL上,并將最后一個SQL的逗號去掉
trim標(biāo)簽
trim標(biāo)簽使用來去除SQL語句中多余的and關(guān)鍵字、逗號,或者給SQL拼接的where、set或者values等前后綴,可以選擇性的進行插入、更顯,或者添加查詢操作
*prefix:前綴
prefixoverride:去掉第一個and或者是or
suffix:后綴
suffixoverride:去掉最后一個逗號(也可以是其他的標(biāo)記,就像是上面前綴中的and一樣)
foreach標(biāo)簽
批量處理
如:
insert table_name (id,name,age) values((1,1,1),(2,2,2))
select * from Student where SID in(1,2,3,4,5);
foreach標(biāo)簽實現(xiàn)批量數(shù)據(jù)處理,遍歷集合對象
各屬性解釋
動態(tài)代理
代理模式是設(shè)計模式之一
委托類(RealSubject):真正實現(xiàn)功能或者提供真實服務(wù)
代理類(Proxy):并不提供真正實現(xiàn)服務(wù),而是通過調(diào)用委托類的對象的相關(guān)方法提供特定服務(wù),可以在該服務(wù)基礎(chǔ)上提供一些其他的服務(wù)
subject:代理類和委托類共有的接口或者服務(wù),提供了代理類和委托類共有方法
Client需要的服務(wù)是是通過代理類來獲取的,而真正的服務(wù)是有委托類提供的
JDK自帶動態(tài)代理
接口:
/*** 代理類和委托類共有的接口*/ public interface Iuser {void eate(); }委托類:
/*** 委托類:具體實現(xiàn)接口中方法*/ public class User implements Iuser{@Overridepublic void eate() {System.out.println("User實現(xiàn)了eate方法");} }代理輔助類:
/*** 代理輔助類* 要實現(xiàn)動態(tài)代理,則需要給定一個實現(xiàn)類invocationHandler接口的實現(xiàn)類* 該類中需要持有IUser實現(xiàn)類的引用*/ public class UserProxy implements InvocationHandler {private Iuser user;public UserProxy(Iuser user){this.user=user;}/*** 實現(xiàn)InvocationHandler接口* 重寫invoke方法* @param proxy :產(chǎn)生的代理對象* @param method:調(diào)用的方法* @param args :表示方法的參數(shù)* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理類自定義業(yè)務(wù)邏輯1");//調(diào)用委托類的方法method.invoke(user,args);System.out.println("代理類自定義業(yè)務(wù)邏輯2");return null;}產(chǎn)生代理類的形式:
public static void main(String[] args) {/*** ClassLoader loader,指定代理輔助類的加載器* Class<?>[] interfaces,當(dāng)前被代理的接口* InvocationHandler h :代理輔助類*///產(chǎn)生的代理類Iuser user = (Iuser) Proxy.newProxyInstance(UserProxy.class.getClassLoader(), new Class[]{Iuser.class}, new UserProxy(new User()));user.eate();}運行結(jié)果:
通過分析:動態(tài)打理的對象的產(chǎn)生通過Proxy.newProxyInstance()調(diào)用產(chǎn)生了代理對象
代理對象調(diào)用eate方法,通過打印結(jié)果可知,其調(diào)用了invocationHandler輔助類的invoke方法,該方法下來調(diào)用委托類User的eate實現(xiàn)
CGLib代理
JDK自帶的動態(tài)代理使用比較簡單,缺點也是明顯的,需要目標(biāo)對象實現(xiàn)一個或多個接口
當(dāng)代理沒有接口的類,此時Proxy和InvocationHandler機制就不能使用了,此時就需要使用cglib
cglib采用字節(jié)碼技術(shù),通過對字節(jié)碼為一個類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù),攔截所有父類方法的調(diào)用,順勢織入橫切技術(shù)
AOP技術(shù)的實現(xiàn)是使用到了JDK自帶的動態(tài)代理和CGLib動態(tài)代理的
演示
引入依賴:
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.2</version></dependency>委托類:
public class CCGlibSuper {public void doing(){System.out.println("委托類");} }輔助類:
/*** 產(chǎn)生CGlib代理對象的輔助類* 實現(xiàn)MethodInterceptor* 該接口中的intercept方法需要實現(xiàn)*/ public class CGLibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public <T> T getProxy(Class<T> tClass){//設(shè)置父類enhancer.setSuperclass(tClass);enhancer.setCallback(this);//通過字節(jié)碼技術(shù)創(chuàng)建子類實例return (T)enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("代理類使用前");Object o1 = methodProxy.invokeSuper(o, objects);System.out.println("代理類使用后");return o1;}public static void main(String[] args) {CGLibProxy cgLibProxy = new CGLibProxy();CCGlibSuper proxy = cgLibProxy.getProxy(CCGlibSuper.class);proxy.doing();} }MyBatis中的動態(tài)代理
MyBatis中使用的是 JDK自帶動態(tài)代理模式
添加接口信息如下
addMapper方法實現(xiàn):
Configuration類:
mapper實際上被添加到了mapperRegistry中
MapperRegistry類:
mybatis在執(zhí)行configuration.addMapper(StudentMapper.class),最終將接口信息放到HashMap中,名稱為knownMappers,knownMappers是MapperRegistry類的私有屬性,是一個HashMap,key為當(dāng)前class對象,value為一個MapperProxyFactory類型的實例
繼續(xù)看getMapper的代碼跟蹤
//通過動態(tài)代理機制(反射)產(chǎn)生了一個代理類(重點:動態(tài)代理模式,源碼實現(xiàn))StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);getMapper實現(xiàn)類通過debug測試確定為DefaultSQLSession類
DefaultSQLSession類:
該代碼直接調(diào)用Configuration類中的getMapper方法
Configuration類:
通過代碼是通過Proxy.newProxyInstance產(chǎn)生了一個StudentMapper接口的代理對象,mybatis為了完成mapper接口的實現(xiàn)運用了代理模式
總結(jié)
以上是生活随笔為你收集整理的mybatis动态代理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: netty使用
- 下一篇: mybatis缓存机制