1. 程式人生 > >JDBC 及連線池底層原理

JDBC 及連線池底層原理

一:

    1.JDBC是資料庫驅動:資料庫廠商 提供的  用來操作資料庫的  jar包

    2.因為每個資料庫的驅動都不一樣,導致學習成本高,sun為了簡化資料庫操作,提供了的一套規範,本質是一大堆介面。(要求資料庫常桑在提供驅動時都實現jdbc介面)

        jdbc由兩個包組成:java.sql   javax.sql    已經被整合到了javase中(jdbc中是一個介面,真實操作的程式碼在具體的資料庫驅動中,除了匯入jdbc相關的包之外,還需要匯入具體的資料驅動包)

    3.實現六大步驟:

1.註冊資料庫驅動

2.獲取資料庫連線

3.獲取傳輸器

4.利用傳輸器,傳送sql到資料庫執行,返回執行結果、

5.處理結果

6.釋放資源

Connection conn = null;

Statement stat = null;

ResultSet rs = null;

try {

//1.註冊資料庫驅動

Class.forName("com.mysql.jdbc.Driver");

//2.獲取資料庫連線

conn = DriverManager.getConnection("jdbc:mysql:///mydb5", "root", "root");

//3.獲取傳輸器

stat = conn.createStatement();

//4.利用傳輸器,傳送sql到資料庫執行,返回執行結果

rs = stat.executeQuery("select * from account");

//5.處理結果

while(rs.next()){

int id = rs.getInt(1);

String name = rs.getString("name");

double money = rs.getDouble("money");

System.out.println(id+name+money);

}

} catch (Exception e) {

e.printStackTrace();

throw new RuntimeException();

}finally{

//6.釋放資源

if(rs!=null){

try {

rs.close();

}

 catch (SQLException e) {

e.printStackTrace();

}finally{

rs = null;

}

}

if(stat!=null){

try {

stat.close();

} catch (SQLException e) {

e.printStackTrace();

}finally{

stat = null;

}

}

if(conn!=null){

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}finally{

conn = null;

}

}

}

4.1註冊資料庫驅動

        使用drivermanager。registerdriver(new driver) 註冊有兩個缺點,通過觀察mysql的driver介面的實現類發現在靜態程式碼中,這種方式會造成驅動被註冊兩次,另外導致了程式和具體的資料庫驅動綁死了,靈活性低,所以推薦class.forName("")的方式註冊資料庫

4.2資料庫連線

Connection conn = DriverManager.getConnection(url,name,psw);

url用於標識資料庫的位置 寫法: 

Oracle寫法:jdbc:oracle:thin:@localhost:1521:sid

SqlServer寫法:jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sid

MySql:jdbc:mysql://localhost:3306/sid

Mysql的url地址的簡寫形式: jdbc:mysql:///sid

4.3connection

代表資料庫的連線。是資料庫程式設計中最重要的物件,客戶端和資料庫互動都是通過connection物件完成的

常用方法:

createStatement():建立向資料庫傳送sql的statement物件。

prepareStatement(sql):建立向資料庫傳送預編譯sql的PreparedSatement物件。

prepareCall(sql):建立執行儲存過程的callableStatement物件。

setAutoCommit(boolean autoCommit):設定事務是否自動提交。

commit():在連結上提交事務。

rollback():在此連結上回滾事務

4.4statement 

    jdbc 程式中用於向資料庫傳送sql語句。常用方法

executeQuery(String sql) :用於向資料庫傳送查詢語句。

executeUpdate(String sql):用於向資料庫傳送insert、update或delete語句

execute(String sql):用於向資料庫傳送任意sql語句

addBatch(String sql):把多條sql語句放到一個批處理中。

executeBatch():向資料庫傳送一批sql語句執行。 

4.5resultset

代表sql語句執行的結果,封裝結果時:採用類似於表格的方式,resultset物件維護了一個指向表格資料行的遊標,初始的時候,遊標在第一行之前,呼叫resultset.next()方法,可以使遊標指向具體的資料行,進而呼叫該方法獲取該行資料

ResultSet既然用於封裝執行結果的,所以該物件提供的都是用於獲取資料的get方法:

獲取任意型別的資料

