09_JDBC & DBUtils

JDBC(java database connectivity)
面向接口開發思想
  • java數據庫連接
  • java語言和數據庫之間的鏈接(java提供的api),為多種數據庫提供統一的訪問
  • 每個數據庫內部的操作方式都不一樣,我們不可能自己寫實現類操作數據庫,因為這是數據庫公司的內部機密,所以每個數據庫廠商都提供一套操作自己數據庫的實現類給我們調用
  • 鏈接mysql需要用到mysql公司提供的mysql-connector-java-5.1.39-bin.jar文件(數據庫供應商寫好的)
  • java提供數據庫操作的接口,供應商根據接口來進行實現操作數據庫,這樣,通過同一套接口,可以實現不同數據庫的操作,而不需要不同數據庫需要調用不同的api
  • 需要加載驅動,驅動程序中的類會實現JDBC的接口,我們只需要學習接口就好(驅動就是接口的實現類)
    • JDBC是接口,驅動是接口的實現
JDBC開發步驟
  1. 注冊驅動:加載廠商實現jdbc接口的實現類
    • 通過drivermanager(驅動管理者),調用registerDriver(Driver)
    • Driver驅動接口類,對象在導入的驅動中
    • 傳入mysql驅動程序中的Driver對象
  2. 獲取連接:鏈接到廠商的數據庫
    • 連接的效率比較低,tcp協議(保證安全性)
  3. 獲得語句執行平臺:獲取操作數據庫的實現類(sql語句的執行者)
  4. 執行sql語句:操作數據庫
  5. 處理結果:得到結果
  6. 釋放資源:斷開連接
  • 1,2,3,6都是固定的.只有4,5是開發人員可控的
  • 因為加載的驅動是jar包,里面都是編譯后的class文件,點進入相應的類中是沒有源碼的,這時需要自己導入源碼,在下載官方的驅動包時有一個src文件夾,里面放的就是源碼,我們attach resource the src floder,如果選擇導入file,則源碼需要是以jar的形式提供的
import com.mysql.jdbc.Driver;
public static void main(String[] args) throws SQLException {
    // 注冊驅動
    DriverManager.registerDriver(new Driver());
}
  • 在Driver類源碼中,調用了一段靜態代碼塊,注冊一次驅動,只要一加載類,就會調用
  • 如果按照上面的寫法寫,就會注冊2次驅動,造成浪費
  • 通過反射的方式把類加載進內存,這樣就可以只調用一次加載驅動
public static void main(String[] args) throws Exception {
    Class.forName("com.mysql.jdbc.Driver");
}
  • 通過 DriverManager獲取鏈接,得到的鏈接對象是在驅動包中的實現類
    • 比較耗時,因為通過TCP協議創建連接
