主要內容:
- 使用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"。