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阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容

  • JDBC概述 在Java中,数据库存取技术可分为如下几类:JDBC直接访问数据库、JDO技术、第三方O/R工具,如...
    usopp阅读 3,534评论 3 75
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,621评论 18 399
  • 一、JDBC简介 Sun公司为了简化、统一对数据库的操作,定义了一套java操作数据库的规范,称之为JDBC。 注...
    yjaal阅读 817评论 0 4
  • 晨读推荐的书经典且实用,分享的知识或小技巧有时候给人豁然开朗的感觉,一点点帮助着拨开云雾见阳光。 关键仍在行动,分...
    哇哇来啦阅读 95评论 0 0
  • 前两天去阿毛家吃饭,听到了这么一个故事。阿毛的爸爸是军人,我去吃饭的前一天,他曾经带过的一位飞行员的遗孀来拜访做客...
    玎町阅读 607评论 0 0