JDBC總結

JDBC總結

概述

JDBC是一組可以執行SQL語句的API
1.    鏈接數據庫的步驟:
1)       註冊驅動  
    JDBC類庫向DriverManager註冊數據庫驅動·
2)       創建鏈接java

    使用DriverManager提供的getConnection()方法鏈接到數據庫
3)       建立語句mysql

    經過數據庫的鏈接對象的createStatement方法創建SQL語句對象
4)       執行語句sql

    執行SQL語句,並將結果集合返回到ResultSet中
5)       處理結果數據庫

    使用while循環讀取結果
6)       釋放資源(注意關閉的順序)服務器

demo框架

 DriverManager.registerDriver(newcom.mysql.jdbc.Driver());性能

      

       System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");優化

          

        //加載驅動方式url

        Class.forName("com.mysql.jdbc.Driver");//推薦方式spa

       //2.創建鏈接

        String url = "jdbc:mysql:localhost:3306/jdbc";

        String user = "root";

        String password = "mysql";

        Connection conn = DriverManager.getConnection(url,user,password);

      

       //3.建立語句

       Statement st = conn.createStatement();

      

       //4.執行語句

       ResultSet rs = st.executeQuery("select * from user");

       //5.處理結果

       while(rs.next()){//按行來遍歷

        System.out.println(rs.getObject(1) + "\t" + rs.getObject(2) + "\t" +rs.getObject(3) + "\t" + rs.getObject(4)        );

       }

       //6.釋放資源(注意關閉的順序)

       rs.close();

       st.close();

       conn.close();

JDBC的使用方法

1.創建鏈接:

創建鏈接分爲兩個關鍵步驟:①加載驅動程序;②創建鏈接。此處所涉及到的Java類有:ClassDriverDriverManager

創建鏈接,要提供3個必不可少的參數:①數據庫名稱;②數據庫帳號;③數據庫密碼。

關鍵代碼:

① 加載驅動程序:Class.forName(com.mysql.jdbc.Driver);

② 創建鏈接:

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

此處,String url=」jdbc:mysql://localhost:3306/」+數據庫名稱

String name=數據庫帳號

 String pwd=數據庫密碼

須要說明的是,這兩句關鍵代碼所用的方法都會拋出異常,故應將這兩句放在try-catch塊裏

 

import java.sql.*;

public class TestConnection{

static {

try{

//加載驅動程序

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

}

catch(Exeception e){

e.printStackTrace();

}

}

 

public static void main(String[] args){

String url=」jdbc:mysql://localhost:3306/lt_atm」;

String name=」admin」;

String pwd=」lt11235」;

Connection conn=null;

try{

//創建數據庫鏈接

conn=DriverManager.getConnection(url,name,pwd);

}

catch(SQLExeception e){

e.printStackTrace();

}

finally{

try{

conn.close();

}

catch(SQLException e){

   e.printStackTrace();

}

 

}

}

}

通常,咱們在靜態代碼塊里加載驅動程序,不須要每次調用時都從新加載一次驅動。

創建鏈接過程——流程圖總結:

 

2.執行SQL命令:

①在創建起來的鏈接線上建立Statement對象;②用新建的Statement對象傳送SQL命令;③接收Statement對象返回過來的結果。

管理系統將所接受的SQL命令分爲兩類:①寫,具體來講就是增刪改;②讀,即查。對於寫性質的SQL命令,管理系統會將受到影響的記錄條數交給信使Statement;對於讀性質的SQL命令,管理系統會將知足條件的全部記錄封裝在一個對象裏交給信使Statement,而這個對象就是ResultSet類的對象。如今咱們來看一些這些動做的關鍵代碼:

 

增刪改:stmt.executeUpdate(sql)返回修改的記錄條數

查:stmt.executeQuery返回結果對象

 

關鍵代碼:

建立信使

Statement stmt=conn.createStatement();

傳送SQL命令&接收返回結果

添加記錄:        

