欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Mybatis接口式编程的原理

程序员文章站 2024-03-05 10:23:00
mybatis 有两种实现方式 其一:通过xml配置文件实现 其二:面向接口编程的实现       &nb...

mybatis 有两种实现方式

其一:通过xml配置文件实现

其二:面向接口编程的实现

           前者原理在mybatis运行套路里面大致说了一下,此节说的是后者,面向接口的编程,可以解决掉 namespace / 传入参数 / 返回值 / 与sql关联id 等四处风险

           意思就是,mybatis配置文件dao.xml找了一个接口作为自己的代言人,并告诉其他的java对象,以后访问数据库不要再骚扰我这个dao.xml文件了,你去找我的代言人助理它会全权负责的。

           如果接口助理要全权负责dao.xml文件的所有工作,那么,dao.xml文件肯定要和代言接口交接清楚工作任务,不能然接口乱搞。

仍旧以访问数据库信息列表为例:

首先要定义一个接口imessage和dao.xml文件里面的各种配置项一一对应:

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"/> <!--主键标签--> 
  <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> 

测试:

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);           
      //方式二:通过接口调用配置文件里面的sql语句 
      imessageimessage=sqlsession.getmapper(imessage.class); 
      messagelist=imessage.querymessagelist(message); 
    } catch (ioexception e) { 
      e.printstacktrace(); 
    } 
    finally{ 
      if(sqlsession!=null) 
      { 
        sqlsession.close(); //要关闭数据库会话 
      } 
    } 
    return messagelist; 
  } 

            第一,dao.xml文件命名空间要和接口的全名保持一致:写接口的全名(包括报名com.terence.dao.imessage)方便接口找到配置文件的命名空间。

            第二,接口定义代言的sql语句对应的方法:querymessagelist(),方法名要和代言的sql语句配置项的id:querymessagelist相同,方便接口根据自己声明的方法映射到对应的配置项id。

            第三,接口声明的方法带入的形参message要和dao.xml文件对应配置项需要的参数保持一致。

            第四,接口声明的方法的返回值类型list<message>要和dao.xml文件id配置项resultmap类型一致。

            这样就完成了接口的代理工作,配置文件会告诉其他的java代码,以后通过这个接口就可以完成我本来要完成的工作,执行sql语句对数据库完成交互工作;很明显,这种接口式编程比以前的直接调用配置文件方便多了,以前直接调用配置文件,每次使用配置文件,都需要写配置文件的命名空间、id、参数和返回值,这些地方有时候会手滑写不一致,如果出错,编译器不会出现提示,开发者只能根据执行结果错误提示推敲错误的地方慢慢调试。如果使用接口式编程,通过将配置文件dao.xml和定义的接口一一匹配对应,通过接口代理配置文件,以后不管谁使用都可以直接调用接口下,不用管配置文件里面的命名空间和sql配置id,调用接口时如果出错,会自动提示,更有利于错误的查找。

            但是,如果仅仅在mybatis中使用接口式编程,并没有什么显著的效果,但是当mybatis遇到spring的时候,效果就显著了。

            当mybatis遇到spring,mybatis的核心配置文件configuration.xml中连接数据库的配置,就会取代了spring中的db层,mybatis中的sqlsession会话将会托管给spring,上述的messagedao.xml部分带入参数调用接口的部分都会托管给spring的service来完成。此时我们定义的imessage接口将会替代原来的dao层,此时的dao层只剩下接口文件和javadao.xml配置文件. 

mybatis接口式编程的原理

第一个问题,明天为什么接口imssage.querymessagelist()没有实现类,但是却可以调用对应的方法?

            首先要有一个创建代理实例的类,类里面有个方法invoke();

mapperproxy implements invocationhandler
{
 mapperproxy.invoke();
}

            当我们调用接口的时候,走的是invoke()方法,会通过proxy.newproxyinstance()加载一个代理实例,实际上也就是通过sqlsession.getmapper()来获取代理实例,即

sqlsession.getmapper()==proxy.newproxyinstance(); 
imessage imessage=sqlsession.getmapper(imessage.class);
messagelist=imessage.querymessagelist(message);

            这样,即使imessage自身没有实现类,但是通过sqlsession的getmapper方法带入接口类imessage.class,就可以获取一个imessage类型的代理实例,很明显,这里是泛型在起作用,带入什么样的类型,就得到一个什么类型的接口,原因是mybatis已经利用泛型做了强转了; 

第二个问题,既然是通过invoke()方法,它是怎么知道我们要调用sqlsession.selectlist()方法?

            因为刚初始化sqlsession的时候,加载了configuration.xml文件,并在改文件中加载了各个javadao.xml文件,而这个configuration.xml文件对应了mybatis中相关的类:configuration,接口的全名称在invoke()方法里面都可以拿到, 接口全名称.方法名==namespace.id,所以可以拿到配置文件中的查询方法。 

sqlsession的获取

public sqlsession getsqlsession() throws ioexception 
{ 
    //1、通过配置文件获取数据库连接相关信息 
    readerreader=resources.getresourceasreader("hdu/terence/config/configuration.xml"); 
    //2、通过配置信息构建sqlsessionfactory 
    sqlsessionfactoryssf=newsqlsessionfactorybuilder().build(reader); 
    //3、通过sqlsessionfactory打开数据库会话 
    sqlsessionsqlsession=ssf.opensession(); 
    return sqlsession; } 

    sqlsession通过上述配置实现,首先通过resources.getresourceasreader(“配置文件路径”)方法加载配置文件包装一个reader对象,然后通过sqlsessionfactory这个接口带入reader对象,获取一个动态代理实例,即sqlsessionfactory会话工厂,通过会话工厂得到一个会话sqlsession().   

  其中,在获取会话工厂获取实例的时候,底层实现源码是将带入的参数read作为key,找到map中对应的value值,即mapperproxyfactory。

以上所述是小编给大家介绍的mybatis接口式编程的原理,希望对大家有所帮助