前言:自己的小理解和大部分javasec內容
JDBC
什么是JDBC?
JDBC本質:官方定義的一套操作所有關系型數據庫的規則,即接口。 各個數據庫廠商去實現了這個JDBC的接口,提供數據庫驅動jar包,我們可以使用這套接口JDBC編程,真正執行代碼的是驅動jar包中的實現類
什么是"真正執行代碼的是驅動jar包中的實現類",其實就是一個類去實現官方寫的接口中的方法,這樣就是一個實現類!
那么廠商們要實現哪個哪個接口呢? java.sql.Driver
跟進去看下,如下的方法都是廠商們一定需要實現的方法!!!
public interface Driver //這是一個接口,不用說,要不然其他廠商如何實現呢!
Connection connect(String url, java.util.Properties info)
boolean acceptsURL(String url) //還能判斷是否是正規的數據庫協議
DriverPropertyInfo[] getPropertyInfo // 該方法可以獲得一些驅動的相關信息放到DriverPropertyInfo數組中
int getMajorVersion(); //獲取主版本信息
int getMinorVersion(); //獲取副版本信息
boolean jdbcCompliant(); //判斷驅動程序是否為正版JDBC
public Logger getParentLogger() //返回此驅動程序使用的所有記錄器的父記錄器
可以看下Mysql中的驅動包是如何寫的,如下顯示,這里它通過繼承NonRegisteringDriver類來實現了java.sql.Driver的接口
java.sql.DriverManager
Java通過java.sql.DriverManager來管理所有數據庫的驅動注冊,所以如果想要建立數據庫連接需要先在java.sql.DriverManager中注冊registerDriver對應的驅動類,然后調用getConnection方法才能連接上數據庫。
跟進去簡單的了解下DriverManager這個類的屬性和方法
這是一個公有類public class DriverManager
如下屬性:注冊的JDBC驅動程序列表
// List of registered JDBC drivers
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;
一個靜態代碼塊:
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
還有一些關於日志的操作:
public static java.io.PrintWriter getLogWriter()
public static void setLogWriter(java.io.PrintWriter out)
....
....
獲取數據庫的連接:
public static Connection getConnection(String url, java.util.Properties info)
public static Connection getConnection(String url, String user, String password)
public static Connection getConnection(String url)
private static Connection getConnection(String url, java.util.Properties info, Class<?> caller)
驅動的相關操作:
public static Driver getDriver(String url) //獲取驅動
public static synchronized void registerDriver(java.sql.Driver driver) //注冊驅動1
public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) //注冊驅動2
public static synchronized void deregisterDriver(Driver driver) //取消驅動
一個概念:Java通過java.sql.DriverManager來管理所有數據庫的驅動注冊,所以如果想要建立數據庫連接需要先在java.sql.DriverManager中注冊對應的驅動類,然后調用getConnection方法才能連接上數據庫。
java.sql.DriverManager.getConnection(xx)其實就是間接的調用了java.sql.Driver類的connect方法實現數據庫連接的。數據庫連接成功后會返回一個叫做java.sql.Connection的數據庫連接對象,一切對數據庫的查詢操作都將依賴於這個Connection對象。
JDBC連接數據庫的一般步驟:
1、注冊驅動,Class.forName("數據庫驅動的類名")
2、獲取連接,DriverManager.getConnection(xxx)
正常實現的代碼如下
Class.forName("com.mysql.jdbc.Driver");
String URL = "jdbc:mysql://localhost:3306/mysql";
String USERNAME = "root";
String PASSWORD = "123456";
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
我自己學的時候反正是有疑問的,為什么注冊用Class.forName("com.mysql.jdbc.Driver");
來實現,然后就是DriverManager.getConnection
為什么能夠獲得Mysql驅動包中的connection對象
這兩個問題得解決!
為什么Class.forName能夠實現注冊驅動
那么直接跟進com.mysql.jdbc.Driver的Driver類中去觀察
看下如下的內容,這是一個靜態代碼塊,並且Class.forName("com.mysql.jdbc.Driver")
使用的時候會觸發類加載,從而執行該靜態代碼塊,那么也就可以說明了,為什么能夠Class.forName("com.mysql.jdbc.Driver")
能夠注冊驅動!
提醒,如果想拿到對應類型的Class實例,但是又不想觸發類加載執行靜態代碼塊的話,下面兩種方法可以解決:
1、使用Class.forName("xxxx", false, loader)
方法,將第二個參數傳入false。
2、ClassLoader.load("xxxx");
DriverManager.getConnection為什么能夠獲得Mysql
那么也從源碼中觀察,老樣子跟進DriverManager中,靜態代碼塊執行的是DriverManager.registerDriver(new Driver());
繼續跟registerDriver方法,如下圖所示,它會將Mysql自身Driver實例化然后放到registerDriver中
最后還會添加到registeredDrivers屬性中
然后現在就是Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
我們可以看下DriverManager.getConnection的方法是怎么樣的,如下圖所示,它會將賬號密碼這些都存儲起來然后放到一個info對象中,再將info作為參數傳入getConnection中
跟進去看,重點是如下的紅框處,它的for循環會遍歷registeredDrivers數組,取出DriverInfo類型的aDriver變量,DriverInfo這個就是之前存儲到registeredDrivers數組中的內容,此時的aDriver.driver就是已經實例化的Driver對象(Mysql,Mssql等等),最后調用它們實現Driver接口之后的connect方法,返回一個connection的對象!!!