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

主要內(nèi)容:

  • 使用JDBC處理大數(shù)據(jù)
  • 處理大文本
  • 使用JDBC處理二進(jìn)制數(shù)據(jù)
  • Orecla中大數(shù)據(jù)處理
  • 使用JDBC進(jìn)行批處理
  • 獲取數(shù)據(jù)庫(kù)自動(dòng)生成的主鍵
  • jdbc調(diào)用存儲(chǔ)過程

一、使用JDBC處理大數(shù)據(jù)

在實(shí)際開發(fā)中,程序需要把大文本或二進(jìn)制數(shù)據(jù)保存到數(shù)據(jù)庫(kù)饲趋。

基本概念:大數(shù)據(jù)也稱之為L(zhǎng)OB距糖,LOB分為:

  • clob:用于存儲(chǔ)文本,使用字符流垒迂。
  • blob: 用于存儲(chǔ)二進(jìn)制數(shù)據(jù)械姻,如圖像,二進(jìn)制等机断。

對(duì)MySQL而言只有blob楷拳,而沒有clob,MySQL存儲(chǔ)大文本采用的是text吏奸,text和blob又分為:

  • TINYTEXT欢揖、TEXT、MEDIUMTEXT 和 LONGTEXT
  • TINYBLOB奋蔚、BLOB她混、MEDIUMBLOB 和 LONGBLOB

二、處理大文本

  • 對(duì)于mysql的text類型泊碑,可調(diào)用如下方法進(jìn)行添加等設(shè)置:
    PreparedStatement.setCharacterStream(index, reader, length);

  • 對(duì)于mysql的text類型坤按,可調(diào)用如下方法進(jìn)行讀取等設(shè)置:
    reader = resultSet. getCharacterStream(i);一般使用此方法
    reader = resultSet.getClob(i).getCharacterStream();
    string s = resultSet.getString(i);不要使用此方法,可能會(huì)導(dǎo)致系統(tǒng)崩潰
    (工程jdbc
    新建數(shù)據(jù)庫(kù):

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 {
    
    //測(cè)試插入大文本
    @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);
            //必須要使用流的馒过,因?yàn)橄缺仨殞⒁嫒霐?shù)據(jù)庫(kù)的內(nèi)容讀到內(nèi)存中臭脓,如果不使用流則內(nèi)存不夠
            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);
        }
    }
    
    //測(cè)試讀取大文本數(shù)據(jù)
    @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處理二進(jìn)制數(shù)據(jù)

對(duì)于mysql的blob類型沉桌,可調(diào)用如下方法進(jìn)行添加等設(shè)置:
PreparedStatement. setBinaryStream(i, inputStream, length);

對(duì)于mysql中的blob類型谢鹊,可調(diào)用如下方法進(jìn)行查詢等設(shè)置:
InputStream in = resultSet.getBinaryStream(i);一般使用此方法
InputStream in = resultSet.getBlob(i).getBinaryStream();
例:
創(chuàng)建表:

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 {
    
    //測(cè)試添加
    @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);
        }
    }
    
    //測(cè)試讀取
    @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中大數(shù)據(jù)處理

  • Oracle定義了一個(gè)blob字段用于保存二進(jìn)制數(shù)據(jù),但這個(gè)字段并不能存放真正的二進(jìn)制數(shù)據(jù)佃扼,只能向這個(gè)字段存一個(gè)指針偎巢,然后把數(shù)據(jù)放到指針?biāo)赶虻腛racle的lob段中,lob段是在數(shù)據(jù)庫(kù)內(nèi)部表的一部分兼耀。因而在操作Oracle的blob之前压昼,必須獲得指針(定位器)才能進(jìn)行blob數(shù)據(jù)的讀取和寫入。
  • 如何獲得表中的blob指針呢瘤运?可以先使用insert語(yǔ)句向表中插入一個(gè)空的blob(調(diào)用Oracle的函數(shù)empty_blob())窍霞,這將創(chuàng)建一個(gè)blob的指針,然后再把這個(gè)empty的blob的指針查詢出來(lái)拯坟,這樣就可以得到blob對(duì)象但金,從而讀取blob數(shù)據(jù)了。
  • Oracle中l(wèi)ob類型的處理
    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郁季,鎖定該行冷溃,直至該行被修改完畢,保證不產(chǎn)生并發(fā)沖突梦裂。
    3.利用io似枕,和獲取到的cursor往數(shù)據(jù)庫(kù)讀寫數(shù)據(jù)
    注意:以上操作需要開啟事務(wù)

五、使用JDBC進(jìn)行批處理

  • 業(yè)務(wù)場(chǎng)景:當(dāng)需要向數(shù)據(jù)庫(kù)發(fā)送一批sql語(yǔ)句執(zhí)行時(shí)年柠,應(yīng)避免向數(shù)據(jù)庫(kù)一條條的發(fā)送執(zhí)行凿歼,而應(yīng)采用JDBC的批處理機(jī)制,以提升執(zhí)行效率冗恨。

  • 實(shí)現(xiàn)批處理有兩種方式答憔,第一種方式:
    Statement.addBatch(sql),將sql語(yǔ)句存到一個(gè)list中去
    executeBatch()方法:執(zhí)行批處理命令
    clearBatch()方法:清除批處理命令

  • 實(shí)現(xiàn)批處理的第二種方式:
    PreparedStatement.addBatch()
    優(yōu)點(diǎn):發(fā)送的是預(yù)編譯后的sql語(yǔ)句派近,執(zhí)行效率高
    缺點(diǎn):只能應(yīng)用在sql語(yǔ)句相同攀唯,但參數(shù)不同的批處理中。因此此種形式的批處理經(jīng)常用于在同一個(gè)表中批量插入數(shù)據(jù)渴丸,或批量更新表的數(shù)據(jù)侯嘀。

