18.JDBC開發(fā)(1)(我的JavaEE筆記)

一、JDBC簡介

Sun公司為了簡化笼恰、統(tǒng)一對數(shù)據(jù)庫的操作,定義了一套java操作數(shù)據(jù)庫的規(guī)范囚衔,稱之為JDBC挖腰。

  • 注意:JDBC只是一個規(guī)范,一套對數(shù)據(jù)庫操作的接口练湿,其是由sun公司定義的猴仑,所以我們在導入相關包時都是導入javaSE中的包,而不是導入相關的驅動中的包肥哎,那只是對sun公司JDBC的實現(xiàn)辽俗。
  • JDBC主要由兩個包組成:java.sqljavax.sql。開發(fā)jdbc應用需要以上兩個包的支持外篡诽,還需要導入相應的jdbc的數(shù)據(jù)庫實現(xiàn)(即驅動)崖飘。而java.sqljavax.sql已經(jīng)稱為javaSE的規(guī)范,所以現(xiàn)在不需要導入了杈女。只需要導入相關的驅動就可以了朱浴。

二、第一個JDBC程序

2.1搭建試驗環(huán)境

  • 1.在mysql中創(chuàng)建一個庫达椰,并創(chuàng)建user表和插入表的數(shù)據(jù)翰蠢。
create database day14;
use day14;
create table user(
    id int primary key auto_increment,
    name varchar(40),
    password varchar(40),
    email varchar(60),
    birthday date
)character set utf8 collate utf8_general_ci;
insert into user(name,password,email,birthday) values('zs','123456','zs@sina.com','1980-12-04');
insert into user(name,password,email,birthday) values('lisi','123456','lisi@sina.com','1981-12-04');
  • 2.新建一個java工程(day14),并導入相關數(shù)據(jù)庫驅動啰劲。
    驅動是:mysql-connector-java-5.1.37-bin.jar

Demo1.java

package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Demo1 {

    public static void main(String[] args) throws SQLException {
        String url = "jdbc:mysql://localhost:3305/day14";
        String username = "root";
        String password = "walp1314";
        
        //1.加載驅動
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        
        //2.獲取與數(shù)據(jù)庫的鏈接
        Connection connection = DriverManager.getConnection(url, username, password);
        
        //3.獲取用于向數(shù)據(jù)庫發(fā)送sql語句的statement對象
        Statement st = connection.createStatement();
        
        //4.向數(shù)據(jù)庫發(fā)送sql語句梁沧,并獲取代表結果集的ResultSet對象
        String sql = "select id, name, password, email, birthday from user";
        ResultSet result = st.executeQuery(sql);
        
        //5.取出結果集的數(shù)據(jù)
        while(result.next()){
            System.out.println("id= " + result.getObject("id"));
            System.out.println("name= " + result.getObject("name"));
        }
        
        //6.關閉鏈接,釋放資源
        result.close();
        st.close();
        connection.close();

    }
}

2.2程序詳解

2.2.1 DriverManager

  • jdbc程序中的DriverManager用于加載驅動蝇裤,并創(chuàng)建與數(shù)據(jù)庫的連接廷支,這個API的常用方法:
DriverManager.registerDriver(new Driver());
DriverManager.getConnection(url,user,password);
  • 注意:在實際開發(fā)中并不推薦采用registerDriver方法注冊驅動频鉴。原因有二:
    一是通過Driver的源代碼可以看到,如果采用此種方式恋拍,會導致驅動程序注冊兩次垛孔,也就是在內存中會有兩個Driver對象。
    二是程序依賴mysql的api施敢,脫離這個api的jar包似炎,程序將無法編譯,這樣不便于切換底層數(shù)據(jù)庫悯姊。
    推薦方式:Class.forName("com.mysql.jdbc.Driver");采用此種方式不會導致驅動對象在內存中重復出現(xiàn)羡藐,并且采用此種方式,程序僅僅需要一個字符串悯许,不需要依賴具體的驅動仆嗦,程序的靈活性更高。
    同樣也不建議采用具體的驅動類型指向getConnection方法返回的connection對象先壕,比如:
conn = (com.mysql.jdbc.Connection) DriverManager.getConnection(url, username, password);

