【我的javaEE學習】JDBC簡單入門

一、JDBC簡介

1、JDBC是SUN公司爲了簡化操作數據推出一套規範。數據庫廠商的驅動就是對JDBC的實現

2、Java Data Base Connectivity(java數據庫連接),它主要由接口組成。

java.sql.*    javax.sql.*   JDK中數據庫的驅動jar包

二、JDBC的編碼步驟

前提:拷貝數據庫的驅動到構建路徑中(classpath)

1、註冊驅動

2、獲取與數據庫的鏈接

3、創建代表SQL語句的對象

4、執行SQL語句

5、如果是查詢語句,需要遍歷結果集

6、釋放佔用的資源

三、JDBC中常用的接口詳解

1、DriverManager作用

   ⑴註冊驅動:

       方式一(不建議使用):DriverManager.registerDriver(new com.mysql.jdbc.Driver());

         原因:①依賴具體驅動。②導致驅動註冊2遍,從源碼裏看(如下圖)。

         

       方式二(建議):Class.forName("com.mysql.jdbc.Driver");

        只依賴字符串,可以實現運行時依賴,不用編碼依賴(如下圖)。

        

   ⑵獲取與數據庫的鏈接

        url:SUN和數據庫廠商間的協議。

               MySql:jdbc:mysql://localhost:3306/test

        Oracle: jdbc:oracle:thin:@localhost:1521/test

        public static Connection getConnection(String url,String user,String password) throws SQLException

        public static Connection getConnection(String url,Properties info) throws SQLException

        public static Connection getConnection(String url) throws SQLException       

 

2、Connection

   所有的數據庫操作都是基於鏈接之上的。

   Statement createStatement():創建向數據庫發送sql的statement對象。即Statement stmt = conn.createStatement();//創建向數據庫發送sql的statement對象

   preparedStatement(sql): 創建向數據庫發送預編譯sql的Prepare Statement對象。

   preparedCall(sql): 創建執行存儲過程的Callable Statement對象

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

   commit():在鏈接上提交事務

   rollback():在此鏈接上回滾事務

 

3、Statement

   作用:代表SQL語句對象。可以向數據庫發送任何的SQL語句

   ResultSet executeQuery(String sql):執行sql查詢,sql一般都是查詢語句,返回ResultSet

   int executeUpdate(String sql):sql一般是DML(insert update delete)語句。返回int值,操作幾條記錄。

   boolean execute(String sql):sql可以是任意的語句。返回值不是代表成功與否。如果是查詢語句,就有結果集,返回true。沒有返回結果集的,返回false。

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

   executeBatch():向數據庫發送一批sql語句執行。

 

4、ResultSet

   作用:封裝了查詢的結果集。封裝執行結果時,採用類似表格的方式。ResultSet對象維護了一個指向數據行的遊標,默認指向表格第一行數據內容的前面。

   方法:X getX(String columnName或 int columnIndex) 其中X爲String,int,long等類型

 

補充,遊標的操作:

     boolean next():遊標下移。返回值是有無記錄

     boolean previous():遊標上移。

     boolean absolute(int count):定位到指定的行。第一行是1。

     void beforeFirst():移動遊標到第一行的前面。

     void afterLast():移動遊標到最後一行的後面。

 

四、釋放佔用的資源

   一定要釋放資源,所以寫到finally裏。

五、SQL注入

       SQL注入攻擊指的是黑客通過構建特殊的命令作爲參數傳入Web程序,而這些命令大都是SQL語法裏的一些基本組合。當條件爲' or 1=1 and id ='可以當條件查詢。

如:select * from user where name='' or 'a'='a';

       select * from user where name='' or 1=1

       等價於 select * from user

       SQL注入分爲平臺注入和代碼層注入。前者是由不安全的數據庫配置或數據庫平臺的漏洞導致;後者主要是由於程序員對輸入未進行細緻的過濾,從而執行了非法執行。

       產生原因:

①不當的類型處理

②不安全的數據庫配置

③不合理的查詢集處理

④不當的錯誤處理

⑤轉義字符處理不合適

⑥多個提交處理不當

       SQL注入的預防:

    ①用戶的表單輸入域:防止一些特殊字符。

    ②對密碼加密:MD5加密

    ③PreparedStatement預編譯(得到該對象時,就必須給他SQL語句)

      支持參數佔位符:  ?  一個問號代表着一個參數。

      注:能用PreparedStatement就不要用Statement。

 

六、如何調用存儲過程

Mysql:

inputParam爲輸入參數,inOutParam既可以作爲輸出參數,又可以作爲輸入參數。

Oracle:

七、事務

1、事務指邏輯上的一組操作,組成這組操作的各個單元,要麼全部成功,要麼全部不成功。

   MySQL:每一條語句都屬於獨立事務,默認自動管理的。

2、相關操作內容:

    開啓事務:start transaction; //日後的語句都會處於同一個事務之中。

    提交事務:commit;

    回滾事務:rollback;

3、事務的特性(數據安全):

原子性:處於事務中的多條語句是不可分割的。(當做一個整體對待,操作事務要麼都發生,要麼都不發生)

一致性:事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態。比如:轉賬,轉賬前A+B=2000,轉賬後A+B=2000

