您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

MyBatis整体预览(一)

2024/6/25 1:01:17发布33次查看
题记:最近在工作之余分析了一下mybatis的源码,促使我阅读源码的原因是为了实现mybatis在物理上的分页。我们知道,mybatis是在逻辑上的分页,通过用户的查询,将结果缓存下来,在查看是否传递了rowbounds对象,在查看里面的offset和limit值,通过这两个值,从返回的结果集合中截取位于期间的值。但是这样并不是很好,可以想想,如果假设查询的数据量很大,但是有用的可以是前几条,这未免有点太浪费了。在之前,也在网上查了一下实现分页的方法,最常用的就是添加mybatis插件,实现interceptor接口,拦截statementhandler接口中的prepare方法,后面会介绍为什么拦截这个接口的这个方法。在拦截resultsethandler接口的handlerresultset方法,后面也会对其缘由进行介绍。但是这中方法虽然可以添加分页的sql语句,但是并没有将分页的offset和limit的值让mybatis动态的添加到sql中去,有人会说,可以在拦截statementhandler接口的时候我们将它们拼装上去。但是这样会容易出现sql注入的问题。所以这样不得不使我进一步的了解mybatis的内部原理。本文将就一下几个方面对mybatis的内部实现进行分析
数据管家——configuration: mybatis在运行期的基本上所有的数据都会汇总到这个类。它的初始数据是来自开发人员配置在configuration的xml配置文件。通过用户配置的environments来获得系统运行的数据库环境,如事物管理以及数据源。下面给出了最基本的配置: [html] <configuration> <environments default="development"> <environment id="development"> <transactionmanager type="jdbc" /> <datasource type="pooled"> <property name="driver" value="com.mysql.jdbc.driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useunicode=true&characterencoding=gbk"/> <property name="username" value="root"/> <property name="password" value="root"/> </datasource> </environment> </environments> <mappers> <mapper resource="com/bieber/mybatis/io/user-mapper.xml"/> </mappers> </configuration>
这些配置对于mybatis需要做哪些工作呢?通过阅读configuration的源码会发现,mybatis其实为configuration标签下面的子标签都有一个对应的变量来进行存储,例如: [java] protected final typehandlerregistry typehandlerregistry = new typehandlerregistry();
则是存储<typehandlers></typehandlers>标签下面配置的所有信息。其他的也类似可以找到。负责创建configuration对象的则是xmlconfigurationbuilder,这里将完成从配置的xml数据映射到configuration对象的数据。通过一下方法完成数据的映射: [java] private void parseconfiguration(xnode root) { try { propertieselement(root.evalnode("properties")); typealiaseselement(root.evalnode("typealiases")); pluginelement(root.evalnode("plugins")); objectfactoryelement(root.evalnode("objectfactory")); objectwrapperfactoryelement(root.evalnode("objectwrapperfactory")); settingselement(root.evalnode("settings")); environmentselement(root.evalnode("environments")); databaseidproviderelement(root.evalnode("databaseidprovider")); typehandlerelement(root.evalnode("typehandlers")); mapperelement(root.evalnode("mappers")); } catch (exception e) { throw new builderexception("error parsing sql mapper configuration. cause: " + e, e); } }
可以到,它为每个元素都对应了一个处理方法,这些方法将负责解析我们配置的xml文件。这里面我主要跟踪了几个方法的执行 www.2cto.com
(mapperelement,typehandlerelement,typealiaseselement,environmentselement)
mapperelement——orm
我们知道,mybatis支持注解形式和xml形式的orm配置。那么当然将会有两个类来处理这两种行为,它们分别是xmlmapperbuilder和mapperannotationbuilder,它们分别处理什么类型,我看我就不用说了。通过解析configuration/mappers元素来获得orm配置信息。
1)xml方式的orm配置和方式,当我们在mappers/mapper的属性中配置了url或者是resource信息的时候将触发mybatis采用xml的方式进行处理,并读取你指定的mapper路径。在xmlmapperbuilder类中有如下方法:
[java]
private void configurationelement(xnode context) { try { string namespace = context.getstringattribute("namespace"); builderassistant.setcurrentnamespace(namespace); cacherefelement(context.evalnode("cache-ref")); cacheelement(context.evalnode("cache")); parametermapelement(context.evalnodes("/mapper/parametermap")); resultmapelements(context.evalnodes("/mapper/resultmap")); sqlelement(context.evalnodes("/mapper/sql")); buildstatementfromcontext(context.evalnodes("select|insert|update|delete")); } catch (exception e) { throw new runtimeexception("error parsing mapper xml. cause: " + e, e); } }
这个方法便是读取你mapper文件中所有制的orm信息。该方法将通过调用xmlmapperbuilder的parse()方法触发。
2)注解方式配置orm信息加载,当你配置了mappers/package或者在mapper里面配置了class属性的时候将触发信息的读取,具体的过程我就再描述了,基本和上面差不多,只是读取的是注解的信息。
注意:mybatis优先处理的是注解形式的方式,并且在mapper配置中,当配置了多个属性时,resource属性优先处理。
那么在这样处理后configuration会得到怎样的数据呢?通过这些处理在configuration里面将会获得几个主要的变量值:sqlfragments,resultmaps,mappedstatements。其中sqlfragments就是我们定义在mapper里面的sql标签或者注解的内容,而resultmaps也是定义在mapper里面或者注解的resultmap内容。最重要的是mappedstatements,这是orm的最关键部分。它里面通过键值对的方式存储,key这是我们配置的id属性加上namespace,而value则是mappedstatement对象,这个对象这就对应了我们配置的select/update/delete/insert标签的值。
mappedstatement对象包含这条slq语句的id,执行的类型(inser,update,delte,select),statementtype(指定产生statement的类型,如preparedstatement),还有一个就是sqlsource接口的子类对象,在mybatis中有两种sqlsource,一种是动态的,另一种是静态的。不用解释,应该都明白,一个是生成动态sql用的,另一个这是简单静态的sql。在sqlsource中,包括你定义的sql语句,以及引入的外部sql语句块。mappedstatement最后还要包括一个重要的信息,这就是parametermap,这直接关系你定义的sql语句中通过#{propertyname}定义的动态填充值。如果你的是一个pojo对象,那么mybatis将会通过反射获得这个对象的属性,并依次填入到对应的propertyname所在的位置。
注意:此时的mappedstatement中的sql语句还是带有#{propertyname}这样占位符的字符串,还并没有解析成待问号(?)的占位符。要执行该操作是在执行具体的数据库操作的时候才替换成(?),只是为了很好的找到这个propertyname所对应的值所在的位置。
以上就将整个sqlsession的初始化过程所做的操作进行了解剖。完成这些操作之后,那么就等待用户触发对数据库的操作了。
后续将会给出,mybatis是如何触发用户自定义的插件的过程以及开发自己的typehandler。mybatis允许用户的插件可以拦截parameterhandler,resultsethandler,statementhandler,executor接口,从而进行一些操作。
本文到此继续,后续会有新的更新。如有严重不对的地方,还望各位能够及时提出,毕竟对mybatis的接触也只有一个星期,未免有些地方不对,还望大家谅解。
以上就是mybatis整体预览(一)的内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product