19.JDBC開發(2)(我的JavaEE筆記)

主要內容:

  • 使用JDBC處理大數據
  • 處理大文本
  • 使用JDBC處理二進制數據
  • Orecla中大數據處理
  • 使用JDBC進行批處理
  • 獲取數據庫自動生成的主鍵
  • jdbc調用存儲過程

一、使用JDBC處理大數據

在實際開發中,程序需要把大文本或二進制數據保存到數據庫。

基本概念:大數據也稱之為LOB,LOB分為:

  • clob:用于存儲文本,使用字符流。
  • blob: 用于存儲二進制數據,如圖像,二進制等。

對MySQL而言只有blob,而沒有clob,MySQL存儲大文本采用的是text,text和blob又分為:

  • TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT
  • TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB

二、處理大文本

  • 對于mysql的text類型,可調用如下方法進行添加等設置:
    PreparedStatement.setCharacterStream(index, reader, length);

  • 對于mysql的text類型,可調用如下方法進行讀取等設置:
    reader = resultSet. getCharacterStream(i);一般使用此方法
    reader = resultSet.getClob(i).getCharacterStream();
    string s = resultSet.getString(i);不要使用此方法,可能會導致系統崩潰
    (工程jdbc
    新建數據庫:

CREATE DATABASE day15;
USE day15;
CREATE TABLE testclob(
    id INT PRIMARY KEY AUTO_INCREMENT,
    RESUME TEXT
);

Demo1.java

package junit.test;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.Reader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
public class Demo1 {
    
    //測試插入大文本
    @Test
    public void add(){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet result = null;
        
        try{
            conn = JdbcUtils.getConnection();
            String sql = "insert into testclob(resume) values(?)";
            ps = conn.prepareStatement(sql);
            //必須要使用流的,因為先必須將要存入數據庫的內容讀到內存中,如果不使用流則內存不夠
            String path = Demo1.class.getClassLoader().getResource("1.txt").getPath();
            File file = new File(path);
            
            ps.setCharacterStream(1, new FileReader(file), file.length());
            int num = ps.executeUpdate();
            if(num > 0){
                System.out.println("插入成功");
            }
            
        }catch(Exception e ){
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, ps, result);
        }
    }
    
    //測試讀取大文本數據
    @Test
    public void read(){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet result = null;
        
        try{
            conn = JdbcUtils.getConnection();
            String sql = "select resume from testclob where id=1";
            ps = conn.prepareStatement(sql);
            result = ps.executeQuery();
            if(result.next()){
                //模版代碼
                Reader reader = result.getCharacterStream("resume");
                char buffer[] = new char[1024];
                int len = 0;
                FileWriter writer = new FileWriter("D:\\1.txt");
                while((len = reader.read(buffer)) > 0){
                    writer.write(buffer, 0, len);
                }
                writer.close();
                reader.close();
            }
        }catch(Exception e ){
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, ps, result);
        }
    }
}

三、使用JDBC處理二進制數據

對于mysql的blob類型,可調用如下方法進行添加等設置:
PreparedStatement. setBinaryStream(i, inputStream, length);

對于mysql中的blob類型,可調用如下方法進行查詢等設置:
InputStream in = resultSet.getBinaryStream(i);一般使用此方法
InputStream in = resultSet.getBlob(i).getBinaryStream();
例:
創建表:

CREATE TABLE `testblob` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `image` longblob,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

Demo2.java

package junit.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.Reader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;

public class Demo2 {
    
    //測試添加
    @Test
    public void add(){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet result = null;
        
        try{
            conn = JdbcUtils.getConnection();
            String sql = "insert into testblob(image) values(?)";
            ps = conn.prepareStatement(sql);
            String path = Demo2.class.getClassLoader().getResource("1.jpg").getPath();
            ps.setBinaryStream(1, new FileInputStream(path), new File(path).length());
            int num = ps.executeUpdate();
            if(num > 0){
                System.out.println("插入成功");
            }
            
        }catch(Exception e ){
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, ps, result);
        }
    }
    
    //測試讀取
    @Test
    public void read(){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet result = null;
        
        try{
            conn = JdbcUtils.getConnection();
            String sql = "select image from testblob where id = ?";
            ps = conn.prepareStatement(sql);
            ps.setInt(1, 1);
            result = ps.executeQuery();
            while(result.next()){
                InputStream in = result.getBinaryStream("image");
                int len = 0;
                byte[] buffer = new byte[1024];
                FileOutputStream out = new FileOutputStream("D:\\1.jpg");
                while((len = in.read(buffer)) > 0){
                    out.write(buffer, 0, len);
                }
                in.close();
                out.close();
            }
        }catch(Exception e ){
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, ps, result);
        }
    }
}

四、Orecla中大數據處理

  • Oracle定義了一個blob字段用于保存二進制數據,但這個字段并不能存放真正的二進制數據,只能向這個字段存一個指針,然后把數據放到指針所指向的Oracle的lob段中,lob段是在數據庫內部表的一部分。因而在操作Oracle的blob之前,必須獲得指針(定位器)才能進行blob數據的讀取和寫入。
  • 如何獲得表中的blob指針呢?可以先使用insert語句向表中插入一個空的blob(調用Oracle的函數empty_blob()),這將創建一個blob的指針,然后再把這個empty的blob的指針查詢出來,這樣就可以得到blob對象,從而讀取blob數據了。
  • Oracle中lob類型的處理
    1.插入空blob
    insert into test(id,image) values(?,empty_blob());
    2.獲得blob的cursor
    select image from test where id= ? for update;
    Blob b = rs.getBlob(“image”);
    注意:必須加for update,鎖定該行,直至該行被修改完畢,保證不產生并發沖突。
    3.利用io,和獲取到的cursor往數據庫讀寫數據
    注意:以上操作需要開啟事務

