先上一段很原始的纯JDBC操作mysql代码
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8", "root", "123456");
try {
String sql = "select CURRENT_TIMESTAMP";
Statement stmt = connection.createStatement();
try {
ResultSet rs = stmt.executeQuery(sql);
try {
while (rs.next()) {
System.out.println(rs.getTimestamp("CURRENT_TIMESTAMP"));
}
} finally {
rs.close();
}
} finally {
stmt.close();
}
} finally {
connection.close();
}
很简单的纯jdbc操作数据示例,相信大家在接触java初涉数据库部分的时候,都学习过这段代码,今天我想说说第一行代码
第一行之所以能够注册驱动,是因为在com.mysql.jdbc.Driver实现中,存在一个静态代码块,调用了 java.sql.DriverManager.registerDriver(new Driver()); 这就注册驱动了
第一行也可以改写成:DriverManager.registerDriver(new com.mysql.jdbc.Driver());
这是最早的两种注册驱动机制了,不过这种机制存在一个问题,就是不遵守直线型代码约定,所谓直线型代码就是代码在所处上下文环境中依赖关系非常的明显,如下:
data = ReadData();
results = CalculateResultsFromData(data);
PrintResults(results);
这段代码有着非常明确的顺序,第三条依赖第二条,第二条依赖第一条,而下面这种写法,依赖关系就不明显了。
revenue.ComputeMonthly();
revenue.ComputeQuarterly();
revenue.ComputeAnnual();
前面注册驱动的写法,与这个类似,依赖关系不明显,很可能导致在实现的时候或者维护的时候发生漏写(没有注册驱动而出错的例子还是经常发生)、顺序错乱而编译期发现不了的问题
上面两个例子摘自《代码大全2》,根据《代码大全2》中的指导思想,我们首先要尽力写没有顺序依赖关系的代码,其次尽力写依赖关系明显的代码。
自JDK1.6开始,提供了ServiceLoader,可以主动加载服务,并且在jdk自带的DriverManager中也完善了驱动扫描实现,关键实现代码如下:
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
/* Load these drivers, so that they can be instantiated.
* It may be the case that the driver class may not be there
* i.e. there may be a packaged driver with the service class
* as implementation of java.sql.Driver but the actual class
* may be missing. In that case a java.util.ServiceConfigurationError
* will be thrown at runtime by the VM trying to locate
* and load the service.
*
* Adding a try catch block to catch those runtime errors
* if driver not available in classpath but it's
* packaged as service and that service is there in classpath.
*/
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
}
});
关于ServiceLoader的使用方式,大家自行查看API即可,已经够详细了。
于是在mysql驱动5.1.6版本开始(mysql-connector-java-5.1.6.jar),利用了这个机制,大家可自行下载5.1.6版本之后的jar查看,存在文件:META-INF/services/java.sql.Driver
文件内容:com.mysql.jdbc.Driver
自此之后,大家写纯jdbc的时候,就不需要自己注册驱动了 Class.forName(“com.mysql.jdbc.Driver”); 这样就省掉了一行不那么规范的代码。