jdbc筆記(完整)

JDBC:java database connection


一  Why JDBC

    我們一直說,計算機是用來幫助人們進行快速運算的。運算最根本的依據是數據。那麼我們需要有操作的數據的來源,並且最終計算完成後,需要數據能夠長久的保存,也就是數據能夠持久化。
    
    持久化:                                 寫入到

    狹義上講  內存對象 -------------------------------》持久化介質(磁帶,磁盤,文件等。。)

        如果直接寫入文件中,可以在應用程序中使用I/O操作來處理數據,但是獲取有結構的數據,並且對數據進行制定查找,修改比較複雜,不好管理。後來嘗試給文件制定規則,用來存儲數據。 我們有xml文件,xml文件可以作爲小型數據庫,也是可以存儲信息,並且具有結構化良好,可讀性高,自我描述功能強的優點。但是這種格式存儲的數據非常簡單,不提供給我們對於檢索,排序 等更多優化的性能,可以說,他本身在處理大數據量的需求下,是不適用的。所以xml我們僅適用於做小數據量的信息傳遞。針對於xml文件我們也有專門的解析和構建方式如Sax和Dom。然後有了數據庫的產生。數據庫提供了更強有力的數據存儲和分析能力,例如:數據索引、排序、查找、相關一致性等。當數據庫產生之後,如果我們的應用程序需要得到數據庫中數據的支持,就需要和數據庫之間產生交互。各語言和數據庫之間交互的技術營運而生。JDBC解決java操作的內存中的數據和數據庫之間的交互問題。
    

二  What JDBC

    連接數據庫的方式:
        1.ODBC:開放數據庫連接(Open Database Connectivity,ODBC)是微軟公司開放服務結構(WOSA,Windows Open Services Architecture)中有關數據庫的一個組成部分,是數據庫訪問接口標準。開放數據庫互連定義了訪問數據庫API的一個規範,這些API獨立於不同廠商的DBMS,也獨立於具體的編程語言(但是Microsoft的ODBC文檔是用C語言描述的,許多實際的ODBC驅動程序也是用C語言寫的。)
    ODBC規範後來被X/OPEN和ISO/IEC採納,作爲SQL標準的一部分。簡單點說,ODBC是基於C語言實現的。提供了語言和數據庫進行交互的一致性的接口,便於語言和和數據庫通信以及語言對數據庫的各種操作。
    
        2.JDBC: Java Data Base Connectivity,java數據庫連接
    可以認爲是java版本的odbc。JDBC是一種用於執行SQL語句的Java API,可以爲多種關係數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成
       JDBC API主要分爲兩部分:
           ①針對應用開發人員,必須遵循的規則。 對數據庫進行增刪改查操作

           ②對於數據庫驅動(實現類)開發人員必須遵循的規則。 可以讓用戶通過驅動連接數據庫

    我們主要關注針對於應用開發人員的標準。目前jdbc的版本已經到達5.0的版本。
            
        

三  數據庫驅動       

        數據庫軟件可以由各個數據庫廠商提供,我們熟知的mysql,oracle,sqlserver,access,db2等等都是由不同的廠商提供的,既有不同的開發商開發,因此對於數據庫軟件的實現過程都不盡相同。定義應用程序和數據庫之間進行交互的規則(標準)。這個標準稱之爲驅動(Driver)。開發商在開發數據庫軟件時提供針對於Driver標準的實現,應用開發人員再開發時,通過標準Driver的調用轉換成對實際數據庫Driver程序的調用。因此,每一款數據庫軟件在實現時都會提供相對於Driver標準的一些列接口和類的實現。更明確一點說我們需要獲取人家提供的這個驅動包才能保證程序和數據庫之間的連接。  

四   JDBC驅動

    四種JDBC驅動:
    ①JDBC-ODBC橋 加ODBC
        作爲jdk1.1後的一部分,是sun.jdbc.odbc包的一部分, 將jdbc調用轉化爲odbc調用,性能低,要求用戶在終端上安裝相應驅動。 適用於快速的原型開發,沒有提供JDBC驅動的數據庫如Access
        java --->JDBC-ODBC橋---->ODBC --->數據庫廠商代碼

    ②部分java實現的本地JDBC驅動
        相對①有所提高,直接利用開發商提供的本地庫來直接與數據庫通信
        java ----type2 ----native Database library ----數據庫廠商代碼

    ③jdbc網絡純java驅動程序
        將JDBC調用轉換爲DBMS無關的網絡協議,然後由某個服務器將其轉換爲相應的DBMS調用,具有最大的靈活性,通常由那些非數據庫廠商提供,是四種類型中最小的。
        java --->type3 ---java middleware --->jdbc Driver ----->數據庫廠商代碼
       
    ④本地協議純java驅動程序
        將jdbc調用直接轉化成響應的DBMS調用,最高的性能,通過自己的本地協議直接與數據庫引擎通信,具備internet的裝配能力,目前java程序連接數據庫都是用純jdbc驅動。使用純jdbc驅動需要先獲取數據庫廠商提供的驅動包:針對於oracle數據庫,可以從安裝目錄下的app\oracle\product\10.2.0\server\jdbc\lib下找一個叫做ojdbc14.jar。 根據jdbc版本的更新換代,現在最高的jdbc版本爲4.0的版本。可以單獨獲取jar包,例如獲取ojdbc5.jar,ojdbc6.jar.

       

