一媒介:
以前刚开始用Java毗连MySQL时,图纸加密,都是连猜带蒙的。好比:
一个Statement,Connection何时封锁?
Connection能不能先于Statement封锁?
ResultSet是奈何存放数据的?奈何才气高效哄骗ResultSet?
PrepareStatement到底是奈何回事?
毗连池是奈何事情的?
二、从JDBC driver代码阐明:
在机能要求高的处所,该当利用ResultSet.get**(int)系列函数
如ResultSet.getBytes(String columnName),
则会先会挪用findColumn(columnName)去查找到columnName对应的index是什么,而在findColumn(columnName)函数中,
会查抄索引有没有构建好了,假如还没有则要构建columnName对应的索引。
所以,假如对机能要求,则应该利用ResultSet.getBytes(int column)函数。
PreparedStatement的缓存及重用
对付PreparedStatement,会有一个LRUCache来存放,会先到内里去取,拿不到再建设一个新的。
这个LRUCache的默认巨细是25(太小了吧。。)。对付sql长度,假如大于256的,软件开发,貌似则不缓存这个PreparedStatement。
LRUCache很简朴,代码:
public class LRUCache extends LinkedHashMap { protected int maxElements; public LRUCache(int maxSize) { super(maxSize); this.maxElements = maxSize; } protected boolean removeEldestEntry(Entry eldest) { return (size() > this.maxElements); }
LinkedHashMap在每次put和putAll后,会挪用removeEldestEntry来判定是否要移除最老的Entry。
LinkedHashMap的实现也较量简朴,内里用双向链表把所有的Entry串在一起,当挪用get时,把get地址的key移到链表的最前面。
PreparedStatement是如何实现重用的:
pStmt = (com.mysql.jdbc.ServerPreparedStatement)this.serverSideStatementCache.remove(sql); if (pStmt != null) { ((com.mysql.jdbc.ServerPreparedStatement)pStmt).setClosed(false); pStmt.clearParameters(); }
可见只是配置未封锁,再排除Parameters。所以从代码上来说,我们获得一个PreparedStatement在利用后,可以挪用clearParameters,再接着利用。可是最好不要这样做。
假如是想要执行多次,可以用addBatch和executeBatch函数来多次执行。
关于CallableStatement和ServerPreparedStatement
CallableStatement,ServerPreparedStatement担任自PreparedStatement,实际上prepareStatement(String sql)函数返回的就是ServerPreparedStatement,LRUCache中放的也是。
CallableStatement也有一个LRUcache。
实际上当PreparedStatement挪用close时,并没有真正释放掉资源,
Statement、Connection、ResultSet何时close
查察Statement的close函数代码,可以发明当close时,这个Statement中所有的ResultSet也会被close。
查察Connection的close函数,当close时,这个Connection的所有Statement城市被close。
可是据JDBC4的类型,有大概当Statement封锁时,ResultSet中的资源未被完全释放,当GC再次运行时才会接纳。
所以最好就是顺序封锁ResultSet,Statement,Connection。
异常处理惩罚
SQLException是可以迭代的,应该用以下的代码来处理惩罚所有的异常:
catch(SQLException ex) { while(ex != null) { System.out.println("SQLState:" + ex.getSQLState()); System.out.println("Error Code:" + ex.getErrorCode()); System.out.println("Message:" + ex.getMessage()); Throwable t = ex.getCause(); while(t != null) { System.out.println("Cause:" + t); t = t.getCause(); } ex = ex.getNextException(); } } //可能 catch(SQLException ex) { for(Throwable e : ex ) { System.out.println("Error encountered: " + e); } }
在代码Connection类的许多处所,好比void closeAllOpenStatements()函数,可以看到这样的代码:
for (int i = 0; i < numStmts; i++) { Statement stmt = (Statement) currentlyOpenStatements.get(i); try { stmt.realClose(false, true); } catch (SQLException sqlEx) { postponedException = sqlEx; // throw it later, cleanup all // statements first } }
感受这个是有问题的,因为把一些异常信息给丢掉了,实际上是可以迭代的,应该挪用setNextException函数把异常都加到一起。