//static Connection getConnection(String url, String user, String password)  
//返回值是Connection接口的實現類,在mysql驅動程序
//url: 數據庫地址  jdbc:mysql://連接主機IP:端口號//數據庫名字
String url = "jdbc:mysql://localhost:3306/mybase";
//用戶名和密碼用自己的
String username="root";
String password="root";
Connection con = DriverManager.getConnection(url, username, password);
  • 通過得到的連接(connection)對象,去獲取數據庫的操作對象Statement
  • Statement制定int executeUpDate(string sql),僅限于執行insert,update,delete
  • 通過SQLYog拼接sql語句
  • 關閉資源
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class JDBCDemo {
    public static void main(String[] args) throws Exception {
        //1.注冊驅動 反射技術,將驅動類加入到內容
        //使用java.sql.DriverManager類靜態方法 registerDriver(Driver driver)
        // Diver是一個接口,參數傳遞,MySQL驅動程序中的實現類
        //DriverManager.registerDriver(new Driver());
        //驅動類源代碼,注冊2次驅動程序
        Class.forName("com.mysql.jdbc.Driver");
        //2.獲得數據庫連接  DriverManager類中靜態方法
        //static Connection getConnection(String url, String user, String password)  
        //返回值是Connection接口的實現類,在mysql驅動程序
        //url: 數據庫地址  jdbc:mysql://連接主機IP:端口號//數據庫名字
        String url = "jdbc:mysql://localhost:3306/mybase";
        String user = "root";
        String password = "root";
        //3.獲得語句執行平臺, 通過數據庫連接對象,獲取到SQL語句的執行者對象
        // con對象調用方法   Statement createStatement() 獲取Statement對象,將SQL語句發送到數據庫
        // 返回值是 Statement接口的實現類對象,,在mysql驅動程序
        Connection conn = DriverManager.getConnection(url,user,password);
        Statement statement = conn.createStatement();
        //4.執行sql語句
        // 通過執行者對象調用方法執行SQL語句,獲取結果
        // int executeUpdate(String sql)  執行數據庫中的SQL語句, insert delete update
        // 返回值int,操作成功數據表多少行
        int rows = statement.executeUpdate("INSERT INTO sort(sname,sprice,sdesc) VALUES('xx',50, 'xx');");
        System.out.println(rows);
        //6.釋放資源  一堆close()
        statement.close();
        conn.close();
    }
}
public class JDBCDemo1 {
    public static void main(String[] args) throws Exception{
        //1. 注冊驅動
        Class.forName("com.mysql.jdbc.Driver");
        //2. 獲取連接對象
        String url = "jdbc:mysql://localhost:3296/mybase";
        String username="root";
        String password="123";
        Connection con = DriverManager.getConnection(url, username, password);
        //3 .獲取執行SQL 語句對象
        Statement stat = con.createStatement();
        // 拼寫查詢的SQL
        String sql = "SELECT * FROM sort";
        //4. 調用執行者對象方法,執行SQL語句獲取結果集
        // ResultSet executeQuery(String sql)  執行SQL語句中的select查詢
        // 返回值ResultSet接口的實現類對象,實現類在mysql驅動中
        ResultSet rs = stat.executeQuery(sql);
        //5 .處理結果集
        // ResultSet接口方法 boolean next() 返回true,有結果集,返回false沒有結果集
        while(rs.next()){
            //獲取每列數據,使用是ResultSet接口的方法 getXX方法參數中,建議寫String列名
            System.out.println(rs.getInt("sid")+"   "+rs.getString("sname")+
                    "   "+rs.getDouble("sprice")+"   "+rs.getString("sdesc"));
        }
        
        rs.close();
        stat.close();
        con.close();
    }
}
sql注入
  • 登陸查詢
    • SELECT * FROM 用戶表 WHERE NAME = 用戶輸入的用戶名 AND PASSWORD = 用戶輸的密碼
    • 此時,當用戶輸入正確的賬號與密碼后,查詢到了信息則讓用戶登錄
    • 但是當用戶輸入的賬號為XXX 密碼為:XXX’ OR ‘a’=’a時,則真正執行的代碼變為
    • SELECT * FROM 用戶表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’ OR ’a’=’a’
    • 此時,上述查詢語句時永遠可以查詢出結果的。那么用戶就直接登錄成功了,顯然我們不希望看到這樣的結果,這便是SQL注入問題
select * from tbl_user where usr_name='xx' and usr_pwd='xx';
select * from tbl_user where usr_name='xx' and usr_pwd='xx or 1=1';
預編譯sql語句
  • PrepareStatement接口預編譯SQL語句
# 使用PreparedStatement預處理對象時,建議每條sql語句所有的實際參數,都使用逗號分隔。
# String sql = "insert into sort(sid,sname) values(?,?)";;
# PreparedStatement預處理對象代碼:
# PreparedStatement psmt = conn.prepareStatement(sql)
//執行SQL語句,數據表,查詢用戶名和密碼,如果存在,登錄成功,不存在登錄失敗
String sql = "SELECT * FROM users WHERE username=? AND PASSWORD=?";
//調用Connection接口的方法prepareStatement,獲取PrepareStatement接口的實現類
//方法中參數,SQL語句中的參數全部采用問號占位符
PreparedStatement pst =  con.prepareStatement(sql);
System.out.println(pst);
//調用pst對象set方法,設置問號占位符上的參數
pst.setObject(1, "username");
pst.setObject(2, "password");