五、使用JDBC進行批處理

  • 業務場景:當需要向數據庫發送一批sql語句執行時,應避免向數據庫一條條的發送執行,而應采用JDBC的批處理機制,以提升執行效率。

  • 實現批處理有兩種方式,第一種方式:
    Statement.addBatch(sql),將sql語句存到一個list中去
    executeBatch()方法:執行批處理命令
    clearBatch()方法:清除批處理命令

  • 實現批處理的第二種方式:
    PreparedStatement.addBatch()
    優點:發送的是預編譯后的sql語句,執行效率高
    缺點:只能應用在sql語句相同,但參數不同的批處理中。因此此種形式的批處理經常用于在同一個表中批量插入數據,或批量更新表的數據。

例,創建表:

CREATE TABLE testbatch(
    id INT PRIMARY KEY,
    NAME varchar2(20)
);

Demo3.java

package junit.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Test;

//jdbc批處理的兩種方式:Statement 和 PrepareStatement
public class Demo3 {
    
    //測試Statement方式
    @Test
    public void testbatch1(){
        Connection conn = null;
        Statement st = null;
        ResultSet result = null;
        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            String sql1 = "insert into testbatch(id, name) values(1, 'aaa')";
            String sql2 = "insert into testbatch(id, name) values(2, 'bbb')";
            String sql3 = "insert into testbatch(id, name) values(3, 'ccc')";
            st.addBatch(sql1);
            st.addBatch(sql2);
            st.addBatch(sql3);
            
            st.executeBatch();
            st.clearBatch();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, st, result);
        }
    }
    
    //測試PrepareStatement方式
    @Test
    public void testbatch2(){
        long starttime = System.currentTimeMillis();
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet result = null;
        try {
            conn = JdbcUtils.getConnection();
            String sql = "insert into testbatch(id, name) values(?, ?)";
            ps = conn.prepareStatement(sql);
            
            for(int i = 0; i < 10000008; i++){
                //這里就體現出了此種方式常用于同一個表中批量插入數據,或批量更新表的數據
                ps.setInt(1, i);
                ps.setString(2, "aa" + i);
                ps.addBatch();
                
                if(i % 1000 == 0){
                    //這里我們不能將所有操作都交給虛擬機完成,這樣會導致虛擬機崩潰,所以分成多次完成
                    ps.executeBatch();
                    ps.clearBatch();
                }
            }
            //執行剩余的sql語句
            ps.executeBatch();
            ps.clearBatch();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, ps, result);
        }
        long endtime = System.currentTimeMillis();
        System.out.println("花費時間: " + (endtime - starttime )/1000 + "秒");
    }
}

六、獲取數據庫自動生成的主鍵

直接看例子:
新建表:

CREATE TABLE test1(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20)
);

Demo4.java

package junit.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

public class Demo4 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet result = null;
        try {
            conn = JdbcUtils.getConnection();
            String sql = "insert into test1(name) values(?)";
            ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            ps.setString(1, "aa");
            ps.executeUpdate();
            
            result = ps.getGeneratedKeys();//將主鍵存在結果集中
            if(result.next()){
                System.out.println(result.getInt(1));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, ps, result);
        }
    }
}

七、jdbc調用存儲過程

創建一個存儲過程:

DELIMITER $$
 CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam VARCHAR(255))
 BEGIN
    SELECT CONCAT('zyxw---', inputParam) INTO inOutparam;
 END $$
DELIMITER;

說明:這里我們先將結束符換成$$,然后創建一個存儲過程,其中demoSp是存儲過程名稱,接收兩個參數,一個是輸入,一個既可以作輸入,又可作輸出。存儲過程就是數據庫內部定義的邏輯函數,我們可以調用這些邏輯函數實現一些功能。這個存儲過程的功能就是將在接收的第二個參數前面加上第一個參數表示的字符串,然后還是使用第二個參數進行輸出。

Demo5.java

package junit.test;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Types;

public class Demo5 {

    public static void main(String[] args) {
        Connection conn = null;
        CallableStatement cs = null;
        ResultSet result = null;
        try{
            conn = JdbcUtils.getConnection();
            cs = conn.prepareCall("{call demoSp(?, ?)}");
            cs.setString(1, "xxx");
            cs.registerOutParameter(2, Types.VARCHAR);
            cs.execute();
            String res = cs.getString(2);
            System.out.println(res);
        }catch(Exception e ){
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, cs, result);
        }
    }
}

說明:如果我們輸入"aaa",那么返回出來的是"zyxw---aaa"。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • JDBC概述 在Java中,數據庫存取技術可分為如下幾類:JDBC直接訪問數據庫、JDO技術、第三方O/R工具,如...
    usopp閱讀 3,546評論 3 75
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,737評論 18 399
  • 一、JDBC簡介 Sun公司為了簡化、統一對數據庫的操作,定義了一套java操作數據庫的規范,稱之為JDBC。 注...
    yjaal閱讀 822評論 0 4
  • 晨讀推薦的書經典且實用,分享的知識或小技巧有時候給人豁然開朗的感覺,一點點幫助著撥開云霧見陽光。 關鍵仍在行動,分...
    哇哇來啦閱讀 99評論 0 0
  • 前兩天去阿毛家吃飯,聽到了這么一個故事。阿毛的爸爸是軍人,我去吃飯的前一天,他曾經帶過的一位飛行員的遺孀來拜訪做客...
    玎町閱讀 615評論 0 0