1.传统的jdbc 步骤:
Connection connection=null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/myshool?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong","root","root");
String sql="select * from student where name= ? ";
preparedStatement=connection.prepareStatement(sql);
preparedStatement.setString(1,"小明");
resultSet=preparedStatement.executeQuery();
while (resultSet.next()){
System.out.println(resultSet.getString("id")+" " +resultSet.getString("name"));
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
这里检出一下步骤:建表,创建连接,操作数据库,等一般模式。
2。源码分析:
Class.forName("com.mysql.cj.jdbc.Driver");
在Class.forName加载完驱动类后,开始执行静态代码块时,会new一个Driver,并调用DriverManager的registerDriver把Driver给注册到自己的驱动程序管理器(DriverManager)中去。
问题1.为啥使用DriverMangangsger?????
- Classloder.loaderClass(String name)
其实该方法内部调用的是:Classloder. loadClass(name, false)
方法:Classloder. loadClass(String name, boolean resolve)
1:参数name代表类的全限定类名
2:参数resolve代表是否解析,resolve为true是解析该类
- Class.forName(String name)
其实该方法内部调用的是:Class.forName(className, true, ClassLoader.getClassLoader(caller))
方法:Class.forName0(String name, boolean initialize, ClassLoader loader)
参数name代表全限定类名
参数initialize表示是否初始化该类,为true是初始化该类
参数loader 对应的类加载器
Class.forName得到的class是已经初始化完成的
Classloder.loaderClass得到的class是没有初始化的
river接口是每个数据库驱动都必须继承的接口
public class DriverManager {
//已经注册的驱动列表
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
private static volatile int loginTimeout = 0;
private static volatile java.io.PrintWriter logWriter = null;
private static volatile java.io.PrintStream logStream = null;
// Used in println() to synchronize logWriter
private final static Object logSync = new Object();
//阻止被初始化,DriverManager里面都是静态的方法。
private DriverManager(){}
//初始化加载驱动,其中用到了ServiceLoader机制
static {
//初始化加载驱动
loadInitialDrivers();
//打印日志
println("JDBC DriverManager initialized");
}
/*因为源代码过长,这里我们只讲重要的一些方法*/
//初始化加载驱动
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;
}
//这里涉及到一个ServiceLoader概念。上面我推荐了一篇文章,想了解的可以去看看。通过ServiceLoader去加载所有的driver。
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
//通过ServiceLoader.load()方法加载所有驱动
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
}
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);
}
}
}
//3个获取connection方法,对外提供的方法。
@CallerSensitive
public static Connection getConnection(String url, java.util.Properties info) throws SQLException {
return (getConnection(url, info, Reflection.getCallerClass()));
}
//这个方法中可以看到,properties中至少配置参数其实就是user和password
@CallerSensitive
public static Connection getConnection(String url,
String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
if (user != null) {
info.put("user", user);
}
if (password != null) {
info.put("password", password);
}
return (getConnection(url, info, Reflection.getCallerClass()));
}
@CallerSensitive
public static Connection getConnection(String url)
throws SQLException {
java.util.Properties info = new java.util.Properties();
return (getConnection(url, info, Reflection.getCallerClass()));
}
// 内部真正工作的方法(私有)
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
//检查callerCL是否为空,如果为空则通过Thread.currentThread().getContextClassLoader()去加载
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
//这里判断url
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
SQLException reason = null;
//遍历registeredDrivers去获得正确的connection
for(DriverInfo aDriver : registeredDrivers) {
// 如果callerCL不允许读取驱动,就会跳过。
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
//真正的获取connection的方法,其实还是通过driver接口中的connect方法。
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
throw new SQLException("No suitable driver found for "+ url, "08001");
}
//通过url获取driver。
@CallerSensitive
public static Driver getDriver(String url)
throws SQLException {
println("DriverManager.getDriver(\"" + url + "\")");
Class<?> callerClass = Reflection.getCallerClass();
// 通过遍历registeredDrivers中每个驱动
for (DriverInfo aDriver : registeredDrivers) {
// acceptsURL()方法判断url是否符合driver
if(isDriverAllowed(aDriver.driver, callerClass)) {
try {
if(aDriver.driver.acceptsURL(url)) {
println("getDriver returning " + aDriver.driver.getClass().getName());
return (aDriver.driver);
}
} catch(SQLException sqe) {
}
} else {
println(" skipping: " + aDriver.driver.getClass().getName());
}
}
println("getDriver: no suitable driver");
throw new SQLException("No suitable driver", "08001");
}
//注册驱动的方法
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 {
//判断driver是否已经被加载到registeredDrivers,没有就加进去
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
throw new NullPointerException();
}
println("registerDriver: " + 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(di.action() != null) {
di.action().deregister();
}
//通过remove()注销。
registeredDrivers.remove(aDriver);
} else {
throw new SecurityException();
}
} else {
println(" couldn't find driver to unload");
}
}
}
2.preparedstatement 为什么statement 好?
statement和preparedStatement的作用是一样的,都是用来执行sql。
1.代码的可读性和可维护性.
虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次:
stmt.executeUpdate(“insert into tb_name (col1,col2,col2,col4) values (‘”+var1+”’,’”+var2+”’,”+var3+”,’”+var4+”’)”);//stmt是Statement对象实例
perstmt = con.prepareStatement(“insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)”);
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate(); //prestmt是 PreparedStatement 对象实例
2.PreparedStatement尽最大可能提高性能.
3.最重要的一点是极大地提高了安全性.
由此可见:开发的时候尽量用preparedStatement,少用statement。
参考博文: