Mybatis接口式编程的原理
作者:Terence_Jing 发布时间:2023-11-27 22:16:05
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接口式编程的原理网站的支持!
来源:http://blog.csdn.net/csdn_terence/article/details/62216226


猜你喜欢
- 前言在Java8中接口中不再只有抽象方法,还可以有静态方法以及默认方法,此时的接口更像是一个类。我们一起来看看如何使用吧~Java8中,可以
- Spring课程工程构建 在IDEA 工作空间里面创建Spring文件夹。打开IDEA,file–>Open&am
- 本文实例讲述了java读取properties文件的方法。分享给大家供大家参考。具体实现方法如下:package com.test.demo
- 要说,这也是一个很简单的功能,没必要开一篇博客这么大动干戈。 对于一张知道全路径的照片,如果其路径包含后缀名的话,要取得后缀名,只需要一行代
- 背景我们项目一开始的所有提示都是中文,后来要做国际化。发现项目中的带双引号的中文居然有 2.3 w 多条!!!简直让人欲
- 悲观锁和乐观锁是面试高频问题之一,本文将对悲观锁和乐观锁简单的进行一个介绍。悲观锁(Pessimistic Locking)悲观锁在并发环境
- Mybatis Log Plugin使用今天发现大部分猿友关于查看执行sql语句的方法,只知道将其输出到控制台。然而还有更简便的方法,就是使
- 前一段时间遇到一个问题,是关于读取项目中文件资源的问题。我是一个maven工程 我把一张照片放到resource下面,然后在本地读取的时候可
- 本文实例为大家分享了Android实现文字下方加横线的具体代码,供大家参考,具体内容如下public class WhiteTextview
- 今天有同事用swagger2开发时,有一方法返回Map<String,List<Object>>出现无法解析错误。P
- 本文实例讲述了android中Bitmap用法。分享给大家供大家参考。具体如下:在Android SDK中可以支持的图片格式如下:png ,
- 闲来无事,做了一个简单的抽奖转盘的ui实现,供大家参考package com.microchange.lucky; import andro
- 前言从来没接触过flutter,我将在这里记录下我的flutter学习踩坑历程。安装就从安装开始叭,官网链接在此。先遵照官网教程来叭。系统要
- 1、System.Threading.Timer 线程计时器1、最底层、轻量级的计时器。基于线程池实现的,工作在辅助线程。2、它并不是内在线
- 前言该篇文章主要总结的是自己平时工作中使用频率比较高的Xml文档操作的一些常用方法和收集网上写的比较好的一些通用Xml文档操作的方法(主要包
- 项目里一直用的是 spring-security ,不得不说,spring-security 真是东西太多了,学习难度太大(可能我比较菜),
- 把三状态转换图放在这,方便分析方法的作用:1.Session的save()方法Session是Hibernate所有接口中最重要的接口,提供
- 基于项目需求,想要实现Post消息推送,故采用HttpClient组件进行实现,相关代码如下(注:程序采用的httpclient和httpc
- public class Change{ public static void main(String args[]){ fin
- createCoroutine 和 startCoroutine协程到底是怎么创建和启动的?本篇文章带你揭晓。在Continuation.k