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"。

你可能感兴趣的:(19.JDBC开发(2)(我的JavaEE笔记))