您现在的位置:首页 >> 污染防治

java培训:MyBatis的虚拟化与原理分析

时间:2024-10-08 04:20:59

p>

return resultList;

}

3 JDBC演变到Mybatis步骤#

上头我们看见了发挥作用JDBC有七个步骤,哪些步骤是可以全面性芯片的,降低我们开发计划的编码量。

3.1 第一步可用性:相连换取和囚禁##

1、 应对办法刻画:

信息库相连频繁的敞开和关停本身就造如此一来了自然资源的浪费,阻碍系统的可靠性 。

为了让:

信息库相连的换取和关停我们可以常用信息库相连池来应对自然资源浪费的应对办法 。【关切尚矽谷,轻松专攻IT】通过相连池就可以反复依靠已经建立的相连去会面信息库了。降低相连的敞开和关停的整整。

2、应对办法刻画:

但是以前相连池多种多样,不太可能存在转变 ,不太可能会引入DBCP的相连池,也不太可能会引入试管本身的JNDI信息库相连池。

为了让:

我们可以通过DataSource展开隔离解能量守恒 ,我们统;大从DataSource里换取信息库相连,DataSource具体可能会由DBCP发挥作用还是由试管的JNDI发挥作用都可以 ,所以我们将DataSource的具体可能会发挥作用通过让浏览器装配来应对转变。

3.2 第二步可用性:SQL统;大存取##

1、应对办法刻画:

我们常用JDBC展开操控信息库时,SQL解释器连续性都散落在各个JAVA类里 ,这样有三个不足之附近:

第一,可读性很差,尽量避免保护以及想到可靠性调优。

第二,改动Java编码并不需要重新编译、打包部署。

第三,尽量避免装进SQL在信息库客户端督导(装进后还得删掉里间的Java编码,编写好的SQL解释器写好后还得通过+号在Java展开补足)。

为了让:

我们可以权衡不把SQL解释器写到Java编码里,那么把SQL解释器抽显现出哪里呢?首到时并不需要有一个统;大存放的;也,我们可以将这些SQL解释器统;大集里抽显现出装配PDF或者信息库里(以key-value的编解码器存放) 。然后通过SQL解释器的key个数去换取相异的SQL解释器。

既然我们将SQL解释器都统;大抽显现出装配PDF或者信息库里,那么这里就无关一个SQL解释器的复制到应对办法 。

3.3 第三步可用性:兴起模板射影和实时SQL

1、应对办法刻画:

很多可能会下,我们都可以通过在SQL解释器里增设标记九宫来达到常用兴起模板的目地,这种方式为本身就有一定局限性,它是按照一定顺序兴起模板的,要与标记九宫紧接著匹配。但是,如果我们兴起的模板是不确定的 (比如列详见查看,根据浏览器个人资料的查看前提有所不同,兴起查看的模板也是有所不同的,有时是一个模板、有时不太可能是三个模板),那么我们就得在后台编码里自己根据劝告的兴起模板去补足反之亦然的SQL解释器 ,这样的土话还是避免就让在Java编码里写SQL解释器的命运 。既然我们已经把SQL解释器统;大存抽显现出装配PDF或者信息库里了,怎么够能够根据一人兴起模板的有所不同,实时聚;大相异的SQL解释器呢?

为了让:

第一,我们到时应对这个实时应对办法,按照我们情况下的处理程序员认知是,通过if和else这类的推断来展开是最直观的 ,这个时候我们想到了JSTL里的这样的ID,那么,能只能将这类的ID转用到SQL解释器里呢?假定可以,那么我们这里就并不需要一个专门的SQL判别器来判别这样的SQL解释器,但是,if推断的信息一般来却说来自于哪里呢?兴起的个数本身是可变的,那么我们得为这个个数度量一个不变的信息一般来却说地名,而且这个信息一般来却说地名只能和相异的个数要有相异关连,可以通过这个信息一般来却说地名找相异的个数,这个时候我们想到了key-value的Map。判别的时候根据信息一般来却说名的具体可能会个数来推断。

