日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mybatis动态代理

發布時間:2025/5/22 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mybatis动态代理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 動態SQL
    • if關鍵字
    • where 標簽
    • where和if聯合使用
    • set標簽
    • trim標簽
    • foreach標簽
  • 動態代理
    • JDK自帶動態代理
    • CGLib代理
      • 演示
  • MyBatis中的動態代理

動態SQL

采用OGNL表達式來進行SQL的淘汰不需要的元素。根據不同的添加進行動態的SQL的組裝和拼接

if關鍵字

if標簽:包含test表達式 必填,通過ognl表達式進行判斷,true和false,
如果為真,會執行if中的SQL
如果為假,則不執行if中的SQL

where 標簽

where標簽作用:如果where標簽包含了具有返回值時,就會插入一個where,如果where后面的字符串以and 和or開頭的,則將他剔除

where和if聯合使用

where表達式一般和if表達式一塊使用,如果一個條件都不滿足,則不拼接where到SQL中,如果有一個或者多個if表達式成立,where會直接拼接在SQL上,并且緊隨where的表達式的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標簽

set標簽的作用,如果set標簽中的元素有返回值,就插入一個set,如果set后的字符串以逗號為結尾,則將最后的逗號剔除
set標簽和if表達式一塊使用,如果有條件滿足時,會直接拼接一個set到SQL上,并將最后一個SQL的逗號去掉

<update id="updateStudent" parameterType="student" >update student<set><if test="Sname != null ">Sname = #{Sname} ,</if><if test="Sage != null ">Sage = #{Sage} ,</if></set>where SID = #{SID}</update>

trim標簽

trim標簽使用來去除SQL語句中多余的and關鍵字、逗號,或者給SQL拼接的where、set或者values等前后綴,可以選擇性的進行插入、更顯,或者添加查詢操作
*prefix:前綴      
prefixoverride:去掉第一個and或者是or
suffix:后綴  
suffixoverride:去掉最后一個逗號(也可以是其他的標記,就像是上面前綴中的and一樣)

<select id="selectStudentByDIY" parameterType="student" resultType="student">select * from Student<trim prefix="where" prefixOverrides="and"><if test="SID != null and SID != 0">and SID = #{SID}</if><if test="Sname != null ">and Sname = #{Sname}</if></trim></select><update id="updateStudent" parameterType="student" >update student<trim prefix="set" suffixOverrides=","><if test="Sname != null ">Sname = #{Sname} ,</if><if test="Sage != null ">Sage = #{Sage} ,</if></trim>where SID = #{SID}</update>

foreach標簽

批量處理
如:
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標簽實現批量數據處理,遍歷集合對象
各屬性解釋

collection:必填,指定輸入參數類型(列表:list 數組:array hashmap:map) item:起名字,給定集合中單個元素的名稱 open:開始的字符串 close:結束的字符串 separator:數據之間的分隔符 index:索引的屬性名,當類型為數組時是當前的索引值 <select id="selectStudentByIds" resultType="student">select * from student where SID in<foreach collection="list" item="id" open="(" close=")" separator="," index="">#{id}</foreach></select>

動態代理

代理模式是設計模式之一

委托類(RealSubject):真正實現功能或者提供真實服務
代理類(Proxy):并不提供真正實現服務,而是通過調用委托類的對象的相關方法提供特定服務,可以在該服務基礎上提供一些其他的服務
subject:代理類和委托類共有的接口或者服務,提供了代理類和委托類共有方法
Client需要的服務是是通過代理類來獲取的,而真正的服務是有委托類提供的

JDK自帶動態代理

接口:

/*** 代理類和委托類共有的接口*/ public interface Iuser {void eate(); }

委托類:

/*** 委托類:具體實現接口中方法*/ public class User implements Iuser{@Overridepublic void eate() {System.out.println("User實現了eate方法");} }

代理輔助類:

/*** 代理輔助類* 要實現動態代理,則需要給定一個實現類invocationHandler接口的實現類* 該類中需要持有IUser實現類的引用*/ public class UserProxy implements InvocationHandler {private Iuser user;public UserProxy(Iuser user){this.user=user;}/*** 實現InvocationHandler接口* 重寫invoke方法* @param proxy :產生的代理對象* @param method:調用的方法* @param args :表示方法的參數* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理類自定義業務邏輯1");//調用委托類的方法method.invoke(user,args);System.out.println("代理類自定義業務邏輯2");return null;}

產生代理類的形式:

public static void main(String[] args) {/*** ClassLoader loader,指定代理輔助類的加載器* Class<?>[] interfaces,當前被代理的接口* InvocationHandler h :代理輔助類*///產生的代理類Iuser user = (Iuser) Proxy.newProxyInstance(UserProxy.class.getClassLoader(), new Class[]{Iuser.class}, new UserProxy(new User()));user.eate();}

運行結果:

通過分析:動態打理的對象的產生通過Proxy.newProxyInstance()調用產生了代理對象
代理對象調用eate方法,通過打印結果可知,其調用了invocationHandler輔助類的invoke方法,該方法下來調用委托類User的eate實現

CGLib代理

JDK自帶的動態代理使用比較簡單,缺點也是明顯的,需要目標對象實現一個或多個接口
當代理沒有接口的類,此時Proxy和InvocationHandler機制就不能使用了,此時就需要使用cglib

cglib采用字節碼技術,通過對字節碼為一個類創建子類,并在子類中采用方法攔截的技術,攔截所有父類方法的調用,順勢織入橫切技術

AOP技術的實現是使用到了JDK自帶的動態代理和CGLib動態代理的

演示

引入依賴:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.2</version></dependency>

委托類:

public class CCGlibSuper {public void doing(){System.out.println("委托類");} }

輔助類:

/*** 產生CGlib代理對象的輔助類* 實現MethodInterceptor* 該接口中的intercept方法需要實現*/ public class CGLibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public <T> T getProxy(Class<T> tClass){//設置父類enhancer.setSuperclass(tClass);enhancer.setCallback(this);//通過字節碼技術創建子類實例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中的動態代理

MyBatis中使用的是 JDK自帶動態代理模式
添加接口信息如下

configuration.addMapper(StudentMapper.class);//添加mapper

addMapper方法實現:
Configuration類:

public <T> void addMapper(Class<T> type) {mapperRegistry.addMapper(type);}

mapper實際上被添加到了mapperRegistry中
MapperRegistry類:

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();public <T> void addMapper(Class<T> type) {if (type.isInterface()) { //只添加接口if (hasMapper(type)) {//不能重復添加throw new BindingException("Type " + type + " is already known to the MapperRegistry.");}boolean loadCompleted = false;try {knownMappers.put(type, new MapperProxyFactory<T>(type));MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}}}

mybatis在執行configuration.addMapper(StudentMapper.class),最終將接口信息放到HashMap中,名稱為knownMappers,knownMappers是MapperRegistry類的私有屬性,是一個HashMap,key為當前class對象,value為一個MapperProxyFactory類型的實例

繼續看getMapper的代碼跟蹤

//通過動態代理機制(反射)產生了一個代理類(重點:動態代理模式,源碼實現)StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

getMapper實現類通過debug測試確定為DefaultSQLSession類
DefaultSQLSession類:

@Overridepublic <T> T getMapper(Class<T> type) {return configuration.<T>getMapper(type, this);}

該代碼直接調用Configuration類中的getMapper方法
Configuration類:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");}try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}

通過代碼是通過Proxy.newProxyInstance產生了一個StudentMapper接口的代理對象,mybatis為了完成mapper接口的實現運用了代理模式

總結

以上是生活随笔為你收集整理的mybatis动态代理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。