欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-10-28 10:15:20
最近一个小项目dao层涉及对connection的获取,优化的时候顺便了解了一下jdbc中connection使用的几个细节问题,跟大家分享一下: 1. 通常情况下,应在每个方法...

最近一个小项目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才会被返回数据库连接池。

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