五  JDBC應用開發接口

    java.sql.*;  ------標準版
    javax.sql.*; ------企業版。  
  我們主要看java.sql.*包下的接口和類:
    
    1).Driver: 驅動的標準接口。
    2).DriverManager: 驅動管理器,管理多個加載的驅動程序;能夠根據數據庫的url標識,自動查找合適的數據庫驅動類。
    3).Connection: 和數據庫連接的對象形式,代表了一個和數據庫的連接;

    4).Statement:  用以執行SQL語句                                                                                                                                           PreparedStatement(繼承自Statement);

                c. CallableStatement(繼承自PreparedStatement);
    5).ResultSet: 結果集,用來獲取select語句返回的數據結果
    

六  JDBC的執行流程

    1.由DriverManager根據數據庫的URL標識,自動識別查找註冊給DriverManager的多各Driver對象,
    2.通過調用Driver對象的Connect方法和數據庫之間建立起來連接(此時返回Connection對象)
    3.建立起來了解之後,由Statement對象負責搬運sql語句到數據庫服務端執行,然後將執行結果搬回程序端
    4.處理程序端返回的ResultSet。
    

七  數據庫的URL標識

     數據庫url標識的存在主要是爲了能夠讓DriverManager通過這個標示可以正確的識別使用的數據庫,以及查找到正確的Driver對象,並且通過這個Driver可以和數據庫之間建立起來連接。這個url由數據庫廠商提供。
     基本格式:
        jdbc:subprotocol:subname
        example: jdbc:odbc:dbname (通過jdbc-odbc橋的方式實現的數據庫連接url)
        oracle :jdbc:oracle:thin:@localhost:1521:xe
        mysql : jdbc:mysql://localhost:3306/javademo?characterEncoding=UTF8    
    
----------------------------------------------------------------------------------------------------------------------------------
Model 2   USing    JDBC


一  JDBC編程步驟

  1.註冊驅動/加載驅動
  2.獲取連接
  3.創建Statement對象
  4.執行sql
  5.處理結果集
  6.關閉資源。

