Mybatis中SqlSession下的四大对象之执行器(executor)

2025-05-29 0 29

首先我先解释一下标题 四大对象是指:executor, statementhandler,parameterhandler,resulthandler对象。(为了方便下面的文章说道四大对象就专指它们)

它们都是sqlsession的底层类实现,也是插件能够拦截的四大对象。所以这里已经触及了mybatis的底层,动态代理,反射随时可以看到,如果没有第一篇作为基础,你将十分难以理解它。了解他们的协作,是插件编写的基础之一,所以这是十分的重要。

executor在sqlsession中的应用

上篇我们谈到了一个问题,一个mapper被执行是通过动态代理来完成的,然后进入到了sqlsession的方法中去。这个并不难理解,但是sqlsession内部是怎么运行的呢?答案四大对象的协作。在sqlsession它还是一个接口,mybatis内部是通过defaultsqlsession这个实现类为我们提供服务的,它比较长,但是我们不需要全部看到,我们只看到很常用的selectlist方法便可以了。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20
package org.apache.ibatis.session.defaults;

public class defaultsqlsession implements sqlsession {

private configuration configuration;

private executor executor;

private boolean autocommit;

private boolean dirty;

.......

@override

public <e> list<e> selectlist(string statement, object parameter, rowbounds rowbounds) {

try {

mappedstatement ms = configuration.getmappedstatement(statement);

return executor.query(ms, wrapcollection(parameter), rowbounds, executor.no_result_handler);

} catch (exception e) {

throw exceptionfactory.wrapexception("error querying database. cause: " + e, e);

} finally {

errorcontext.instance().reset();

}

}

......

}

我们可以看到它是通过executor去执行方法来完成查询的。

初认executor

那么我们对executor就很感兴趣,于是我们看看executor是怎么样的,首先在mybatis中有三种executor:

simpleexecutor — simple 就是普通的执行器

reuseexecutor -执行器会重用预处理语句(prepared statements)

batchexecutor –它是批量执行器

这些就是mybatis的三种执行器。你可以通过配置文件的settings里面的元素defaultexecutortype,配置它,默认是采用simpleexecutor如果你在spring运用它,那么你可以这么配置它:

?

1

2

3

4

5
<bean id="sqlsessiontemplatebatch" class="org.mybatis.spring.sqlsessiontemplate">

<constructor-arg index="0" ref="sqlsessionfactory" />

<!--更新采用批量的executor -->

<constructor-arg index="1" value="batch"/>

</bean>

这样,它便是一个批量的执行器mybatis的三个executor都有一个共同的父类——baseexecutor。

executor初始化

首先我们先了解一下mybatis是怎么样生成executor的。我们看到生成executor的地方(org.apache.ibatis.session.configuration):

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17
public executor newexecutor(transaction transaction, executortype executortype) {

executortype = executortype == null ? defaultexecutortype : executortype;

executortype = executortype == null ? executortype.simple : executortype;

executor executor;

if (executortype.batch == executortype) {

executor = new batchexecutor(this, transaction);

} else if (executortype.reuse == executortype) {

executor = new reuseexecutor(this, transaction);

} else {

executor = new simpleexecutor(this, transaction);

}

if (cacheenabled) {

executor = new cachingexecutor(executor);

}

executor = (executor) interceptorchain.pluginall(executor);

return executor;

}

这里大部分都很好理解,但是有个地方就好不好理解,它就是:

executor = (executor) interceptorchain.pluginall(executor);

这是一段非常重要的代码,它是采用责任链模式,来产生代理对象。我们需要再深入理解它,打开它具体的pluginall方法:

?

1

2

3

4

5

6
public object pluginall(object target) {

for (interceptor interceptor : interceptors) {

target = interceptor.plugin(target);

}

return target;

}

我们这里先介绍一下这段代码:

interceptor它是mybatis拦截器必须要实现的接口,换句话说,这个遍历就是遍历mybatis的拦截器。

然后调用plugin方法,这个方法是为了生成代理对象(占位)的。

于是可以想象我们的插件的代理对象将会是一层层的嵌套,所以当中任何一个插件(interceptor)都有机会拦截这个真是的服务对象(executor),则便是责任链模式,我们完全可以提供插件(interceptor),进入到代理对象的invoke方法里面,来改变executor的行为和方法。

但是我要在这里强调,当你使用插件的时候,你将改变mybatis的executor内容实现,你必须慎重的使用它。

如果要我们自己编写动态的代理,那么工作量可不小,好在mybatis为我们提供了plugin.java类来完成我们所需要的功能。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35
public class plugin implements invocationhandler {

private object target;

private interceptor interceptor;

private map<class<?>, set<method>> signaturemap;

private plugin(object target, interceptor interceptor, map<class<?>, set<method>> signaturemap) {

this.target = target;

this.interceptor = interceptor;

this.signaturemap = signaturemap;

}

public static object wrap(object target, interceptor interceptor) {

map<class<?>, set<method>> signaturemap = getsignaturemap(interceptor);

class<?> type = target.getclass();

class<?>[] interfaces = getallinterfaces(type, signaturemap);

if (interfaces.length > 0) {

return proxy.newproxyinstance(

type.getclassloader(),

interfaces,

new plugin(target, interceptor, signaturemap));

}

return target;

}

@override

public object invoke(object proxy, method method, object[] args) throws throwable {

try {

set<method> methods = signaturemap.get(method.getdeclaringclass());

if (methods != null && methods.contains(method)) {

return interceptor.intercept(new invocation(target, method, args));

}

return method.invoke(target, args);

} catch (exception e) {

throw exceptionutil.unwrapthrowable(e);

}

}

......

}

这里有一个wrap方法:它会为我们生成代理对象。一旦我们的插件和它绑定,那么我们可以想到就会进入invoke方法里面。

invoke方法:很简单,它运行首先通过class和method的过滤,看看是否需要拦截这个方法,如果被拦截,那么它就运行interceptor的intercept方法。所以当我们配置了签名,就能够拦截我们的方法。

我们先讨论那么多,我们知道后面讲插件的时候我们还会提及它,这里我们知道它会根据插件的个数生成一层层的代理对象就可以了。

executor的执行

executor的执行是依赖于statement对象来操作的,让我们以simpleexecutor的doquery方法为例子:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23
public class simpleexecutor extends baseexecutor {

......

@override

public <e> list<e> 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);

stmt = preparestatement(handler, ms.getstatementlog());

return handler.<e>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);

handler.parameterize(stmt);

return stmt;

}

}

很显然这里调度的是一个查询方法

首先它先生成statementhandler对象

通过preparestatement方法调用prepare方法初始化参数。

然后使用parameterize方法设置参数到运行环境。

然后便通过handler.<e>query(stmt, resulthandler);方法来完成结果组装。

于是我们的焦点就集中在了statementhandler对象上,下章我们将谈及它。

总结

以上所述是小编给大家介绍的mybatis中sqlsession下的四大对象执行器(executor),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对快网idc网站的支持!

原文链接:https://blog.csdn.net/ykzhen2015/article/details/50315027

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Mybatis中SqlSession下的四大对象之执行器(executor) https://www.kuaiidc.com/108762.html

相关文章

发表评论
暂无评论