String sql=」INSERT INTO account VALUES (‘1132’,’金龍’,’’,10000) 」;

int count=stmt.executeUpdate(sql);

 

修改記錄:

String sql=」UPDATE account SET name=’無花’ WHERE accId=’1132’」;

int count=stmt.executeUpdate(sql);

 

刪除記錄:

String sql=」DELETE FROM account WHERE accId=’1132’」;

int count=stmt.executeUpdate(sql);

讀性質的命令:

查詢記錄:

String sql=」SELECT * FROM account」;

ResultSet rs=stmt.executeQuery(sql);

 

接下來,咱們以具體的程序例子來講明傳送SQL命令的過程;再以流程圖來總結該過程:

傳送SQL命令過程——代碼示例:

import java.sql.*;

public class TestExecute{

static {

try{

//加載驅動程序

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

System.out.println(Success loading Driver!);

}

catch(Exeception e){

e.printStackTrace();

}

}

 

public static void main(String[] args){

String url=」jdbc:mysql://localhost:3306/lt_atm」;

String name=」admin」;

String pwd=」lt11235」;

Connection conn=null;

try{

//創建數據庫鏈接

conn=DriverManager.getConnection(url,name,pwd);

Statement stmt=conn.createStatement();

//添加記錄的SQL命令

String sql_1=INSERT INTO account VALUES

(1132,金龍,,10000) ;

//修改記錄的SQL命令

String sql_2=UPDATE account SET name=無花’ 

WHERE accId=1132’」;

//刪除記錄的SQL命令

String sql_3=DELETE FROM account WHERE accId=1132’」;

 

//查詢記錄的SQL命令

String sql_4=SELECT * FROM account;

 

//傳送SQL命令

int count_1=stmt.executeUpdate(sql_1);

int count_2= stmt.executeUpdate(sql_2);

int count_3= stmt.executeUpdate(sql_3);

ResultSet rs=stmt.executeQuery(sql_4);

 

}

catch(SQLExeception e){

e.printStackTrace();

}

finally{

try{

conn.close();

}

catch(SQLException e){

   e.printStackTrace();

}

}

}

}

 

傳送SQL命令過程——流程圖總結:

 

3.從返回的對象結果集中讀取數據:

當是查找數據時,返回的是結果對象集合。

如何從返回的ResultSet對象中讀取數據

ResultSet對象中,除了每一條記錄各佔用一個位置,還有一些特殊做用的位置,其中有兩個分別是:beforeFirstafterLast。他們分別是第一條記錄的前一個位置、最後一條記錄的下一個位置。當咱們用ResultSet對象封裝了查詢到的記錄,遊標初始位置置爲beforeFirst

ResultSet類中有一個next()方法,其做用就是移動遊標,使其指向下一個位置。該方法的返回值是一個boolean類型變量,當移動遊標後能指向一個有效記錄,返回true,不然(好比說移動到了afterLast位置)返回falseResultSet類還有一系列方法,能夠統一寫成getXXX()。其做用是從遊標指向的記錄中讀取數據。其中XXXStringIntDouble類的變量類型,取決於所要讀取的字段的數據類型。

思路:①用獲得的ResultSet對象調用next()方法,若返回true轉向②,不然轉向③;②調用getXXX方法,從遊標當前指向的記錄中讀取各個字段的數值;而後調用next方法,若返回true,轉向②,不然轉向③。③讀取過程完成,正常結束。

讀取數據的過程——代碼示例:

import java.sql.*;

