类的加载时机
- new对象
- 加载子类
- 通过类中的静态成员
- 通过反射
使用new 对象的方式加载类的不足:
- 属于编译器加载,如果编译期键4间该类不存在,则直接报编译错误,强依赖
- 导致Driver对象创建了两遍,效率较低。
rs.next()
指向下一行
rs.getObject
获取单元格
创建和释放的顺序相反
最后创建的先释放
为什么需要释放
JDBC实际上是Socket连接,开端口号,占用系统的内存,个数是有限的
关闭连接非常重要,如果上线时不关闭连接,表现非常明显
尽量晚的建立连接,尽量早的释放连接,减少占用时间。
三种方法
- 1.System.setProperty
System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver:oracle.jdbc.driver.OracleDriver");
- 2.registerDriver
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
- 3.Class.forName
Class.forName("com.mysql.jdbc.Driver");
前两种方法分析
loadInitialDrivers源码
原理loadInitialDrivers方法会取出属性判断
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
// If the driver is packaged as a Service Provider, load it.
// Get all the drivers through the classloader
// exposed as a java.sql.Driver.class service.
// ServiceLoader.load() replaces the sun.misc.Providers()
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;
}
});
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {
try {
println("DriverManager.Initialize: loading " + aDriver);
Class.forName(aDriver, true,
ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
registerDriver
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
registerDriver(driver, null);
}
public static synchronized void registerDriver(java.sql.Driver driver,
DriverAction da)
throws SQLException {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
deregisterDriver(Driver driver) 卸载驱动源码
@CallerSensitive
public static synchronized void deregisterDriver(Driver driver)
throws SQLException {
if (driver == null) {
return;
}
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);
}
println("DriverManager.deregisterDriver: " + driver);
DriverInfo aDriver = new DriverInfo(driver, null);
if(registeredDrivers.contains(aDriver)) {
if (isDriverAllowed(driver, Reflection.getCallerClass())) {
DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));
// If a DriverAction was specified, Call it to notify the
// driver that it has been deregistered
if(di.action() != null) {
di.action().deregister();
}
registeredDrivers.remove(aDriver);
} else {
// If the caller does not have permission to load the driver then
// throw a SecurityException.
throw new SecurityException();
}
} else {
println(" couldn't find driver to unload");
}
}
第三种实现
static块中将驱动注册进ManagerDriver,所以前两种方式实际上
package com.mysql.jdbc;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
其他:
driverinfo封装每一个传入的driver的信息
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
如果没有就添加进CopyOnWriteArrayList,
CopyOnWriteArrayList的特点:
- 实现了List接口
- 内部持有一个ReentrantLock lock = new ReentrantLock();
- 底层是用volatile transient声明的数组 array
- 读写分离,写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array
写时复制:
https://blog.csdn.net/weixin_39554266/article/details/82835478
三种比较
- 后两种都是字符串,反射得到类,去掉jar包也能通过编译。
- 第一种,new对象依赖于jar包,不能通过编译。(更换数据库需要改代码)