二  分步驟詳解

    1.註冊驅動(加載驅動)

        註冊的方式:
          1.使用類加載器(使用反射的方式)
             Class.forName(driverName);
          2.實例化Driver
             Driver driver = new oracle.jdbc.driver.OracleDriver();
             DriverManager.registerDriver(driver);
          public class Driver extends NonRegisteringDriver implements java.sql.Driver {  
                   static {  
                    try {  
                        java.sql.DriverManager.registerDriver(new Driver());  
                    } catch (SQLException E) {  
                        throw new RuntimeException("Can't register driver!");  
                      }  
             }  
          3.加虛擬機參數jdbc.drivers

            -Djdbc.drivers=oracle.jdbc.driver.OracleDriver

   2.建立連接

        連接方式:
   1.DriverManager的getConnection方法
          getConnection(url);//沒有用戶名密碼
          //將用戶名密碼存放在java.util.Properties對象中
          getConnection(url,properties);
          getConnection(url,user,passwd);      
          DriverManager中的getConnection其實也是調用的Driver.connect方法,因此可以直接使用。
    2.直接調用Driver.connect方法執行
          Driver d = new oracle.jdbc.driver.OracleDriver();

          d.connect(url,properties);

   3.創建Statement

        Statement:connection.createStatement();
          1.創建時不需要傳遞sql語句,但是執行時需要傳遞sql語句
          2.如果涉及到動態參數的傳遞,必須使用字符串拼接
        
        PreparedStatement:connection.prepareStatement(String sql);
          1.創建時就需要傳遞sql語句,執行的時候不需要傳遞sql語句
          2.如果涉及到動態參數的傳遞,可以使用字符串拼接,也可以使用?佔位的形式,給?號傳值使用的是 pstmt.setType(index,value); index從1開始
          3.提供預編譯的功能,某種程度上可以避免sql注入的問題
          4.提前做語法檢查,在給?賦值的過程中要求數據類型一定要匹配,這樣在某種程度上可以避免因爲數據類型不匹配而發生的異常

        CallableStatement:主要用來執行pl/sql的一些過程,函數等。

   4.執行sql語句

      ①execute:返回boolean類型的值,代表是否有結果集返回(如果執行select操作,是有ResultSet的,返回值爲true)
      ②executeUpdate:返回int類型的值,代表的是,操作執行完成後,受影響的數據庫的行計數(針對於insert,update,delete)
      ③executeQuery:返回的是ResultSet。ResultSet:類似於指針或者遊標的東西,裏邊保存的不是所有的結果,而是指向結果集的正上方。所以如果一旦連接關閉那ResultSet將取不到值(sekect操作的結果)
   

   5.處理結果:有結果集,處理結果集

    ResultSet
    next(),每執行一次,向下移動一次,如果有值,返回true,如果沒值返回false
    while(rs.next()){
        rs.getType(index/columnName);   如果傳的是index,那麼索引是從1開始的。
        例如:
            執行select id,last_name from s_emp;
            那麼1代表的就是id,依次類推
    }
    

   6.關閉資源

    先開的後關

   

package jdbc.day01;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SimpleJDBC {
	private static Connection conn;
	private static Statement stmt;
	private static ResultSet rs;
	public static void main(String []args) throws SQLException{
		try{
			//註冊驅動
			Class.forName("oracle.jdbc.driver.OracleDriver");
			
			//獲取連接    getConnection方法的參數url,userName,userPassword
			conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","hjh","hjh");
			
			//創建Statement對象,創建sql語句
			String sql = "select * from s_emp";
			String sql2 = "delete from emp_41";
			stmt = conn.createStatement();
			
			//System.out.println("excute:"+stmt.executeUpdate(sql2));//4
			System.out.println("excuteUpdate:"+stmt.executeUpdate(sql2));//4
			
			//處理結果集    ResultSet只會在select語句纔有
			rs = stmt.executeQuery(sql);
			
			//rsִ�У�next�ж��Ƿ�����ݣ�get��ȡ���
			while(rs.next()){
				System.out.println("id:"+rs.getInt("id")+"  name:"+rs.getString(2)+"  dept_id:"+rs.getInt("dept_id"));
			}
				
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}catch(SQLException e){
			e.printStackTrace();
		}finally{
			//關閉資源
			if(rs!=null)rs.close();
			if(stmt!=null)stmt.close();
			if(conn!=null)conn.close();
		}
	}
}
   

三  Statement和PreparedStatement

    Statement
        1.創建時不需要傳遞sql語句,但是執行時需要傳遞sql語句
        2.如果涉及到動態參數的傳遞,必須使用字符串拼接
    PreparedStatement
        1.創建時就需要傳遞sql語句,執行的時候不需要傳遞sql語句
        2.如果涉及到動態參數的傳遞,可以使用字符串拼接,也可以使用?佔位的形式。 要求在執行sql語句之前,給?號傳值。給?傳值使用的是  pstmt.setType(index,value); index代表給第幾個?賦值。index從1開始
        3.提供預編譯的功能,某種程度上可以避免sql注入的問題
        4.提前做語法檢查,在給?賦值的過程中要求數據類型一定要匹配,這樣在某種程度上可以避免因爲數據類型不匹配而發生的異常
        

四  sql注入

        SQL注入攻擊是指利用設計上的漏洞,在目標服務器上運行Sql語句以及進行其他方式的攻擊,動態生成Sql語句時沒有對用戶輸入的數據進行驗證,是Sql注入攻擊得逞的主要原因。對於JDBC而言,SQL注入攻擊只對Statement有效,對PreparedStatement是無效的,這是因爲PreparedStatement不允許在不同的插入時間改變查詢的邏輯結構。
    
    例如:
        1.定義Sql語句,select * from test where name = '';
        如果設置由用戶輸入用戶名  test' or ‘1’ = '1 ,則sql語句變爲 :select * from test where name = 'test' or '1'='1' ; 這條語句結果恆爲true。
            
        2.如果設置 select * from test where name = '' and password = '';
            如果由用戶輸入查詢條件 (“jack”,”123 or 1 = 1”) 則sql語句編程select * from test where name = ‘jack’ and passsword = 123 or 1 = 1;
            
    現在大家已經對SQL Injection的攻擊有了初步的瞭解了,接下讓我們學習如何防止SQL Injection。
    總的來說有以下幾點:
    1.永遠不要信任用戶的輸入,要對用戶的輸入進行校驗,可以通過正則表達式,或限制長度,對單引號進行轉換等。
    2.永遠不要使用動態拼裝SQL,可以使用參數化的SQL或者直接使用存儲過程進行數據查詢存取。
    3.永遠不要使用管理員權限的數據庫連接,爲每個應用使用單獨的權限有限的數據庫連接。
    4.不要把機密信息明文存放,請加密或者hash掉密碼和敏感的信息。
    5.應用的異常信息應該給出儘可能少的提示,最好使用自定義的錯誤信息對原始錯誤信息進行包裝,把異常信息存放在獨立的表中。
    
    

五  批處理

    業務場景:當需要向數據庫發送一批SQL語句執行時,應避免向數據庫一條條的發送執行,而應採用JDBC的批處理機制,以提升執行效率。
    
    實現批處理有兩種方式:第一種方式:Statement.addBatch(sql)
                                                第二種方式:PreparedStatement.addBatch()
                          
    執行批處理SQL語句    executeBatch()方法:執行批處理命令
                                            clearBatch()方法:清除批處理命令
    
    採用Statement.addBatch(sql)方式實現批處理:
            優點:可以向數據庫發送多條不同的SQL語句。

            缺點:?SQL語句沒有預編譯。

    statement = connection.createStatement();
    String sql = “insert into student values(1,’tom’)”
    String sql2 = “update student set id = 2 ”;
    statement.addBatch(sql);
    statement.addBatch(sql2);

    statement.executeBatch();

  當向數據庫發送多條語句相同,但僅參數不同的SQL語句時,需重複寫上很多條SQL語句。例如

      Insert into user(name,password) values(‘aa’,’111’);
      Insert into user(name,password) values(‘bb’,’222’);
      Insert into user(name,password) values(‘cc’,’333’);
      Insert into user(name,password) values(‘dd’,’444’);
    
    採用PreparedStatement.addBatch()實現批處理
            優點:發送的是預編譯後的SQL語句,執行效率高。
            缺點:只能應用在SQL語句相同,但參數不同的批處理中。因此此種形式的批處理經常用於在同一個表中批量插入數據,或批量更新表的數據。
    實例代碼
    for(int i=0;i<50000;i++) {
        ps.setInt(1,i);
        ps.setString(2,"aaa"+i);
        ps.setInt(3,1000+i);
        ps.addBatch();
        if(i%5000 == 0) {
            System.out.println(i);
            ps.executeBatch();
            ps.clearBatch();
        }
    }
    ps.executeBatch();
    
    

六  事務控制

    jdbc是自動事務提交的,因此,執行一條sql語句之後,sql語句可以自動將數據插入到數據庫,並且事務自動提交。如果不希望sql事務自動提交,設置:
        connection.setAutoCommint(false);
       如此需要在用戶手動的提交事務。connection.commit();
       如果需要保存回滾點,可以使用:Savepoint a2  = connection.setSavepoint("a1");
       如果需要回滾事務到某一指定保存點,可以使用: Savepoint a2  = connection.rollback(a2);
       如果希望事務回滾,可以使用:connection.rollback();
       回滾的操作一般不用jdbc處理,建議oracle手動控制
    

七  三層框架

    通常意義上的三層架構就是將整個業務應用劃分爲:表現層(UI)、業務邏輯層(BLL)、數據訪問層(DAL)。區分層次的目的即爲了“高內聚,低耦合”的思想。

原理:
    1:數據訪問層:主要是對原始數據(數據庫或者文本文件等存放數據的形式)的操作層,而不是指原始數據,也就是說,是對數據的操作,而不是數據庫, 具體爲業務邏輯層或表示層提供數據服務.
    2:業務邏輯層:主要是針對具體的問題的操作,也可以理解成對數據層的操作,對數據業務邏輯處理,如果說數據層是積木,那邏輯層就是對這些積木的搭建。
    3:表示層:主要表示用戶的操作終端,如果邏輯層相當強大和完善,無論表現層如何定義和更改,邏輯層都能完善地提供服務。

具體的區分方法
    1:數據訪問層:主要看你的數據層裏面有沒有包含邏輯處理,實際上他的各個函數主要完成各個對數據文件的操作。而不必管其他操作。
    2:業務邏輯層:主要負責對數據層的操作。也就是說把一些數據層的操作進行組合。
    3:表示層:主要對用戶的請求接受,以及數據的返回,爲客戶端提供應用程序的訪問。位於最外層(最上層),最接近用戶。用於顯示數據和接收用戶輸入的數據,爲用戶提供一種交互式操作的界面。

優缺點
    優點:
          1、開發人員可以只關注整個結構中的其中某一層;
          2、可以很容易的用新的實現來替換原有層次的實現;
          3、可以降低層與層之間的依賴;
          4、有利於標準化;
          5、利於各層邏輯的複用。
          6、結構更加的明確
          7、在後期維護的時候,極大地降低了維護成本和維護時間

    缺點:
         1、降低了系統的性能。這是不言而喻的。如果不採用分層式結構,很多業務可以直接造訪數據庫,以此獲取相應的數據,如今卻必須通過中間層來完成。
         2、有時會導致級聯的修改。這種修改尤其體現在自上而下的方向。如果在表示層中需要增加一個功能,爲保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼。
         3、增加了開發成本。

發佈了30 篇原創文章 · 獲贊 6 · 訪問量 4817
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章