public class TestExecute{

static {

try{

//加載驅動程序

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

System.out.println(Success loading Driver!);

}

catch(Exeception e){

e.printStackTrace();

}

}

public static void main(String[] args){

String url=」jdbc:mysql://localhost:3306/lt_atm」;

String name=」admin」;

String pwd=」lt11235」;

Connection conn=null;

try{

//創建數據庫鏈接

conn=DriverManager.getConnection(url,name,pwd);

System.out.println(Success eastablishing the Connection…」);

Statement stmt=conn.createStatement();

 

//查詢記錄的SQL命令

String sql=SELECT * FROM account;

//傳送SQL命令

ResultSet rs=stmt.executeQuery(sql);

//讀取數據

while(rs.next()){

String accId=rs.getString(1); //或者 rs.getString(accId);

String name=rs.getString(2);//或者 rs.getString(name);

Char sex=rs.getChar(3);//或者 rs.getChar(sex);

int count=rs.getInt(4);//或者 rs.getInt(count);

System.out.println(accId+/t+name+/t+sex+/t+count);

}

}

catch(SQLExeception e){

e.printStackTrace();

}

finally{

try{

conn.close();

}

catch(SQLException e){

   e.printStackTrace();

}

}

}

}

讀取數據的過程——流程圖總結:

 

二 動態執行SQL命令

動態SQL程序運行時根據條件執行具體的內容。

1、條件動態化:

         編寫一個方法,他從外界接收一個參數,並用這個參數使方法內部的SQL條件具體化,而後return一個結果。具體代碼以下:

public static ResultSet sqlQuery(String accName){

String sql=SELECT * FROM account WHERE name=’」+ accName +」’」;

.............................

return ResultSet

}  

 

 

2、字段動態化:

  承上所述,此處所謂的字段動態化,就是咱們不只能按姓名來查詢記錄,還能根據其餘字段來查詢:好比說根據編號,根據身份,甚至是根據性別。在上文sqlQuery方法的基礎上繼續擴展,其代碼以下:

 

public static ResultSet sqlQuery(String column,String value){

String sql=SELECT * FROM account WHERE

’」column +」’=’」value +」’」;

.............................

return ResultSet

}

 

 

   3、數據表動態化:

 目標是使他能不受具體數據表的限制傳入一個數據表參數,而是根據咱們不一樣的須要,訪問不一樣的數據表。代碼:

 

     public static ResultSet sqlQuery(String table,String column,String value){

String sql=SELECT * FROM ’」+ table +」’ WHERE

’」column +」’=’」value +」’」;

.............................

.............................

return ResultSet

}

4PreparedStatement類的介紹:

PreparedStatement是繼承自Statement的類

PreparedStatement擁有Statement全部的特性和方法。可是與Statement不一樣在於PreparedStatement能夠將SQL命令事先編譯,並存儲在PreparedStatement對象中,當須要執行屢次類似的SQL命令時,可以比較高效地執行。

另外,PreparedStatement最主要的功能就是可以輸入條件式的SQL命令   

     import java.sql.*;

public class VisitDB{

static {

try{

//加載驅動程序

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

}

catch(Exeception e){

e.printStackTrace();

}

}

//負責創建與數據庫管理系統之間的鏈接

public static Connection getCon(){

String url=」jdbc:mysql://localhost:3306/lt_atm」;

String name=」admin」;

String pwd=」lt11235」;

Connection conn=null;

try{

//創建數據庫鏈接

conn=DriverManager.getConnection(url,name,pwd);

   }

catch(SQLExeception e){

    conn=null;

e.printStackTrace();

}

      return conn;

}

//負責動態執行查詢語句

public static ResultSet sqlQuery(String table,String column,String value){

Connection conn= VisitDB.getCon();

//條件式SQL命令,?表示待定參數

String sql=SELECT * FROM ? WHERE ?=?;

try{

//建立pstmt時就將sql命令傳過去,使其預先編譯

PreparedStatement pstmt=conn.prepareStatement(sql);

//表示第1個?的值爲String類型的table

pstmt.setString(1,table);

    //表示第2個?的值爲String類型的column

pstmt.setString(2, column);

//表示第3個?的值爲String類型的value

pstmt.setString(3, value);

//pstmt對象執行將編譯好的SQL命令傳過去,並接收結果

ResultSet rs=pstmt.executeQuery();

return rs;

}

catch(Exception e){

return null;

e.printStackTrace();

}

}

//負責關閉再也不用的對象,釋放系統資源

public static void close(ReaultSet rs,Statement stmt,Connection conn){

try{

rs.close();

stmt.close();

conn.close();

}

catch(Exception e){

e.printStackTrace();

}

}

}

    

  好了,此時咱們的三個動態擴展也用PreparedStatement實現了。不得不提的是PreparedStatement類的setXXX系列的方法並非只有setString一種,只是上例中咱們只用到了這一種而已

