我和JAVA数据库操作的那些事儿(4)
通过前面几篇的介绍,对于JDBC的使用应该基本上够上项目开发的要求了。但是,总是觉得还有一些问题,比如,我写了一个DBUtil类,这个类里持有一个Connection对象,而这个对象是被所有需要使用的地方共用的。
private static Connection conn = null;
public static Connection getConnection() {
if (conn == null) {
String url = "jdbc:sqlite:test.db";
try {
synchronized (this) {
Class.forName("org.sqlite.JDBC");
conn = DriverManager.getConnection(url);
}
} catch (ClassNotFoundException e) {
conn = null;
} catch (SQLException e) {
conn = null;
}
}
return conn;
}
public static void close(Connection conn) {
// 因为connection只有一个,所以不真正关闭
/*
* if (conn != null) { try { conn.close(); } catch (SQLException e) {
*
* } conn = null; }
*/
}
可以看到,因为创建一个Connection是比较破费资源的操作,所以这个Connection是创建一次然后被公用的,而且也没有真正实现它的close方法(如果每次都用完就close,那每次都要重新创建,就失去意义了)
这样做,我总是有一点担心,因为老是觉得Connection被多线程同时使用的话,会出现一些问题。目前为止我没有做过这方面的测试,但我看到有相关的论调:
JDBC and Multithreading"The Oracle JDBC drivers provide full support for, and are highly optimized for, applications that use Java multithreading. Controlled serial access to a connection, such as that provided by connection caching, is both necessary and encouraged. However, Oracle strongly discourages sharing a database connection among multiple threads. Avoid allowing multiple threads to access a connection simultaneously. If multiple threads must share a connection, use a disciplined begin-using/end-using protocol."
也有人通过ThreadLocal的方式,让每个线程都持有一个Connection的副本,这是另外一种技术了,以后在多线程同步的相关文章里再详细介绍。
当我知道数据库连接池的时候,就把这部分工作让它去实现了。何乐而不为呢?
我用过最多的连接池是DBCP,另外也用过c3p0。下面以DBCP为例。
private static DataSource dataSource;
public static Connection getConnection() {
if (dataSource == null) {
buildDataSource();
}
try {
return dataSource.getConnection();
} catch (SQLException e) {
return null;
}
}
private static synchronized void buildDataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("org.sqlite.JDBC");
ds.setUrl("jdbc:sqlite:test.db");
dataSource = ds;
}
这里使用了DBCP的BasicDataSource(这是一个DataSource接口的实现),在这里通过BasicDataSource.getConnection() 的方法来获取连接,至于Connection的关闭,则会被放到连接池中。关于DataSource还有更多的属性,如maxActive(最大活跃数),maxIdle(最大空闲数)等。当然,更常见的做法是把这些配置放到properties文件里,后面会在引用spring的时候进行讨论。
关于BasicDataSource,从下面的类图中可以看到相应的属性。