这天气,热的我满头大蒜。
在上一篇博文《五鼠闹东京之执行器Executor设计原本》中,已经对Executor做了比较详细的分析,但是,测试妹纸阅读完后,表示某些地方看不懂,毫不客气的给我提出了两点修改意见。
一、看完你的Statement和PrepareStatement批处理原理图,依然不明白为何一个编译Sql 3次,而另外一个编译Sql 1次。
二、对关闭Statement对象一笔带过,不够清晰。
我准备亡羊补牢,针对上面的两个问题进行补充完善。
1.Statement和PrepareStatement在批处理时对Sql的编译策略
insert into students(id) values(1);
insert into students(id) values(1);
insert into students(id) values(2);
insert into students(id) values(3);
上面的4个Sql,无论是Statement,还是PrepareStatement,对Sql都编译3次。因为其中第1、2条Sql是完全相同的,只会编译1次。
insert into students(id) values(?); // id=[1,2,3]
对于PrepareStatement,支持问号“?”占位符,向数据库中插入id=[1,2,3]三条记录,对Sql只编译1次,由于减少了编译次数,大幅提高了效率。
Statement不支持问号“?”占位符,向数据库中插入id=[1,2,3]三条记录,只能写成下面这样。
insert into students(id) values(1);
insert into students(id) values(2);
insert into students(id) values(3);
由于Sql不同,所以编译3次,效率较低。
以上讨论,是在批处理情况下,二者的编译Sql表现。
2.doFlushStatements()
ReuseExecutor.doFlushStatements()。
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
for (Statement stmt : statementMap.values()) {
closeStatement(stmt);
}
statementMap.clear();
return Collections.emptyList();
}
Reuse的Statement内,并没有未执行的Sql命令,所以直接close即可。
BatchExecutor.doFlushStatements()。
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
try {
List<BatchResult> results = new ArrayList<BatchResult>();
if (isRollback) {
return Collections.emptyList();
}
for (int i = 0, n = statementList.size(); i < n; i++) {
Statement stmt = statementList.get(i);
BatchResult batchResult = batchResultList.get(i);
try {
// executeBatch()
batchResult.setUpdateCounts(stmt.executeBatch());
//...
results.add(batchResult);
}
return results;
} finally {
for (Statement stmt : statementList) {
closeStatement(stmt);
}
currentSql = null;
statementList.clear();
batchResultList.clear();
}
}
BatchExecutor内保存的Statement对象内,都是有等待执行的Sql批处理命令的,所以,先执行stmt.executeBatch(),保存执行结果,然后再close。
在Executor的实现类中,只有ReuseExecutor和BatchExecutor缓存了Statement对象,所以,其他的Executor对doFlushStatements()进行了空实现。
3.flushStatements()调用时机时序图
(Made In Visual Paradigm)
即,每当调用commit、rollback、close方法时,都会先调用doFlushStatements(),然后再commit、rollback、close。
上图同样适用于其他的Executor实现类。
结语:设计原则中,有一条是“单一职责”原则,受其启发,博文也采取“单一职责”原则,一篇博文尽量分析一类知识点,避免跳跃性晕眩。
另外,大牛黄勇先生,搞了一个smartweb项目,大牛红薯先生,搞了一个J2Cache项目,大牛罗果先生,更是搞了一个高大上的Tiny项目……,羡慕崇拜之余,还是静下心来,夯实基础,希望以后咱也能体验下大牛的无敌最寂寞。
版权提示:文章出自开源中国社区,若对文章感兴趣,可关注我的开源中国社区博客(http://my.oschina.net/zudajun)。(经过网络爬虫或转载的文章,经常丢失流程图、时序图,格式错乱等,还是看原版的比较好)
来源:oschina
链接:https://my.oschina.net/u/2727738/blog/668323