三 批處理SQL命令

1Statement的批處理功能

        Statement提供了批處理的功能,批處理多用在執行寫操做的SQL命令時,若是一次要增刪改不少條記錄,使用批處理會減小對象在程序與數據庫系統之間的交互,從而提升其性能。批處理的流程以下所示:

方法說明:

1public void clearBatch() throws SQLException

 做用:將Statement對象的Batch中的全部SQL命令清空

2public void addBatch(String sql) throws SQLException

 做用:插入一個SQL命令到Statemen對象中的Batch

3public int[] executeBatch() throws SQLException

做用:將Statement對象的Batch中的全部SQL命令傳給數據庫系統

代碼示例:

Import java.sql.*;

public class TestBatch{

String[] sqls={INSERT INTO account VALUES(13579’ ’雲飛’ ‘男’ , 100),

DELETE FROM account WHERE name=’無花’」,

UPDATE account SET name=’鐵手’ WHERE accId=2468’」,}

public void testBatch(){

Connection conn=null;

try{

conn= VisitDB.getCon();

Statement stmt=conn.createStatement();

stmt.clearBatch();

for(int i=0;i<sqls.length;i++){

stmt.addBatch(sqls[i]);

}

stmt.executeBatch();

}

catch(Exception e){

e.printStackTrace();

}

 

}

}

 

2PreparedStatement的批處理功能:

    PreparedStatementStatement的子類,因此他也有批處理功能,其流程以下所示:

圖中所涉及到的方法都已說過,就再也不贅述了。如今咱們直接來看一下代碼示例:

public void testPreBatch(){

try{

Connection conn= VisitDB.getCon();

PreparedStatement  pstmt=conn.prepareStatement(

DELETE FROM account WHERE name=?);

pstmt.clearBatch();

pstmt.setString(金龍);

pstmt.addBatch();

pstmt.setString(無花);

pstmt.addBatch();

pstmt.setString(楚香帥)

pstmt.addBatch();

 

pstmt.executeBatch();

}

catch(Exception e){

e.printStachTrace();

}

}

四 事務機制

事務最主要的功能是用來確保多個連續的數據庫操做,能做爲一個總體被對待。即在執行時,要麼所有執行成功,不然所有執行失敗——回到最初狀態。

流程說明:

1Connection對象調用setAutoCommit()方法,將AutoCommit設置爲false,以取消自動提交事務機制(自動提交事務機制將每一條SQL命令看作是一個事務,每作一次數據庫操做,會自動提交一次)。

    2、當一個邏輯事務所包含的SQL命令都被執行後,調用commit()方法,向數據庫系統提交事務;這條語句一般是try塊裏最後一句。

3、中途若是發生任何錯誤或不明緣由致使操做中斷,調用rollback()方法,要求數據庫系統執行Rollback操做。

 

方法說明:

public void setAutoCommit(boolean autoCommit) throws SQLException

    說明:設置是否自動提交事務。當true時,每執行一條SQL命令,數據庫系統自動提交一次事務,即對數據庫裏的數據進行操做;當爲false時,數據庫系統不自動提交事務,知道遇到調用的commit()方法。

    

public boolean getAutoCommit() throws SQLException

說明:得到當前的Commit方式

 

public void commit() throws SQLException

說明:指示數據庫系統提交事務,將結果寫進數據庫

 

public void rollback() throws SQLException

說明:指示數據庫執行恢復操做,將數據恢復到最初狀態

 