//調用方法,執行SQL,獲取結果集
ResultSet rs = pst.executeQuery();
while(rs.next()){
    System.out.println(rs.getString("username")+"   "+rs.getString("password"));
}
rs.close();
pst.close();
con.close();
JDBCUtils(JSBC工具類)
  • 簡化代碼,方便返回數據庫鏈接對象Connection和關閉資源
public class JDBCUtils {
    //私有構造方法
    private JDBCUtils(){}
    private static Connection con ;
    //加載驅動
    static{
        try{
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/mybase";
            String username="root";
            String password="root";
            con = DriverManager.getConnection(url, username, password);
        }catch(Exception ex){
            throw new RuntimeException(ex+"數據庫連接失敗");
        }
    }
    //獲取鏈接
    public static Connection getConnection(){
        return con;
    }
    //關閉資源
    public static void close(Connection con,Statement stat){
         if(stat!=null){
             try{
                 stat.close();
             }catch(SQLException ex){}
         }
         if(con!=null){
             try{
                 con.close();
             }catch(SQLException ex){}
         }
    }
    //關閉資源
    public static void close(Connection con,Statement stat , ResultSet rs){
         if(rs!=null){
             try{
                 rs.close();
             }catch(SQLException ex){}
         }
         close(conn,stat);
    }
}
public class TestJDBCUtils {
    public static void main(String[] args)throws Exception {
        Connection con = JDBCUtils.getConnection();
        PreparedStatement pst = con.prepareStatement("SELECT sname FROM sort");
        ResultSet rs = pst.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString("sname"));
        }
        JDBCUtils.close(con, pst, rs);
    }
}
properties配置文件
  • DBUtils類通過讀取配置文件去設定數據庫地址,數據庫用戶名密碼,驅動地址等信息
    • 通常都存在配置文件中,方便后期維護,程序如果需要更換數據庫,只需要修改配置文件即可
  • property文件建議放在src目錄下
    • 假設現在項目開發完成了,并且測試完畢,要交付給用戶了,我們給用戶的是bin目錄下的class文件,不可能把整個工程都給用戶的(包含源碼)
    • 文件的擴展名為property
    • 內容為key=value的形式
    • 如果再好一點,會放在遠程服務器上,讓其讀取配置
  • property文件的編寫
properties文件的編寫(內容如下):
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3296/mybase
username=root
password=123
  • property文件讀取
    • 通過類加載器去獲取配置文件的地址:
//獲得當前類的類加載器(負責加載類的對象)
ClassLoader loader = 當前類.class.getClassLoader();
//獲取文件的流對象
InputStrea, fis = loader.getRescoreAsStream(String path);//輸入文件名
Properties pro = new Properties();
pro.load(fis);
public class PropertiesDemo {
    public static void main(String[] args) throws Exception{
        //使用類的加載器
        InputStream in = PropertiesDemo.class.getClassLoader().getResourceAsStream("database.properties");
        System.out.println(in);
        Properties pro = new Properties();
        pro.load(in);
        //獲取集合中的鍵值對
        String driverClass=pro.getProperty("driverClass");
        String url = pro.getProperty("url");
        String username = pro.getProperty("username");
        String password = pro.getProperty("password");
        Class.forName(driverClass);
        Connection con = DriverManager.getConnection(url, username, password);
        System.out.println(con);
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,348評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,442評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,802評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,983評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,542評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,287評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,486評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,710評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,224評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,462評論 2 378

推薦閱讀更多精彩內容