主要內(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"里覆。