隔離性:多線程併發。一個事務不能被其他線程中的事務所打擾。

持久性:事務一旦提交,永久保存起來。(保存到硬盤,而不是內存)

4、事務的隔離級別:屬於事務的。都已開啓了事務爲前提。

不考慮事務的隔離級別,會出現以下情況(是錯的)

  1. 髒讀:一個線程中的事務讀到了另外一個線程中未提交的數據。
  2. 不可重複讀:一個線程中的事務讀到了另外一個線程中已經提交的update的數據。
  3. 虛讀:一個線程中的事務讀到了另外一個線程中已經提交的insert的數據。

 

要想避免以上現象,通過更改事務的隔離級別來避免:()

  1. READ UNCOMMITTED “髒讀、不可重複讀、虛讀”都有可能發生。
  2. READ COMMITTED 避免髒讀的發生,“不可重複讀、虛讀”有可能發生。
  3. REPEATABLE READ 避免“髒讀、不可重複讀”的發生,虛讀有可能發生。
  4. SERIALIZABLE 避免“髒讀、不可重複讀、虛讀”的發生。

 

級別依次升高,效率依次降低,數據越安全。

MySQL:默認REPEATABLE READ

ORACLE:默認READ COMMITTED

 

⑴MySQL:

select @@tx_isolation;//查看當前會話的隔離級別

set transaction isolation level 級別;// 設置當前的事務隔離級別

⑵Oracle:

1.查看系統默認事務隔離級別,也是當前會話隔離級別

--首先創建一個事務
declare
     trans_id Varchar2(100);
  begin
     trans_id := dbms_transaction.local_transaction_id( TRUE );
  end; 

--查看事務隔離級別

SELECT s.sid, s.serial#,

CASE BITAND(t.flag, POWER(2, 28))
WHEN 0 THEN 'READ COMMITTED'
ELSE 'SERIALIZABLE'
END AS isolation_level
FROM v$transaction t
JOIN v$session s ON t.addr = s.taddr AND s.sid = sys_context('USERENV', 'SID');

八、連接池

  1. 連接池:是創建和管理一個連接的緩衝池的技術。
  2. 編寫連接池:

     用一個實現了javax.sql.DataSource類的實例時,用戶如果調用Connection.close()方法,會把鏈接關閉,失去了連接池的意義,而我們需要實現完實例後,放回連接池裏,方便下一次的使用,而不是立馬關閉。所以使用包裝設計模式,而包裝設計模式的核心是保持被包裝對象的原有信息,又可以對某個或某些方法進行改寫

  ⑴流程如下,即用包裝(裝飾)設計模式:

   ①編寫一個類,實現與被包裝類(即數據庫驅動對Connection的實現)相同的接口。(使這個類和數據庫的驅動實現有着相同的行爲)

   ②定義一個變量,引用被包裝類的實例。

   ③定義構造方法,傳入被包裝類的實例。

   ④對於要改寫的方法,編寫自己的代碼即可。

   ⑤對於不需要改寫的方法,調用原有對象的對應方法。

 

 ⑵爲何不用繼承的方法來改寫close()方法:

   ①因爲數據庫的種類比較多,要寫繼承的話會寫死,因爲他是繼承相對應數據庫的架包裏的方法。

   ②數據庫驅動對Connection接口的實現類,不允許被繼承

   ③假設能繼承成功了,丟失了原有對象的信息。

3.連接池的動態代理(Aspect-Oriented Programming,簡稱AOP,即默認適配器設計模式)

3.1動態代理技術介紹

3.1.1代理模式:

     就是爲其他對象提供一種代理以控制對這個對象的訪問。即明星與經紀人關係,經紀人即代理,聯繫代理,由代理轉交給明星。

3.1.2基於接口的動態代理:Proxy;如果一個類沒實現任何的接口,此種代理就不能使用了。

說明:Proxy創建動態代理類的實例提供了靜態方法,也是所有動態代理類的父類的方法創建。是JDK自帶的。

  InvocationHandler handler = new MyInvocationHandler(...);

  Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });

  Foo f = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).

                                   newInstance(new Object[] { handler });

或者更簡單的:

  Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class },handler);      

             

3.2基於接口的連接池動態代理:Proxy

3.3基於子類的動態代理:CGLIB;子類可以擴展父類的功能

     前提:被代理類的要求

a、不能是final的

b、必須是public的

比如普通的JavaBean就可能沒有實現任何的接口。

代理類是被代理類的子類。   

 

4.開源第三方數據源使用(DBCP、C3P0和JDNI)

4.1 JDNI(Java Naming and DIrectory Interface)

⑴拷貝數據庫的驅動到Tomcat\lib目錄下

⑵在web應用的META-INF目錄下建立一個名稱爲context.xml的配置文件

⑶獲取JNDI容器中的資源

Lookup裏的地址後面需要跟第二步裏面起的一致。

補充:JDNI的包放在javax.naming.*裏,不要在main方法中獲取數據源,獲取不到。

 

4.2 DBCP(APache組織實現的。DBCP:DataBase Connection Pool)

需要架包:commons-dbcp-1.4.jar和commons-pool-1.5.6.jar

4.3 C3P0

需要架包:c3p0-0.9.1.2.jar

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章