假如前面可以推断无法应对办法,那么假如推断的结果是true,那么就并不需要输显现出的ID里的SQL段落,但是怎么应对在ID里常用信息一般来却说地名的应对办法呢?这里我们并不需要常用一种大不相同SQL的语言来嵌入信息一般来却说(比如常用#信息一般来却说名#) 。这样,SQL解释器经过判别后就可以实时的聚;大九宫;大词法则的SQL解释器。

还有,怎么区别于标记九宫信息一般来却说和非标记信息一般来却说?往往我们单单常用标记九宫是意味着就让的,标记九宫可能会下为查看前提标记,SQL解释器其他;也常用就让。这里我们可以常用#信息一般来却说名#详见示标记九宫信息一般来却说,常用信息一般来却说名详见示非标记九宫信息一般来却说 。

3.4 第四步可用性:结果射影和结果闪存

1、应对办法刻画:

督导SQL解释器、换取督导结果、对督导结果展开转换附近置、囚禁系统性自然资源是一整套下来的。假如是督导查看解释器,那么督导SQL解释器后,调回的是一个ResultSet结果集,这个时候我们就并不需要将ResultSet;也的信息装进来,不然等到囚禁自然资源时就取不到这些结果资讯了。

我们从前面的可用性来看,以及将换取相连、增设兴起模板、督导SQL解释器、囚禁自然资源这些都芯片起来了,只剩下结果附近置这块还无法展开芯片,如果能芯片起来,每个信息库操控都要用自己写那么一大堆Java编码,直接函数调用一个芯片的作法就可以搞定了。

为了让:

我们比对一下,一般对督导结果的有哪些附近置,不太可能会将结果不想到任何附近置就直接调回,也不太可能会将结果撷取一个JavaBean;也调回、一个Map调回、一个List调回等 `,结果附近置不太可能是多种多样的。从这里看,我们只能告诉SQL附近置器双曲线:第一,并不需要调回什么一般来却说的;也;第二,并不需要调回的;也的信息结构上怎么跟督导的结果射影 ,这样才能将具体可能会的个数copy到相异的信息结构上上。

月里,我们可以进而权衡对SQL督导结果的闪存来强化可靠性 。闪存信息都是key-value的编解码器,那么这个key怎么来呢?怎么前提唯一呢?即使同一条SQL解释器几次会面的步骤里由于兴起模板的有所不同,得到的督导SQL解释器也是有所不同的。那么闪存起来的时候是多对。但是SQL解释器和兴起模板两外;大起来可以作为信息闪存的key个数 。

3.5 第五步可用性:应对反复SQL解释器应对办法

1、应对办法刻画:

由于我们将所有SQL解释器都抽显现出装配PDF里,这个时候但会遇到一个SQL反复的应对办法 ,几个机能的SQL解释器其实都多于,有些不太可能是SELECT后面那段有所不同、有些不太可能是WHERE解释器有所不同。往往详见结构上改了,那么我们就并不需要改多个;也,尽量避免保护。

为了让:

当我们的编码处理程序显现出现反复编码时怎么办?将反复的编码抽离显现出来如此一来为独立国家的一个类,然后在各个并不需要常用的;也展开摘录 。对于SQL反复的应对办法,我们也可以引入这种方式为,通过将SQL段落的设计,将反复的SQL段落独立国家如此一来一个SQL块,然后在各个SQL解释器摘录反复的SQL块 ,这样并不需要变更时只并不需要变更一附近才会。

4 Mybaits有待改进之附近

1、应对办法刻画:

Mybaits所有的信息库操控都是基于SQL解释器,致使什么样的信息库操控都要写SQL解释器 。一个应用领域系统要写的SQL解释器却是多了。

改进作法:

我们对信息库展开的操控大外都是对详见信息的遗漏改查,很多都是对单详见的信息展开操控,由这点我们可以想到一个应对办法:单详见操控就让不写SQL解释器,通过JavaBean的预设射影器聚;大相异的SQL解释器 ,比如:一个类UserInfo相异于USER_INFO详见, userId属性相异于USER_ID配置文件。这样我们就可以通过反射光可以换取到相异的详见结构上了,补足如此一来相异的SQL解释器显然不是应对办法 。

5 MyBatis构建连续性设计者

5.1 模块层-和信息库交互的方式为

MyBatis和信息库的交互有两种方式为:

常用现代的MyBatis包括的API;

常用Mapper模块;

5.1.1 常用现代的MyBatis包括的API

这是现代的传送Statement Id 和查看模板给 SqlSession ;也,常用 SqlSession;也未完如此一来和信息库的交互 ;MyBatis包括了十分方便和非常简单的API,供浏览器发挥作用对信息库的遗漏改查信息操控,以及对信息库相连资讯和MyBatis 自身装配资讯的保护操控。

上述常用MyBatis 的作法,是首推建者一个和信息库打交道的SqlSession;也,然后根据Statement Id 和模板来操控信息库 ,这种方式为固然很非常简单和实用,但是它不九宫;大一个大;也语言的定义和一个大模块Smalltalk的Smalltalk习惯 。由于一个大模块的Smalltalk是一个大;也的大趋势,MyBatis 为了充分利用这一趋势,减低了第二种常用MyBatis 背书模块(Interface)函数调用方式为。

5.1.2 常用Mapper模块

MyBatis 将装配PDF里的每一个路由抽象为一个 Mapper 模块:

这个模块里声明的作法和路由里的 路由项相异,即 路由的id个数为Mapper 模块里的作法地名,parameterType 个数详见示Mapper 相异作法的入旋一般来却说 ,而resultMap 个数则相异了Mapper 模块详见示的调回个数一般来却说或者调回结果集的元素一般来却说 。

根据MyBatis 的装配规范装配好后,通过SqlSession.getMapper(XXXMapper.class)作法,MyBatis 但会根据反之亦然的模块声明的作法资讯,通过实时代理系统聚;大一个Mapper 示例 ,我们常用Mapper模块的某一个作法时,MyBatis但会根据这个作法的作法名和模板一般来却说,确定Statement Id,表层还是通过SqlSession.select("statementId",parameterObject);或者SqlSession.update("statementId",parameterObject); 等等来发挥作用对信息库的操控,MyBatis摘录Mapper 模块这种函数调用方式为,纯粹是为了意味着一个大模块Smalltalk的并不需要 。(其实还有一个原因是在于,一个大模块的Smalltalk,使得浏览器在模块上可以常用释义来装配SQL解释器,这样就可以脱离XML装配PDF,发挥作用“0装配”)。

5.2 信息附近置层

信息附近置层可以却说是MyBatis的当前 ,从大的不足之处上讲显现出,它要未完如此一来两个机能:

通过兴起模板发挥作用实时SQL解释器;

SQL解释器的督导以及芯片查看结果集如此一来List;

5.2.1 模板射影和实时SQL解释器聚;大

实时解释器聚;大可以却说是MyBatis构建十分与众不同的一个设计者,MyBatis 通过兴起的模板个数,常用 Ognl 来实时地构造SQL解释器 ,使得MyBatis 有要强的操纵能力和扩展性。

模板射影所指的是对于java 信息一般来却说和jdbc信息一般来却说之间的转换:这里有包括两个步骤:查看阶段 ,我们要将java一般来却说的信息,撷取jdbc一般来却说的信息,通过 preparedStatement.setXXX() 来设个数;另一个就是对resultset查看结果集的jdbcType 信息撷取java 信息一般来却说 。

5.2.2 SQL解释器的督导以及芯片查看结果集如此一来List

实时SQL解释器聚;大在此之后,MyBatis 将督导SQL解释器,并将不太可能调回的结果集撷取List列详见。

MyBatis 在对结果集的附近置里,背书结果集关连一对多和多对一的转换 ,并且有两种背书方式为,一种为嵌套查看解释器的查看,还有一种是嵌套结果集的查看 。

5.3 构建之上层

1、管理社会活动管理系统

管理社会活动管理系统对于ORM构建而言是不可缺少的一外 ,管理社会活动管理系统的质量也是顾及一个ORM构建确实高水准的一个标准。

2、相连池管理系统

由于首推建者一个信息库相连所占用的自然资源比较大,对于信息日均大和点击量十分大的应用领域而言,相连池的设计者就看上去十分最主要 。

3、闪存系统

为了全面性提高信息依靠率和减少服务器和信息库的压力,MyBatis 但会对于一些查看包括但会土话级别的信息闪存 ,但会将对某一次查看,放置到SqlSession 里,在允许的整整间隔内,对于实质上相同的查看,MyBatis但会直接将闪存结果调回给浏览器,而要用便到信息库里查找。

4、SQL解释器的装配方式为

现代的MyBatis 装配SQL解释器方式为就是常用XMLPDF展开装配的,但是这种方式为只能很差地背书一个大模块Smalltalk的理念,为了背书一个大模块的Smalltalk,MyBatis 转用了Mapper模块的定义,一个大模块的转用,对常用释义来装配SQL解释器如此一来为不太可能,浏览器只并不需要在模块上添加;大理的释义才会,要用便去装配XMLPDF了 ,但是,目前的MyBatis 只是对释义装配SQL解释器包括了依赖于的背书,某些高级机能还是要依赖XML装配PDF装配SQL 解释器。

5.4 引导层

引导层是装配和开启MyBatis装配资讯的方式为 。MyBatis 包括两种方式为来引导MyBatis :基于XML装配PDF的方式为和基于Java API 的方式为 。

5.5 主要构件及其相互关连

从MyBatis编码发挥作用的角度来看,MyBatis的主要的当前部件有表列几个:

SqlSession:作为MyBatis社会活动的主要顶层API,详见示和信息库交互的但会土话,未完如此一来;大理信息库遗漏改查机能;

Executor:MyBatis督导器,是MyBatis 分派的当前,全权负责SQL解释器的聚;大和查看闪存的保护;

StatementHandler:芯片了JDBC Statement操控,全权负责对JDBC statement 的操控,如增设模板、将Statement结果集撷取List等价。

ParameterHandler:全权负责对浏览器传送的模板撷取JDBC Statement 所并不需要的模板;

ResultSetHandler:全权负责将JDBC调回的ResultSet结果集;也撷取List一般来却说的等价;

TypeHandler:全权负责java信息一般来却说和jdbc信息一般来却说之间的射影和转换;

MappedStatement:MappedStatement保护了一条路由的芯片;

SqlSource:全权负责根据浏览器传送的parameterObject,实时地聚;大SQL解释器,将资讯芯片到BoundSql;也里,并调回;

BoundSql:详见示实时聚;大的SQL解释器以及反之亦然的模板资讯;

Configuration:MyBatis所有的装配资讯都保有在Configuration;也之里;

它们的关连如下平面图标明:

6 SqlSession社会活动步骤比对

1、敞开一个信息库会面但会土话便是便是首推建者SqlSession;也

SqlSession sqlSession = factory.openSession();

MyBatis芯片了对信息库的会面,把对信息库的但会土话和管理社会活动操纵抽显现出了SqlSession;也里

2、为SqlSession传送一个装配的Sql解释器的Statement Id和模板,然后调回结果:

List result = sqlSession.selectList("com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary",params);

上述的"com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary",是装配在EmployeesMapper.xml 的Statement ID,params是传送的查看模板。

让我们来看一下sqlSession.selectList()作法的度量:

public List selectList(String statement, Object parameter) {

return this.selectList(statement, parameter, RowBounds.DEFAULT);

}

public List selectList(String statement, Object parameter, RowBounds rowBounds) {

try {

//1.根据Statement Id,在mybatis 装配;也Configuration里查找和装配PDF相相异的MappedStatement

MappedStatement ms = configuration.getMappedStatement(statement);

//2. 将查看任务委托给MyBatis 的督导器 Executor

List result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

return result;

} catch (Exception e) {

throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);

} finally {

ErrorContext.instance().reset();

}

}

MyBatis在调用的时候,但会将MyBatis的装配资讯全部复制到到闪存里,常用org.apache.ibatis.session.Configuration示例来保护 。常用者可以常用sqlSession.getConfiguration()作法来换取。MyBatis的装配PDF里装配资讯的组织起来编解码器和闪存里;也的组织起来编解码器近乎实质上相异的 。

上述举例来却说里的:

select

EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY

from LOUIS.EMPLOYEES

where SALARY

复制到到闪存里但会聚;大一个相异的MappedStatement;也,然后但会以key="com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary" ,value为MappedStatement;也的表达方式保护到Configuration的一个Map里 。当在此在此之后并不需要常用的时候,只并不需要通过Id个数来换取就可以了。

从上述的编码里我们可以看见SqlSession的职能是:SqlSession根据Statement ID, 在mybatis装配;也Configuration里换取到相异的MappedStatement;也,然后函数调用mybatis督导器来督导具体可能会的操控 。

3、MyBatis督导器Executor根据SqlSession传送的模板督导query()作法(由于编码以致于,大众只需读到我原文则的;也才会):

/**

* BaseExecutor 类外编码

*/

public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {

// 1. 根据具体可能会兴起的模板,实时地聚;大并不需要督导的SQL解释器,用BoundSql;也详见示

BoundSql boundSql = ms.getBoundSql(parameter);

// 2. 为当前的查看首推建者一个闪存Key

CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);

return query(ms, parameter, rowBounds, resultHandler, key, boundSql);

}

@SuppressWarnings("unchecked")

public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {

ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());

if (closed) throw new ExecutorException("Executor was closed.");

if (queryStack == 0 && ms.isFlushCacheRequired()) {

clearLocalCache();

}

List list;

try {

queryStack++;

list = resultHandler == null ? (List) localCache.getObject(key) : null;

if (list != null) {

handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);

} else {

// 3.闪存里无法个数,直接从信息库里读取信息

list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);

}

} finally {

queryStack便是;

}

if (queryStack == 0) {

for (DeferredLoad deferredLoad : deferredLoads) {

deferredLoad.load();

}

deferredLoads.clear(); // issue #601

if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {

clearLocalCache(); // issue #482

}

}

return list;

}

private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {

List list;

localCache.putObject(key, EXECUTION_PLACEHOLDER);

try {

//4. 督导查看,调回List 结果,然后 将查看的结果放入闪存之里

list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);

} finally {

localCache.removeObject(key);

}

localCache.putObject(key, list);

if (ms.getStatementType() == StatementType.CALLABLE) {

localOutputParameterCache.putObject(key, parameter);

}

return list;

}

/**

* SimpleExecutor类的doQuery()作法发挥作用

*/

public List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {

Statement stmt = null;

try {

Configuration configuration = ms.getConfiguration();

//5. 根据为了将的模板,首推建者StatementHandler;也来督导查看操控

StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

//6. 首推建者java.Sql.Statement;也,传送给StatementHandler;也

stmt = prepareStatement(handler, ms.getStatementLog());

//7. 函数调用StatementHandler.query()作法,调回List结果集

return handler.query(stmt, resultHandler);

} finally {

closeStatement(stmt);

}

}

上述的Executor.query()作法几经流转,最后但会首推建者一个StatementHandler;也,然后将;大理的模板传送给StatementHandler ,常用StatementHandler来未完如此一来对信息库的查看,最终调回List结果集。

从上头的编码里我们可以显露显现出,Executor的机能和作用是:

根据传送的模板,未完如此一来SQL解释器的实时判别,聚;大BoundSql;也,供StatementHandler常用;

为查看首推建者闪存,以全面性提高可靠性;

首推建者JDBC的Statement相连;也,传送给StatementHandler;也,调回List查看结果;

4、StatementHandler;也全权负责增设Statement;也里的查看模板、附近置JDBC调回的resultSet,将resultSet研磨为List 等价调回:

接着上头的Executor第六步,看一下:prepareStatement() 作法的发挥作用:

/**

* SimpleExecutor类的doQuery()作法发挥作用

*/

public List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {

Statement stmt = null;

try {

Configuration configuration = ms.getConfiguration();

StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

// 1.准备Statement;也,并增设Statement;也的模板

stmt = prepareStatement(handler, ms.getStatementLog());

// 2. StatementHandler督导query()作法,调回List结果

return handler.query(stmt, resultHandler);

} finally {

closeStatement(stmt);

}

}

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {

Statement stmt;

Connection connection = getConnection(statementLog);

stmt = handler.prepare(connection);

//对首推建者的Statement;也增设模板,即增设SQL 解释器里 ? 增设为均须的模板

handler.parameterize(stmt);

return stmt;

}

以上我们可以总结StatementHandler;也主要未完如此一来两个社会活动:

对于JDBC的PreparedStatement一般来却说的;也,首推建者的步骤里,我们常用的是SQL解释器字九宫串但会包括 若干个? 标记九宫,我们其后便对标记九宫展开设个数。StatementHandler通过parameterize(statement)作法对Statement展开设个数;

StatementHandler通过Listquery(Statement statement, ResultHandler resultHandler)作法来未完如此一来督导Statement,和将Statement;也调回的resultSet芯片如此一来List;

5、StatementHandler 的parameterize(statement) 作法的发挥作用:

/**

* StatementHandler 类的parameterize(statement) 作法发挥作用

*/

public void parameterize(Statement statement) throws SQLException {

// 常用ParameterHandler;也来未完如此一来对Statement的设个数

parameterHandler.setParameters((PreparedStatement) statement);

}

/**

* ParameterHandler类的setParameters(PreparedStatement ps) 发挥作用

* 对某一个Statement展开增设模板

*/

public void setParameters(PreparedStatement ps) throws SQLException {

ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());

List parameterMappings = boundSql.getParameterMappings();

if (parameterMappings != null) {

for (int i = 0; i

ParameterMapping parameterMapping = parameterMappings.get(i);

if (parameterMapping.getMode() != ParameterMode.OUT) {

Object value;

String propertyName = parameterMapping.getProperty();

if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params

value = boundSql.getAdditionalParameter(propertyName);

} else if (parameterObject == null) {

value = null;

} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {

value = parameterObject;

} else {

MetaObject metaObject = configuration.newMetaObject(parameterObject);

value = metaObject.getValue(propertyName);

}

// 每一个Mapping都有一个TypeHandler,根据TypeHandler来对preparedStatement展开增设模板

TypeHandler typeHandler = parameterMapping.getTypeHandler();

JdbcType jdbcType = parameterMapping.getJdbcType();

if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();

// 增设模板

typeHandler.setParameter(ps, i + 1, value, jdbcType);

}

}

}

}

从上述的编码可以看见,StatementHandler的parameterize(Statement) 作法函数调用了 ParameterHandler的setParameters(statement) 作法,ParameterHandler的setParameters(Statement)作法全权负责 根据我们匹配的模板,对statement;也的 ? 标记九宫附近展开赋个数。

6、StatementHandler 的Listquery(Statement statement, ResultHandler resultHandler)作法的发挥作用:

/**

* PreParedStatement类的query作法发挥作用

*/

public List query(Statement statement, ResultHandler resultHandler) throws SQLException {

//1.函数调用preparedStatemnt。execute()作法,然后将resultSet交给ResultSetHandler附近置

PreparedStatement ps = (PreparedStatement) statement;

ps.execute();

//2. 常用ResultHandler来附近置ResultSet

return resultSetHandler. handleResultSets(ps);

}

从上述编码我们可以显露显现出,StatementHandler 的Listquery(Statement statement, ResultHandler resultHandler)作法的发挥作用,是函数调用了ResultSetHandler的handleResultSets(Statement) 作法。ResultSetHandler的handleResultSets(Statement) 作法但会将Statement解释器督导后聚;大的resultSet 结果集撷取List结果集:

/**

* ResultSetHandler类的handleResultSets()作法发挥作用

*/

public List handleResultSets(Statement stmt) throws SQLException {

final List multipleResults = new ArrayList();

int resultSetCount = 0;

ResultSetWrapper rsw = getFirstResultSet(stmt);

List resultMaps = mappedStatement.getResultMaps();

int resultMapCount = resultMaps.size();

validateResultMapsCount(rsw, resultMapCount);

while (rsw != null && resultMapCount> resultSetCount) {

ResultMap resultMap = resultMaps.get(resultSetCount);

//将resultSet

handleResultSet(rsw, resultMap, multipleResults, null);

rsw = getNextResultSet(stmt);

cleanUpAfterHandlingResultSet();

resultSetCount++;

}

String[] resultSets = mappedStatement.getResulSets();

if (resultSets != null) {

while (rsw != null && resultSetCount

ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);

if (parentMapping != null) {

String nestedResultMapId = parentMapping.getNestedResultMapId();

ResultMap resultMap = configuration.getResultMap(nestedResultMapId);

handleResultSet(rsw, resultMap, null, parentMapping);

}

rsw = getNextResultSet(stmt);

cleanUpAfterHandlingResultSet();

resultSetCount++;

}

}

return collapseSingleResultList(multipleResults);

}

7 MyBatis调用系统

7.1 MyBatis的调用想到了什么

任何构建的调用,便是便是-是复制到自己运转时所并不需要的装配资讯。MyBatis的装配资讯,至少包括表列资讯,其高层级结构上如下:

MyBatis的上述装配资讯但会装配在XML装配PDF里,那么,这些资讯被复制到带入MyBatis外部,MyBatis是怎样保护的呢?

MyBatis引入了一个十分口吻和非常简单的方式为便是便是常用 org.apache.ibatis.session.Configuration;也作为一个所有【关切尚矽谷,轻松专攻IT】装配资讯的试管,Configuration;也的组织起来结构上和XML装配PDF的组织起来结构上近乎实质上一样 (当然,Configuration;也的机能并不限于此,它还全权负责首推建者一些MyBatis外部常用的;也,如Executor等,这将在后续的文则章里辩论)。如下平面图标明:

Configuration;也的组织起来结构上和XML装配PDF的组织起来结构上近乎实质上一样

MyBatis根据调用好Configuration资讯,这时候浏览器就可以常用MyBatis展开信息库操控了。可以这么却说,MyBatis调用的步骤,就是首推建者 Configuration;也的步骤 。

MyBatis的调用可以有两种方式为:

基于XML装配PDF:基于XML装配PDF的方式为是将MyBatis的所有装配资讯抽显现出XMLPDF里,MyBatis通过复制到并XML装配PDF,将装配文则资讯组装如此一来外部的Configuration;也。

基于Java API:这种方式为要常用XML装配PDF,并不需要MyBatis常用者在Java编码里,手动首推建者Configuration;也,然后将装配模板set 带入Configuration;也里。

月里我们将通过基于XML装配PDF方式为的MyBatis调用,关乎MyBatis是如何通过装配PDF发挥作用Configuration;也,并常用它。

7.2 基于XML装配PDF首推建者Configuration;也

以前就从常用MyBatis的非常简单举例来却说入手,深入比对一下MyBatis是怎样未完如此一来调用的,都调用了什么。看表列编码:

String resource = "mybatis-config.xml";

InputStream inputStream = Resources.getResourceAsStream(resource);

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession sqlSession = sqlSessionFactory.openSession();

List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");

有过MyBatis常用潜能的大众但会其实,上述解释器的作用是督导

com.foo.bean.BlogMapper.queryAllBlogInfo 度量的SQL解释器,调回一个List结果集。总的来却说,上述编码个人经历了mybatis调用 便是>首推建者SqlSession 便是>督导SQL解释器 调回结果三个步骤。

上述编码的机能是根据装配PDFmybatis-config.xml 装配PDF,首推建者SqlSessionFactory;也,然后造成SqlSession,督导SQL解释器。而mybatis的调用就发生在第三句:SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 以前就让我们看看第三句到底发生了什么。

1、MyBatis调用连续性步骤:

SqlSessionFactoryBuilder根据兴起的信息流聚;大Configuration;也,然后根据Configuration;也首推建者预设的SqlSessionFactory示例。

调用的连续性步骤如下序列平面图标明:

由上平面图标明,mybatis调用要经过非常简单的表列几步:

函数调用SqlSessionFactoryBuilder;也的build(inputStream)作法;

SqlSessionFactoryBuilder但会根据匹配流inputStream等资讯首推建者XMLConfigBuilder;也;

SqlSessionFactoryBuilder函数调用XMLConfigBuilder;也的parse()作法;

XMLConfigBuilder;也调回Configuration;也;

SqlSessionFactoryBuilder根据Configuration;也首推建者一个DefaultSessionFactory;也;

SqlSessionFactoryBuilder调回 DefaultSessionFactory;也给Client,供Client常用。

SqlSessionFactoryBuilder系统性的编码如下标明:

public SqlSessionFactory build(InputStream inputStream) {

return build(inputStream, null, null);

}

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {

try {

//2. 首推建者XMLConfigBuilder;也用来判别XML装配PDF,聚;大Configuration;也

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);

//3. 将XML装配PDF内的资讯判别如此一来Java;也Configuration;也

Configuration config = parser.parse();

//4. 根据Configuration;也首推建者显现出SqlSessionFactory;也

return build(config);

} catch (Exception e) {

throw ExceptionFactory.wrapException("Error building SqlSession.", e);

} finally {

ErrorContext.instance().reset();

try {

inputStream.close();

} catch (IOException e) {

// Intentionally ignore. Prefer previous error.

}

}

}

// 从此附近可以显露显现出,MyBatis外部通过Configuration;也来首推建者SqlSessionFactory,浏览器也可以自己通过API构造好Configuration;也,函数调用此作法首推SqlSessionFactory

public SqlSessionFactory build(Configuration config) {

return new DefaultSqlSessionFactory(config);

}

上述的调用步骤里,无关到了表列几个;也:

SqlSessionFactoryBuilder :SqlSessionFactory的构造器,常用首推建者SqlSessionFactory,引入了Builder设计者种系统

Configuration :该;也是mybatis-config.xmlPDF里所有mybatis装配资讯

SqlSessionFactory:SqlSession厂房类,以厂房表达方式首推建者SqlSession;也,引入了Factory厂房设计者种系统

XMLConfigBuilder :全权负责将mybatis-config.xml装配PDF判别如此一来Configuration;也,共SqlSessonFactoryBuilder常用,首推建者SqlSessionFactory

2、首推建者Configuration;也的步骤:接着上述的 MyBatis调用连续性步骤辩论,当SqlSessionFactoryBuilder督导build()作法,函数调用了XMLConfigBuilder的parse()作法,然后调回了Configuration;也 。那么parse()作法是如何附近置XMLPDF,聚;大Configuration;也的呢?

(1)XMLConfigBuilder但会将XML装配PDF的资讯转换为Document;也 ,而XML装配度量PDFDTD撷取XMLMapperEntityResolver;也 ,然后将二者芯片到XpathParser;也里,XpathParser的作用是包括根据Xpath详见达式换取连续性的DOM路由Node资讯的操控 。如下平面图标明:

(2)在此之后XMLConfigBuilder函数调用parse()作法:但会从XPathParser里装进路由相异的Node;也,然后判别此Node路由的孙子Node:properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers:

public Configuration parse() {

if (parsed) {

throw new BuilderException("Each XMLConfigBuilder can only be used once.");

}

parsed = true;

//CVS里无法这一句,只有parseConfiguration(parser.evalNode("/configuration"));

//为了让大众看得更明晰,CVS拆分作表列两句

XNode configurationNode = parser.evalNode("/configuration");

parseConfiguration(configurationNode);

return configuration;

}

/**

* 判别 "/configuration"路由下的孙子路由资讯,然后将判别的结果增设到Configuration;也里

*/

private void parseConfiguration(XNode root) {

try {

//1.首到时附近置properties 路由

propertiesElement(root.evalNode("properties")); //issue #117 read properties first

//2.附近置typeAliases

typeAliasesElement(root.evalNode("typeAliases"));

//3.附近置API

pluginElement(root.evalNode("plugins"));

//4.附近置objectFactory

objectFactoryElement(root.evalNode("objectFactory"));

//5.objectWrapperFactory

objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));

//6.settings

settingsElement(root.evalNode("settings"));

//7.附近置environments

environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631

//8.database

databaseIdProviderElement(root.evalNode("databaseIdProvider"));

//9.typeHandlers

typeHandlerElement(root.evalNode("typeHandlers"));

//10.mappers

mapperElement(root.evalNode("mappers"));

} catch (Exception e) {

throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);

}

}

肯定:在上述编码里,还有一个十分最主要的;也,就是判别XML装配PDF孙子路由的作法mapperElements(root.evalNode("mappers")), 它将判别我们装配的Mapper.xml装配PDF,Mapper装配PDF可以却说是MyBatis的当前,MyBatis的特性和www.atguigu.com理念都体以前此Mapper的装配和设计者上。

(3)然后将这些个数判别显现出来增设到Configuration;也里:判别孙子路由的步骤这里就不紧接著介绍了,浏览器可以简介MyBatisCVS正确地推敲,我们就看上述的environmentsElement(root.evalNode("environments")); 作法是如何将environments的资讯判别显现出来,增设到Configuration;也里的:

/**

* 判别environments路由,并将结果增设到Configuration;也里

* 肯定:首推建者envronment时,如果SqlSessionFactoryBuilder均须了特定的生态系统(即信息集);

* 则调回均须生态系统(信息集)的Environment;也,否则调回预设的Environment;也;

* 这种方式为发挥作用了MyBatis可以相连多信息集

*/

private void environmentsElement(XNode context) throws Exception {

if (context != null)

{

if (environment == null)

{

environment = context.getStringAttribute("default");

}

for (XNode child : context.getChildren())

{

String id = child.getStringAttribute("id");

if (isSpecifiedEnvironment(id))

{

//1.首推建者管理社会活动厂房 TransactionFactory

TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));

DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));

//2.首推建者信息集DataSource

DataSource dataSource = dsFactory.getDataSource();

//3. 构造Environment;也

Environment.Builder environmentBuilder = new Environment.Builder(id)

.transactionFactory(txFactory)

.dataSource(dataSource);

//4. 将首推建者的Envronment;也增设到configuration ;也里

configuration.setEnvironment(environmentBuilder.build());

}

}

}

}

private boolean isSpecifiedEnvironment(String id)

{

if (environment == null)

{

throw new BuilderException("No environment specified.");

}

else if (id == null)

{

throw new BuilderException("Environment requires an id attribute.");

}

else if (environment.equals(id))

{

return true;

}

return false;

}

(4)调回Configuration;也:将上述的MyBatis调用连续性步骤的序列平面图细化:

7.3 基于Java API手动复制到XML装配PDF首推建者Configuration;也,并常用SqlSessionFactory;也##

我们可以常用XMLConfigBuilder手动判别XML装配PDF来首推建者Configuration;也,编码如下:

String resource = "mybatis-config.xml";

InputStream inputStream = Resources.getResourceAsStream(resource);

// 手动首推建者XMLConfigBuilder,并判别首推建者Configuration;也

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, null,null);

Configuration configuration=parse();

// 常用Configuration;也首推建者SqlSessionFactory

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

// 常用MyBatis

SqlSession sqlSession = sqlSessionFactory.openSession();

List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");

7.4 无关到的设计者种系统

调用的步骤无关到首推建者各种;也,所以但会常用一些首推建者改型的设计者种系统。在调用的步骤里,Builder种系统运用的比较多 。

7.4.1 Builder种系统应用领域1:SqlSessionFactory的首推建者

对于首推建者SqlSessionFactory时,但会根据可能会包括有所不同的模板,其模板组;大可以有表列几种 :

根据可能会包括有所不同的模板,首推建者SqlSessionFactory

由于构造时模板不定,可以为其首推建者一个构造器Builder,将SqlSessionFactory的发挥作用步骤和详见示分开 :

MyBatis将SqlSessionFactoryBuilder和SqlSessionFactory相互独立国家

7.4.2 Builder种系统应用领域2:信息库相连生态系统Environment;也的首推建者

在发挥作用Configuration;也的步骤里,XMLConfigBuilder判别 mybatis XML装配PDF路由路由时,但会有表列反之亦然的编码:

private void environmentsElement(XNode context) throws Exception {

if (context != null) {

if (environment == null) {

environment = context.getStringAttribute("default");

}

for (XNode child : context.getChildren()) {

String id = child.getStringAttribute("id");

//是和预设的生态系统相同时,判别之

if (isSpecifiedEnvironment(id)) {

TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));

DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));

DataSource dataSource = dsFactory.getDataSource();

//常用了Environment配有的构造器Builder,传送id 管理社会活动厂房和信息集

Environment.Builder environmentBuilder = new Environment.Builder(id)

.transactionFactory(txFactory)

.dataSource(dataSource);

configuration.setEnvironment(environmentBuilder.build());

}

}

}

}

在Environment外部,度量了静态外部Builder类:

public final class Environment {

private final String id;

private final TransactionFactory transactionFactory;

private final DataSource dataSource;

public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {

if (id == null) {

throw new IllegalArgumentException("Parameter 'id' must not be null");

}

if (transactionFactory == null) {

throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");

}

this.id = id;

if (dataSource == null) {

throw new IllegalArgumentException("Parameter 'dataSource' must not be null");

}

this.transactionFactory = transactionFactory;

this.dataSource = dataSource;

}

public static class Builder {

private String id;

private TransactionFactory transactionFactory;

private DataSource dataSource;

public Builder(String id) {

this.id = id;

}

public Builder transactionFactory(TransactionFactory transactionFactory) {

this.transactionFactory = transactionFactory;

return this;

}

public Builder dataSource(DataSource dataSource) {

this.dataSource = dataSource;

return this;

}

public String id() {

return this.id;

}

public Environment build() {

return new Environment(this.id, this.transactionFactory, this.dataSource);

}

}

public String getId() {

return this.id;

}

public TransactionFactory getTransactionFactory() {

return this.transactionFactory;

}

public DataSource getDataSource() {

return this.dataSource;

}

}

文则章来源于码农小助手

推荐读到:

MyBatis全局装配PDF

java实习:MyBatis高级进阶专攻习分享

Java开发计划构建之Mybatis初阶为基础

java开发计划之Spring集如此一来MyBatis专业知识分享

温州白癜风检查
青岛妇科医院哪家比较好
锦州精神心理专业医院
着凉拉肚子可以吃必奇吗
腹部受凉拉肚子能怎么办
双醋瑞因几周见效
止鼾喷剂对健康有害吗
前列腺增生夜尿多用什么药
相关阅读