流程圖:

代碼示例:

public void testTransaction(){

try{

Connection conn= VisitDB.getCon();

conn.setAutoCommit(false);

Statement stmt=con.createStatement();

String sql_1=UPDATE account SET balance=balance-1000 

WHERE accId=A’」;

String sql_1=UPDATE account SET balance=balance+1000 

WHERE accId=B’」;

conn.commit();

}

catch(SQLException ex){

ex.printStackTrace();

try{

conn.rollback();

}

catch(SQLException e){

e.printStackTrace();

}

}

 

}

 

SQL注入PreparedStatementStatement 

PreparedStatement(從Statement擴展而來)相對Statement的優勢:

1、沒有SQL注入的問題。

2Statement會使數據庫頻繁編譯SQL,可能會形成數據庫緩衝區溢出。

3、數據庫和驅動能夠對PreparedStatement進行優化(只有在相關聯的數據庫鏈接沒有關閉的狀況下有效)。

 

爲何要始終使用PreparedStatement代替Statement?

代碼可維護性

辨別: Statement使用 +  PreparedStatement使用?)
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values       ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");

注意StatementPreparedStatement語句上的區別:Statement是在執行的時候才傳入SQL語句,而PreparedStatement在建立的時候就已經傳入了SQL語句。
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();

 

防止SQL注入
對於JDBC而言,SQL注入攻擊只對Statement有效,PreparedStatement是無效的,這是由於PreparedStatement不容許在插入時改變查詢的邏輯結構.

SQL注射原理

SQL 注射能使攻擊者繞過認證機制,徹底控制遠程服務器上的數據庫

登錄驗證

假如後臺的sql語句時這樣拼接的

select id from test where username='"+myname+"' and password='"+mypasswd+"' ";

表面上看,若是用戶名和口令對匹配,那麼該用戶經過認證;不然,該用戶不會經過認證——可是,事實果然如此嗎?這裏並無對SQL命令進行設防,因此攻擊者徹底可以在用戶名或者口令字段中注入SQL語句,從而改變SQL查詢 。爲此,咱們仔細研究一下上面的SQL查詢字符串:

上述代碼認爲字符串username和password都是數據,不過,攻擊者卻能夠爲所欲爲地輸入任何字符 。若是一位攻擊者輸入的用戶名爲

‘’OR 1=1—

而口令爲

x

雙劃符號--告訴SQL解析器,右邊的東西所有是註釋,因此沒必要理會。這樣,查詢字符串至關於:

select id from test where username='' or 1=1;

由於如今只要用戶名爲長度爲零的字符串''或1=1這兩個條件中一個爲真,就返回用戶標識符ID——咱們知 道,1=1是恆爲真的。因此這個語句將返回user_table中的全部ID。在此種狀況下,攻擊者在username字段放入的是SQL指令 'OR1=1--而非數據。

更爲嚴重的狀況是當username對應的是'OR1=1;DROPTABLEuser_table;--

數據庫中執行的sql語句就變成了:

select id from test where username='' or 1=1;drop table test

這個語句將執行句法上徹底正確的SELECT語句,並利用drop命令清空test表。

應對策略

問題的關鍵就是不要用string構造sql語句,這樣就不會利用輸入的參數構造sql語句了。因此要用PreparedStatement替換Statement,即用佔位符做爲實參定義sql語句,從而避免sql注入攻擊。

無論什麼框架,仍是純JDBC,只用Preparedstatement,必定要用佔位符做爲實參來構造sql(或hql)語句。

String sql= "select * from test where usernmae=? and password=? " ;
PreparedStatement psm=conn.preparedStatement(sql);
psm.setString(1,myname);
psm.setString(2,mypasswd);
Result rs=psm.executeQuery(); 
if (rs.next){
rs.close();
con.close();
return false ;
}
else {
rs.close();
con.close();
return true ;
}

 

 



相關文章
相關標籤/搜索