这天气,热的我满头大蒜。
在上一篇博文《五鼠闹东京之执行器Executor设计原本》中,已经对Executor做了比较详细的分析,但是,测试妹纸阅读完后,表示某些地方看不懂,毫不客气的给我提出了两点修改意见。
一、看完你的Statement和PrepareStatement批处理原理图,依然不明白为何一个编译Sql 3次,而另外一个编译Sql 1次。
二、对关闭Statement对象一笔带过,不够清晰。
我准备亡羊补牢,针对上面的两个问题进行补充完善。
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表现。
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()进行了空实现。
(Made In Visual Paradigm)
即,每当调用commit、rollback、close方法时,都会先调用doFlushStatements(),然后再commit、rollback、close。
上图同样适用于其他的Executor实现类。
结语:设计原则中,有一条是“单一职责”原则,受其启发,博文也采取“单一职责”原则,一篇博文尽量分析一类知识点,避免跳跃性晕眩。
另外,大牛黄勇先生,搞了一个smartweb项目,大牛红薯先生,搞了一个J2Cache项目,大牛罗果先生,更是搞了一个高大上的Tiny项目……,羡慕崇拜之余,还是静下心来,夯实基础,希望以后咱也能体验下大牛的无敌最寂寞。