例,創(chuàng)建表:

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 {
    
    //測(cè)試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);
        }
    }
    
    //測(cè)試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++){
                //這里就體現(xiàn)出了此種方式常用于同一個(gè)表中批量插入數(shù)據(jù)谱轨,或批量更新表的數(shù)據(jù)
                ps.setInt(1, i);
                ps.setString(2, "aa" + i);
                ps.addBatch();
                
                if(i % 1000 == 0){
                    //這里我們不能將所有操作都交給虛擬機(jī)完成戒幔,這樣會(huì)導(dǎo)致虛擬機(jī)崩潰,所以分成多次完成
                    ps.executeBatch();
                    ps.clearBatch();
                }
            }
            //執(zhí)行剩余的sql語(yǔ)句
            ps.executeBatch();
            ps.clearBatch();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, ps, result);
        }
        long endtime = System.currentTimeMillis();
        System.out.println("花費(fèi)時(shí)間: " + (endtime - starttime )/1000 + "秒");
    }
}

六土童、獲取數(shù)據(jù)庫(kù)自動(dòng)生成的主鍵

直接看例子:
新建表:

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();//將主鍵存在結(jié)果集中
            if(result.next()){
                System.out.println(result.getInt(1));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn, ps, result);
        }
    }
}

七诗茎、jdbc調(diào)用存儲(chǔ)過程

創(chuàng)建一個(gè)存儲(chǔ)過程:

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

說(shuō)明:這里我們先將結(jié)束符換成$$,然后創(chuàng)建一個(gè)存儲(chǔ)過程,其中demoSp是存儲(chǔ)過程名稱敢订,接收兩個(gè)參數(shù)王污,一個(gè)是輸入,一個(gè)既可以作輸入楚午,又可作輸出昭齐。存儲(chǔ)過程就是數(shù)據(jù)庫(kù)內(nèi)部定義的邏輯函數(shù),我們可以調(diào)用這些邏輯函數(shù)實(shí)現(xiàn)一些功能矾柜。這個(gè)存儲(chǔ)過程的功能就是將在接收的第二個(gè)參數(shù)前面加上第一個(gè)參數(shù)表示的字符串阱驾,然后還是使用第二個(gè)參數(shù)進(jìn)行輸出。

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);
        }
    }
}

說(shuō)明:如果我們輸入"aaa"怪蔑,那么返回出來(lái)的是"zyxw---aaa"里覆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缆瓣,隨后出現(xiàn)的幾起案子喧枷,更是在濱河造成了極大的恐慌,老刑警劉巖弓坞,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件割去,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡昼丑,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門夸赫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)菩帝,“玉大人,你說(shuō)我怎么就攤上這事茬腿『羯荩” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵切平,是天一觀的道長(zhǎng)握础。 經(jīng)常有香客問我,道長(zhǎng)悴品,這世上最難降的妖魔是什么禀综? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮苔严,結(jié)果婚禮上定枷,老公的妹妹穿的比我還像新娘。我一直安慰自己届氢,他們只是感情好欠窒,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著退子,像睡著了一般岖妄。 火紅的嫁衣襯著肌膚如雪型将。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天荐虐,我揣著相機(jī)與錄音七兜,去河邊找鬼。 笑死缚俏,一個(gè)胖子當(dāng)著我的面吹牛惊搏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忧换,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼恬惯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了亚茬?” 一聲冷哼從身側(cè)響起酪耳,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刹缝,沒想到半個(gè)月后碗暗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡梢夯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年言疗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颂砸。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡噪奄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出人乓,到底是詐尸還是另有隱情勤篮,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布色罚,位于F島的核電站碰缔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏戳护。R本人自食惡果不足惜金抡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腌且。 院中可真熱鬧竟终,春花似錦、人聲如沸切蟋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至喘鸟,卻和暖如春匆绣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背什黑。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工崎淳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人愕把。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓拣凹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親恨豁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嚣镜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • JDBC概述 在Java中,數(shù)據(jù)庫(kù)存取技術(shù)可分為如下幾類:JDBC直接訪問數(shù)據(jù)庫(kù)橘蜜、JDO技術(shù)菊匿、第三方O/R工具,如...
    usopp閱讀 3,530評(píng)論 3 75
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法计福,類相關(guān)的語(yǔ)法跌捆,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法象颖,異常的語(yǔ)法佩厚,線程的語(yǔ)...
    子非魚_t_閱讀 31,587評(píng)論 18 399
  • 一、JDBC簡(jiǎn)介 Sun公司為了簡(jiǎn)化说订、統(tǒng)一對(duì)數(shù)據(jù)庫(kù)的操作可款,定義了一套java操作數(shù)據(jù)庫(kù)的規(guī)范,稱之為JDBC克蚂。 注...
    yjaal閱讀 816評(píng)論 0 4
  • 晨讀推薦的書經(jīng)典且實(shí)用,分享的知識(shí)或小技巧有時(shí)候給人豁然開朗的感覺筋讨,一點(diǎn)點(diǎn)幫助著撥開云霧見陽(yáng)光埃叭。 關(guān)鍵仍在行動(dòng),分...
    哇哇來(lái)啦閱讀 88評(píng)論 0 0
  • 前兩天去阿毛家吃飯,聽到了這么一個(gè)故事壁袄。阿毛的爸爸是軍人类早,我去吃飯的前一天,他曾經(jīng)帶過的一位飛行員的遺孀來(lái)拜訪做客...
    玎町閱讀 601評(píng)論 0 0