getObject(int index)

getObject(string columnName)

獲取指定型別的資料,例如:

getString(int index)

getString(String columnName)

getInt(columnIndex)

getInt(columnLabel)

getDouble(columnIndex)

getDouble(columnLabel)

...

操作遊標的方法,例如:

next():移動到下一行

Previous():移動到前一行

absolute(int row):移動到指定行

beforeFirst():移動resultSet的最前面。

afterLast() :移動到resultSet的最後面。

4.6釋放資源

    這三個物件用完之後,必須馬上釋放,如果補鞥呢即使關閉,則會導致宕機。connection使用原則是儘量晚建立,儘量早釋放。為了釋放大媽順利執行,一定放在finally語句中

5.1 注入攻擊:由於後臺的sql是拼接的,引數是使用者提交的,如果使用者在提交引數摻雜了一些sql關鍵字或特殊符號。就會導致語意改變,

5.2PreparedStatement 

    優點:可以防止sql注入攻擊(先將sql骨架發給資料庫編譯下來,後面傳送的只能是引數的值,即使傳送特殊符號,也只會當成普通文字處理)

                通過方法來設定引數,省去了拼接sql語句的麻煩

                   可以提高程式的效率(傳送的骨架會被快取下來,如果下次執行的sql與快取中的相匹配,就不再編譯而是直接使用快取中的語句,減少sql的編譯;statement每次拼接好再發送sql資料庫,每次引數不同,整條sql也就不同,所以每次都需要編譯)

二 連線池

    使用者每次請求動需要向資料庫獲得連線,而資料建立連線通常需要消耗相對較大的資源,通過連線池共享連線,減少開關連線的次數,提高程式的效率

 1.自定義連線池:(也可採用開源資料庫連線池c3p0     常用)

            需要在使用完連線後記得不關閉連線,而是呼叫retrunconn方法將連線還回池中。

2.改造close 方法(a繼承 b裝飾 )目的:將連線還回去,而不是關閉

a

寫一個類繼承要改造的類,對於不想改造的方法不覆蓋,對於想要改造的方法複寫該方法,將程式碼改造為自己需要的邏輯程式碼。

這種方式只能在還沒有物件的情況下使用,現在Connection物件已經存在了,再用繼承複寫的方式是不行的,所以我們不採用。

b

實現裝飾設計模式:

(1)寫一個裝飾類, 要求裝飾類和被裝飾者所屬的類實現同一個介面或者繼承同一個父類

(2)裝飾類必須提供構造方法接收被裝飾者, 並將被裝飾者儲存在類的內部

(3)對於想要改造的方法直接進行改造, 對於不想改造的方法, 直接呼叫原有物件(被裝設者)上的方法

c3p0

匯入jar包  builpath

在類中

       建立它的連線池:ComboPooledDataSource spds = new ComboPooledDataSource();

       設定連線資料庫引數

        spds.setDriverClass("com.mysql.jdbc.Driver);

        spds.setJdbcUrl("jdbc:mysql:///mydb");

         spds.setUser("root");

           spds.setPassword("root");

            //從連線池獲取連線

            conn= spds.getConnection();

        stat=conn.conn.createStatement();

        rs=stat.executeQuery("select .....");

        if(rs.next(){

        .......

            }

三批處理

Statement方式來實現批處理

優點:

可以在一次批處理中新增結構不同的sql語句

缺點:

不能防止sql注入攻擊

沒有預編譯機制, 效率略低

當傳送結構相同的sql語句時, sql語句的骨架每次都需要編寫。

PreparedStatement方式實現批處理

優點:

可以防止sql注入攻擊

採用預編譯機制, 可以提高程式執行的效率

當傳送多條結構相同的sql時, sql語句的骨架可以只發送一次。

缺點:

不能在一次批處理中新增結構不同的sql語句

            1statement

stat.addBatch("use mydb1")

stat.addBatch(....

stat.addBatch(....

stat.executeBatch();

            2.preparedStatement

   ps=conn.prepareStatement("insert into tb values(null,?));

for(int i = 0 ,i<100;i++   )    {

ps.setString(1,"f"+i  );

ps.addBatch();

}

ps.executeBatch();