Mybatis接口式編程的原理
Mybatis 有兩種實(shí)現(xiàn)方式
其一:通過(guò)xml配置文件實(shí)現(xiàn)
其二:面向接口編程的實(shí)現(xiàn)
前者原理在Mybatis運(yùn)行套路里面大致說(shuō)了一下,此節(jié)說(shuō)的是后者,面向接口的編程,可以解決掉 namespace / 傳入?yún)?shù) / 返回值 / 與Sql關(guān)聯(lián)Id 等四處風(fēng)險(xiǎn)。
意思就是,Mybatis配置文件Dao.xml找了一個(gè)接口作為自己的代言人,并告訴其他的Java對(duì)象,以后訪問數(shù)據(jù)庫(kù)不要再騷擾我這個(gè)Dao.xml文件了,你去找我的代言人助理它會(huì)全權(quán)負(fù)責(zé)的。
如果接口助理要全權(quán)負(fù)責(zé)Dao.xml文件的所有工作,那么,Dao.xml文件肯定要和代言接口交接清楚工作任務(wù),不能然接口亂搞。
仍舊以訪問數(shù)據(jù)庫(kù)信息列表為例:
首先要定義一個(gè)接口IMessage和Dao.xml文件里面的各種配置項(xiàng)一一對(duì)應(yīng):
package hdu.terence.dao; import java.util.List; import hdu.terence.bean.Message; public interface IMessage { publicList<Message> queryMessageList(Message message); }
Dao.xml文件配置:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.terence.dao.IMessage"> <resultMap type="hdu.terence.bean.Message" id="MessageResult"> <id column="id" jdbcType="INTEGER"property="id"/> <!--主鍵標(biāo)簽--> <result column="COMMAND" jdbcType="VARCHAR"property="command"/> <result column="DESCRIPTION" jdbcType="VARCHAR" property="description"/> <result column="CONTENT" jdbcType="VARCHAR"property="content"/> </resultMap> <select id="queryMessageList" parameterType="hdu.terence.bean.Message" resultMap="MessageResult"> SELECTID,COMMAND,DESCRIPTION,CONTENT FROM message WHERE 1=1 <if test="command!=null and!"".equals(command.trim())"> andCOMMAND=#{command} </if> <if test="description!=null and!"".equals(description.trim())"> andDESCRIPTION like '%' #{description} '%' </if> </select><span style="color: teal; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
測(cè)試:
public List<Message> queryMessageListByMybatis(Stringcommand,String description) { DBAccess dbAccess =new DBAccess(); SqlSession sqlSession=null; List<Message>messageList=new ArrayList<Message>(); try { sqlSession=dbAccess.getSqlSession(); Message message=new Message(); message.setCommand(command); message.setDescription(description); //方式二:通過(guò)接口調(diào)用配置文件里面的sql語(yǔ)句 IMessageimessage=sqlSession.getMapper(IMessage.class); messageList=imessage.queryMessageList(message); } catch (IOException e) { e.printStackTrace(); } finally{ if(sqlSession!=null) { sqlSession.close(); //要關(guān)閉數(shù)據(jù)庫(kù)會(huì)話 } } return messageList; }
第一,Dao.xml文件命名空間要和接口的全名保持一致:寫接口的全名(包括報(bào)名com.terence.dao.IMessage)方便接口找到配置文件的命名空間。
第二,接口定義代言的sql語(yǔ)句對(duì)應(yīng)的方法:queryMessageList(),方法名要和代言的sql語(yǔ)句配置項(xiàng)的id:queryMessageList相同,方便接口根據(jù)自己聲明的方法映射到對(duì)應(yīng)的配置項(xiàng)id。
第三,接口聲明的方法帶入的形參Message要和Dao.xml文件對(duì)應(yīng)配置項(xiàng)需要的參數(shù)保持一致。
第四,接口聲明的方法的返回值類型List<Message>要和Dao.xml文件id配置項(xiàng)resultMap類型一致。
這樣就完成了接口的代理工作,配置文件會(huì)告訴其他的Java代碼,以后通過(guò)這個(gè)接口就可以完成我本來(lái)要完成的工作,執(zhí)行Sql語(yǔ)句對(duì)數(shù)據(jù)庫(kù)完成交互工作;很明顯,這種接口式編程比以前的直接調(diào)用配置文件方便多了,以前直接調(diào)用配置文件,每次使用配置文件,都需要寫配置文件的命名空間、id、參數(shù)和返回值,這些地方有時(shí)候會(huì)手滑寫不一致,如果出錯(cuò),編譯器不會(huì)出現(xiàn)提示,開發(fā)者只能根據(jù)執(zhí)行結(jié)果錯(cuò)誤提示推敲錯(cuò)誤的地方慢慢調(diào)試。如果使用接口式編程,通過(guò)將配置文件dao.xml和定義的接口一一匹配對(duì)應(yīng),通過(guò)接口代理配置文件,以后不管誰(shuí)使用都可以直接調(diào)用接口下,不用管配置文件里面的命名空間和sql配置ID,調(diào)用接口時(shí)如果出錯(cuò),會(huì)自動(dòng)提示,更有利于錯(cuò)誤的查找。
但是,如果僅僅在Mybatis中使用接口式編程,并沒有什么顯著的效果,但是當(dāng)Mybatis遇到spring的時(shí)候,效果就顯著了。
當(dāng)Mybatis遇到Spring,Mybatis的核心配置文件Configuration.xml中連接數(shù)據(jù)庫(kù)的配置,就會(huì)取代了Spring中的DB層,Mybatis中的SqlSession會(huì)話將會(huì)托管給Spring,上述的MessageDao.xml部分帶入?yún)?shù)調(diào)用接口的部分都會(huì)托管給Spring的Service來(lái)完成。此時(shí)我們定義的IMessage接口將會(huì)替代原來(lái)的Dao層,此時(shí)的Dao層只剩下接口文件和JavaDao.xml配置文件.
Mybatis接口式編程的原理
第一個(gè)問題,明天為什么接口Imssage.queryMessageList()沒有實(shí)現(xiàn)類,但是卻可以調(diào)用對(duì)應(yīng)的方法?
首先要有一個(gè)創(chuàng)建代理實(shí)例的類,類里面有個(gè)方法invoke();
MapperProxy implements InvocationHandler { MapperProxy.invoke(); }
當(dāng)我們調(diào)用接口的時(shí)候,走的是Invoke()方法,會(huì)通過(guò)Proxy.NewProxyInstance()加載一個(gè)代理實(shí)例,實(shí)際上也就是通過(guò)sqlSession.getMapper()來(lái)獲取代理實(shí)例,即
sqlSession.getMapper()==Proxy.newProxyInstance(); IMessage imessage=sqlSession.getMapper(IMessage.class); messageList=imessage.queryMessageList(message);
這樣,即使IMessage自身沒有實(shí)現(xiàn)類,但是通過(guò)SqlSession的getMapper方法帶入接口類IMessage.class,就可以獲取一個(gè)IMessage類型的代理實(shí)例,很明顯,這里是泛型在起作用,帶入什么樣的類型,就得到一個(gè)什么類型的接口,原因是Mybatis已經(jīng)利用泛型做了強(qiáng)轉(zhuǎn)了;
第二個(gè)問題,既然是通過(guò)invoke()方法,它是怎么知道我們要調(diào)用sqlSession.selectList()方法?
因?yàn)閯偝跏蓟痵qlSession的時(shí)候,加載了Configuration.xml文件,并在改文件中加載了各個(gè)JavaDao.xml文件,而這個(gè)Configuration.xml文件對(duì)應(yīng)了Mybatis中相關(guān)的類:Configuration,接口的全名稱在Invoke()方法里面都可以拿到, 接口全名稱.方法名==namespace.id,所以可以拿到配置文件中的查詢方法。
SqlSession的獲取
public SqlSession getSqlSession() throws IOException { //1、通過(guò)配置文件獲取數(shù)據(jù)庫(kù)連接相關(guān)信息 Readerreader=Resources.getResourceAsReader("hdu/terence/config/Configuration.xml"); //2、通過(guò)配置信息構(gòu)建SqlSessionFactory SqlSessionFactorySSF=newSqlSessionFactoryBuilder().build(reader); //3、通過(guò)SqlSessionFactory打開數(shù)據(jù)庫(kù)會(huì)話 SqlSessionsqlSession=SSF.openSession(); return sqlSession; }
SqlSession通過(guò)上述配置實(shí)現(xiàn),首先通過(guò)Resources.getResourceAsReader(“配置文件路徑”)方法加載配置文件包裝一個(gè)reader對(duì)象,然后通過(guò)SqlSessionFactory這個(gè)接口帶入reader對(duì)象,獲取一個(gè)動(dòng)態(tài)代理實(shí)例,即SqlSessionFactory會(huì)話工廠,通過(guò)會(huì)話工廠得到一個(gè)會(huì)話SqlSession().
其中,在獲取會(huì)話工廠獲取實(shí)例的時(shí)候,底層實(shí)現(xiàn)源碼是將帶入的參數(shù)read作為key,找到Map中對(duì)應(yīng)的value值,即MapperProxyFactory。
以上所述是小編給大家介紹的Mybatis接口式編程的原理,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Java 代碼實(shí)例解析設(shè)計(jì)模式之監(jiān)聽者模式
所謂監(jiān)聽者模式,我理解的是構(gòu)建一個(gè)容器存放所有被監(jiān)聽的線程或?qū)ο?,監(jiān)聽每個(gè)線程或?qū)ο蟀l(fā)生的變化,若某個(gè)線程或?qū)ο笥|發(fā)指定規(guī)則,那么則對(duì)所有被監(jiān)聽的線程或?qū)ο蟾鶕?jù)業(yè)務(wù)需要做處理2021-10-10Java求s=a+aa+aaa+aaaa+aa...a 5個(gè)數(shù)相加的值
求s=a+aa+aaa+aaaa+aa...a的值,其中a是一個(gè)數(shù)字。例如2+22+222+2222+22222(此時(shí)共有5個(gè)數(shù)相加),幾個(gè)數(shù)相加有鍵盤控制2017-02-02Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件 FTP協(xié)議分析(1)
這篇文章主要介紹了Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件的第一篇,針對(duì)FTP協(xié)議進(jìn)行分析,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03