2.2.2 數(shù)據(jù)庫URL

  • url用于標識數(shù)據(jù)庫的位置瘩扼,程序員通過url地址告訴jdbc程序連接哪個數(shù)據(jù)庫,url的寫法為:
    jdbc:mysql://localhost:3305/day14?參數(shù)名:參數(shù)值
    問號后面可以帶上編碼信息垃僚,如果不帶集绰,則根據(jù)數(shù)據(jù)庫的編碼自動指定。
  • 常用數(shù)據(jù)庫URL地址的寫法:
    Oracle寫法:jdbc:oracle:thin:@localhost:1521:sid
    SqlServer寫法:jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sid
    MySql寫法:jdbc:mysql://localhost:3305/day14
  • 常用屬性:useUnicode=true&characterEncoding=UTF-8

2.2.3 Connection

  • jdbc程序中的Connection用于代表數(shù)據(jù)庫的連接谆棺,Connection是數(shù)據(jù)庫編程中最重要的一個對象栽燕,客戶端與數(shù)據(jù)庫所有交互都是通過Connection對象完成的,這個對象的常用方法:
    createStatement():創(chuàng)建向數(shù)據(jù)庫發(fā)送sql的statement對象改淑。
    prepareStatement(sql):創(chuàng)建向數(shù)據(jù)庫發(fā)送預編譯sql的PrepareSatement對象碍岔。
    prepareCall(sql):創(chuàng)建執(zhí)行存儲過程的callableStatement對象。
    setAutoCommit(boolean autoCommit):設置事務是否自動提交朵夏。
    commit():在鏈接上提交事務蔼啦。
    rollback():在此鏈接上回滾事務。

2.2.4 Statement

  • jdbc程序中的Statement對象用于向數(shù)據(jù)庫發(fā)送sql語句仰猖,Statement對象常用方法:
    executeQuery(String sql):用于向數(shù)據(jù)發(fā)送查詢語句捏肢。
    executeUpdate(String sql):用于向數(shù)據(jù)庫發(fā)送insert、update或delete語句
    execute(String sql):用于向數(shù)據(jù)庫發(fā)送任意sql語句
    addBatch(String sql):把多條sql語句放到一個批處理中饥侵。
    executeBatch():向數(shù)據(jù)庫發(fā)送一批sql語句執(zhí)行鸵赫。
  • 注意:這個addBatch是先將多條語句添加到Statement對象中,然后使用executeBatch方法一起執(zhí)行爆捞。

2.2.5 ResultSet

  • jdbc程序中的ResultSet用于代表sql語句的執(zhí)行結果奉瘤。ResultSet封裝執(zhí)行結果時勾拉,采用的類似于表格的方式煮甥。ResultSet對象維護了一個指向表格數(shù)據(jù)行的游標盗温,初始的時候,游標在第一行之前成肘,調用ResultSet.next()方法卖局,可以使游標指向具體的數(shù)據(jù)行,進行調用方法獲取該行的數(shù)據(jù)双霍。
  • ResultSet既然是用于封裝執(zhí)行結果的砚偶,所以該對象提供的都是用于獲取數(shù)據(jù)的get方法:
    獲取任意類型的數(shù)據(jù)
getObject(int index)
getObject(string columnName)

獲取指定類型的數(shù)據(jù)

getString(int index)
getString(String columnName)
  • 提問:數(shù)據(jù)庫中列的類型是varchar,獲取該列的數(shù)據(jù)調用什么方法洒闸?int類型呢染坯?bigint類型呢?Boolean類型丘逸?
    常用數(shù)據(jù)類型轉換表
sql類型 jdbc對應的方法 返回類型
BIT(1) BIT(N) getBoolean getBytes() boolean byte[]
TINYINT getByte() byte
SMALLINT getShort() short
INT getInt() int
BIGINT getLong() long
CHAR,VARCHAR,LONGVARCHAR getString() String
TEXT(clob) BLOB getClob() getBlob() Clob Blob
DATE getDate() java.sql.Date
TIME getTime() java.sql.Time
TIMESTAMP getTimestamp() java.sql.Timestamp
  • ResultSet還提供了對結果進行滾動的方法:
    next():移動到下一行
    previous():移動到前一行
    absolute(int row):移動到指定行
    beforeFirst():移動resultSet的最前面单鹿。
    afterLast():移動到resultSet的最后面。
    注意:開始時指向表頭深纲,使用一次next才指向第一條數(shù)據(jù)仲锄,而使用afterLast方法之后指向表尾,這樣使用previous方法才執(zhí)行最后一條數(shù)據(jù)湃鹊。

