首页 > 安全资讯 >

关于JDBC中Connection的使用的几个details

17-07-04

关于JDBC中Connection的使用的几个details。一般要在每个方法调用时新建connection,因为connection实例并不是线程安全的,下面给出Mysql中调用Connection实现类的方法(com mysql jdbc PreparedStatement中executeUpdate())实例。

最近一个小项目DAO层涉及对Connection的获取,优化的时候顺便了解了一下JDBC中Connection使用的几个细节问题,跟大家分享一下:

1. 通常情况下,应在每个方法调用时新建Connection。

一般要在每个方法调用时新建connection,因为connection实例并不是线程安全的,下面给出Mysql中调用Connection实现类的方法(com.mysql.jdbc.PreparedStatement中executeUpdate())实例:

/**

* com.mysql.jdbc.PreparedStatement中的executeUpdete()

* @throws SQLException

*/

protected synchronized int executeUpdate(byte[][] batchedParameterStrings,

InputStream[] batchedParameterStreams, boolean[] batchedIsStream,

int[] batchedStreamLengths, boolean[] batchedIsNull, boolean isReallyBatch)

throws SQLException {

checkClosed();

//声明MySQLConnection

MySQLConnection locallyScopedConn = this.connection;

if (locallyScopedConn.isReadOnly()) {

throw SQLError.createSQLException(Messages.getString("PreparedStatement.34") //$NON-NLS-1$

+ Messages.getString("PreparedStatement.35"), //$NON-NLS-1$

SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());

}

if ((this.firstCharOfStmt == 'S')

&& isSelectQuery()) { //$NON-NLS-1$

throw SQLError.createSQLException(Messages.getString("PreparedStatement.37"), //$NON-NLS-1$

"01S03", getExceptionInterceptor()); //$NON-NLS-1$

}

if (this.results != null) {

if (!locallyScopedConn.getHoldResultsOpenOverStatementClose()) {

this.results.realClose(false);

}

}

ResultSetInternalMethods rs = null;

// The checking and changing of catalogs

// must happen in sequence, so synchronize

// on the same mutex that _conn is using

/*注意此处,sychronized(connection实例)

catalogs的检查和更改必须按顺序进行,因此在_conn正在使用的synchronized 进行同步*/

synchronized (locallyScopedConn) {

Buffer sendPacket = fillSendPacket(batchedParameterStrings,

batchedParameterStreams, batchedIsStream,

batchedStreamLengths);

String oldCatalog = null;

if (!locallyScopedConn.getCatalog().equals(this.currentCatalog)) {

oldCatalog = locallyScopedConn.getCatalog();

locallyScopedConn.setCatalog(this.currentCatalog);

}

//

// Only apply max_rows to selects

//

if (locallyScopedConn.useMaxRows()) {

executeSimpleNonQuery(locallyScopedConn,

"SET OPTION SQL_SELECT_LIMIT=DEFAULT");

}

boolean oldInfoMsgState = false;

if (this.retrieveGeneratedKeys) {

oldInfoMsgState = locallyScopedConn.isReadInfoMsgEnabled();

locallyScopedConn.setReadInfoMsgEnabled(true);

}

rs = executeInternal(-1, sendPacket, false, false, null,

isReallyBatch);

if (this.retrieveGeneratedKeys) {

locallyScopedConn.setReadInfoMsgEnabled(oldInfoMsgState);

rs.setFirstCharOfQuery(this.firstCharOfStmt);

}

if (oldCatalog != null) {

locallyScopedConn.setCatalog(oldCatalog);

}

}

一个connection对象只能被一个线程所使用,如果涉及到多个线程同时调用同一个connection将造成数据的错乱。因此,一般应在一个方法被调用时新建connection。因此多线程情况下,可以使用数据库连接池来提升性能,数据库连接池可以保证connection实例交替被多个线程使用。

2. 使用数据库连接池时,如何保证一个线程中的所有数据库操作使用的是同一个connection。

若想要同一个线程获取到的connection为同一个有两种方法:

其一,可以使用ThreadLocal保存connection。ThreadLocal内部是用Map来保存数据。其中Map键值对的减是当前线程而值即为当前线程对于的connection。这种方法适用于要求每次请求得到的connection都是唯一的,当线程消亡时才会将connection交给数据库连接池。

在网上看到有些文章交代要看数据库连接池本身是否使用了ThreadLocal然后看了下java.sql包和javax.sql下的Connection和数据库连接池都是interface,每个DatasourcePool具体可以自己更改实现类,DatasourcePool的具体实现需要的话可以采取ThreadLocal来存放connection。

其二,可以直接交给spring去管理,在srping中每个事务和一个connection绑定,在事务回滚时该connection才会被返回数据库连接池。

自己的浅薄理解,若有异议欢迎提出~

相关文章
最新文章
热点推荐