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,从下面的类图中可以看到相应的属性。