2.2.6 釋放資源

  • jdbc程序運行完后儒喊,切記要釋放程序在運行過程中,創(chuàng)建的那些與數(shù)據(jù)庫進行交互的對象币呵,這些對象通常是ResultSet怀愧、Statement和Connection對象。
  • 特別是Connection對象余赢,它是非常稀有的資源掸驱,用完后必須馬上釋放,如果不能及時没佑、正確的關閉毕贼,很容易導致宕機。其使用原則是盡量晚創(chuàng)建蛤奢,盡量早的釋放鬼癣。
  • 為確保資源釋放代碼能運行,資源釋放代碼也一定要放在finally語句中啤贩。

對上面例子進行修正:Demo.java

package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo2 {

    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        String url = "jdbc:mysql://localhost:3305/day14";
        String username = "root";
        String password = "walp1314";
        
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try{
            //1.加載驅動(推薦)
            Class.forName("com.mysql.jdbc.Driver");
            
            //2.獲取與數(shù)據(jù)庫的鏈接
            connection = DriverManager.getConnection(url, username, password);
            
            //3.獲取用于向數(shù)據(jù)庫發(fā)送sql語句的statement對象
            statement = connection.createStatement();
            
            //4.向數(shù)據(jù)庫發(fā)送sql語句待秃,并獲取代表結果集的ResultSet對象
            String sql = "select id, name, password, email, birthday from user";
            result = statement.executeQuery(sql);
            
            //5.取出結果集的數(shù)據(jù)
            while(result.next()){
                System.out.println("id= " + result.getObject("id"));
                System.out.println("name= " + result.getObject("name"));
            }
        }finally{
        
            //6.關閉鏈接,釋放資源
            //方式一:
            /*if(result != null){
                try {
                    result.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(statement != null){
                try {
                    statement.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }*/
            //方式二:
            if(result != null){
                try {
                    result.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally{
                    if(statement != null){
                        try {
                            statement.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }finally{
                            if(connection != null){
                                try {
                                    connection.close();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }
        }

    }

}

說明:

  • 我們在使用jdbc的時候必須要保證最后資源能夠釋放痹屹,不管前面程序是否運行正確章郁。于是我們將資源釋放的代碼放在finally塊中,這樣就保證了不管發(fā)生什么情況下資源都會被釋放。上面我們提供了兩種釋放資源的方式暖庄,因為每一個關閉語句都可能會產生異常聊替,所以關閉比較麻煩。
  • finally塊中的語句在JVM(exit(1))或是死循環(huán)時是不會執(zhí)行的培廓,其他情況下都會執(zhí)行惹悄,同時注意是在return語句之前執(zhí)行。

三肩钠、使用JDBC對數(shù)據(jù)庫進行CRUD

從之前的例子中我們可以發(fā)現(xiàn)在每次使用數(shù)據(jù)庫都需要鏈接數(shù)據(jù)庫和釋放資源泣港,我們可以將這些重復的代碼統(tǒng)一放在一個工具類中。同時對于數(shù)據(jù)庫中需要用到的一些資源价匠,比如url当纱、用戶名、密碼等我們直接寫死在程序中也不便于日后維護踩窖,于是我們將這些資源放在一個配置文件中惫东。

src/db.properties

### MySQL
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3305/day14
username=root
password=walp1314

### Oracle
#driver=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin:@localhost:1521:orcl
#username=root
#password=walp1314

JdbcUtils.java

package cn.itcast.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils {
    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;
    
    static {
        try{
            //獲取資源文件,這里我們的資源文件放在src下
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);
            
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            
            Class.forName(driver);
        
        }catch(Exception e){
            throw new ExceptionInInitializerError(e);
        }
    }
    //獲得數(shù)據(jù)庫鏈接
    public static Connection getConnection() throws SQLException{
        return DriverManager.getConnection(url, username, password);
    }
    //釋放資源
    public static void release(Connection conn, Statement st, ResultSet rs){
        if(rs != null){
            try {
                rs.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if(st != null){
            try {
                st.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

測試:Demo3.java

package cn.itcast.demo;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Test;
import cn.itcast.utils.JdbcUtils;

public class Demo3 {
    
    //數(shù)據(jù)庫插入
    @Test
    public void insert(){
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try {
            //通過工具類獲得數(shù)據(jù)庫的鏈接
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "insert into user(id, name, password, email, birthday) "
                    + "values(4, 'xxx', '12', 'xx@sina.com', '1998-09-09')";
            //下面的返回值表示影響了數(shù)據(jù)庫多少行
            int num = statement.executeUpdate(sql);
            if(num  > 0){
                System.out.println("插入成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //通過工具類釋放資源
            JdbcUtils.release(connection, statement, result);
        }
    }
    
    //刪除操作
    @Test
    public void delete(){
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try {
            //通過工具類獲得數(shù)據(jù)庫的鏈接
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "delete from user where id = 4";
            int num = statement.executeUpdate(sql);
            if(num > 0){
                System.out.println("刪除成功");
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //通過工具類釋放資源
            JdbcUtils.release(connection, statement, result);
        }
    }
    
    //修改操作
    @Test
    public void update(){
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try {
            //通過工具類獲得數(shù)據(jù)庫的鏈接
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "update user set name='tom', email='tom@sina.com' where id = 2";
            int num = statement.executeUpdate(sql);
            if(num > 0){
                System.out.println("修改成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //通過工具類釋放資源
            JdbcUtils.release(connection, statement, result);
        }
    }
    
    //查找操作
    @Test
    public void find(){
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try {
            //通過工具類獲得數(shù)據(jù)庫的鏈接
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "select * from user where id = 1";
            result = statement.executeQuery(sql);
            if(result.next()){
                System.out.println(result.getString("name"));
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //通過工具類釋放資源
            JdbcUtils.release(connection, statement, result);
        }
    }
}

注意:在以后的開發(fā)中我們不會再使用Statement這個對象毙石,而是使用其子類PreparedStatement廉沮,同時這個對象可以防范sql注入,相關使用方法請看筆記17.2 徐矩。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末滞时,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子滤灯,更是在濱河造成了極大的恐慌坪稽,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鳞骤,死亡現(xiàn)場離奇詭異窒百,居然都是意外死亡,警方通過查閱死者的電腦和手機豫尽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門篙梢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人美旧,你說我怎么就攤上這事渤滞。” “怎么了榴嗅?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵妄呕,是天一觀的道長。 經(jīng)常有香客問我嗽测,道長绪励,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮疏魏,結果婚禮上停做,老公的妹妹穿的比我還像新娘。我一直安慰自己蠢护,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布养涮。 她就那樣靜靜地躺著葵硕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贯吓。 梳的紋絲不亂的頭發(fā)上懈凹,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音悄谐,去河邊找鬼介评。 笑死,一個胖子當著我的面吹牛爬舰,可吹牛的內容都是我干的们陆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼情屹,長吁一口氣:“原來是場噩夢啊……” “哼坪仇!你這毒婦竟也來了?” 一聲冷哼從身側響起垃你,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤椅文,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后惜颇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體皆刺,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年凌摄,在試婚紗的時候發(fā)現(xiàn)自己被綠了羡蛾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡锨亏,死狀恐怖林说,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情屯伞,我是刑警寧澤腿箩,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站劣摇,受9級特大地震影響珠移,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一钧惧、第九天 我趴在偏房一處隱蔽的房頂上張望暇韧。 院中可真熱鬧,春花似錦浓瞪、人聲如沸懈玻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涂乌。三九已至,卻和暖如春英岭,著一層夾襖步出監(jiān)牢的瞬間湾盒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工诅妹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留罚勾,地道東北人棒拂。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓蕉朵,卻偏偏與公主長得像故俐,于是被迫代替她去往敵國和親移稳。 傳聞我的和親對象是個殘疾皇子且预,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容

  • JDBC概述 在Java中照筑,數(shù)據(jù)庫存取技術可分為如下幾類:JDBC直接訪問數(shù)據(jù)庫据德、JDO技術肩民、第三方O/R工具般此,如...
    usopp閱讀 3,530評論 3 75
  • 本節(jié)介紹Statement接口及其子類PreparedStatement和CallableStatement蚪战。 它...
    zlb閱讀 1,134評論 0 0
  • JDBC簡介 SUN公司為了簡化、統(tǒng)一對數(shù)據(jù)庫的操作铐懊,定義了一套Java操作數(shù)據(jù)庫的規(guī)范邀桑,稱之為JDBC。JDBC...
    奮斗的老王閱讀 1,504評論 0 51
  • 本人的環(huán)境為Myeclipse10科乎、MySQL5.7.15 本文包括:簡介JDBC編程步驟打通數(shù)據(jù)庫程序詳解—Dr...
    廖少少閱讀 3,930評論 7 39
  • 北京-果汁賀-互聯(lián)網(wǎng)-攝影3888 2017.6 北京 iPhone6p 無 跟新朋友吹著空調吃火鍋壁畸,包場 幸福
    果汁賀閱讀 189評論 2 0