JDBC 之插入Blob(圖片)& 批處理 & 資料庫事務
阿新 • • 發佈:2018-12-26
插入Blob欄位型別(如圖片) 實現批處理和 資料庫事務的一致性 |
---|
一、插入Blob型別資料(如:圖片)
使用JDBC來寫入Blob型資料到資料庫中 資料庫中的Blob欄位比long欄位的效能要好,可以用來儲存如圖片之類的二進位制資料。 BLOB欄位由兩部分組成:資料(值)和指向資料的指標(定位器)。 儘管值與表自身一起儲存,但是一個BLOB列並不包含值,僅有它的定位指標。 為了使用大物件,程式必須宣告定位器型別的本地變數。 當資料庫內部LOB被建立時,定位器被存放在列中,值被存放在LOB段中, LOB段是在資料庫內部表的一部分。 因為Blob自身有一個cursor,當寫入Blob欄位必須使用指標(定位器) 對Blob進行操作,因而在寫入Blob之前,必須獲得指標(定位器)才能進行寫入 如何獲得Blob的指標(定位器) :需要先插入一個empty的blob, 這將建立一個blob的指標,然後再把這個empty的blob的指標查詢出來, 這樣通過兩步操作,就獲得了blob的指標,可以真正的寫入blob資料了。
<1>第一步:連線資料庫和釋放資源的JDBCUtils是不可少的
封裝使用C3P0獲取連線和關閉連線 這兩個方法封裝如下:
public class JDBCUtils { //資料庫連線池值應該被初始化一次放在靜態程式碼塊中 private static DataSource datasource=null; static{ datasource =new ComboPooledDataSource("helloc3p0"); } public static Connection getConnection() throws SQLException{ return datasource.getConnection(); } //用完資源後需要關閉 /*釋放資源: Connection Statement ResultSet 1 儘量晚建立早釋放 2 後使用的先關閉*/ public static void release(ResultSet rs,Statement statement,Connection conn){ if(rs!=null){ try{ rs.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(statement!=null){ try{ statement.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
<2> 編碼格式 資料庫utf8
<2>第二步:實現插入Blob型別(圖片)的資料如下:
public class TestBlob { @Test public void testInsert() throws Exception{ //獲取連線 Connection connection = JDBCUtils.getConnection(); PreparedStatement statement = connection.prepareStatement("insert into star values(null,'mnls',?)"); //插入圖片佔位符值 圖片儲存在src包下 statement.setBlob(1, new FileInputStream("src/mnls.jpg")); //執行插入圖片 int executeUpdate = statement.executeUpdate(); if (executeUpdate>0) { System.out.println("success"); } else { System.out.println("failure"); } JDBCUtils.release(connection, statement, null); }
<2>第三步:實現將資料庫中Blob型別(圖片)的資料取出:
//查詢blob資料
@Test
public void testRead() throws Exception{
Connection connection = DBUtils.getConnection();
PreparedStatement statement = connection.prepareStatement("select * from star where id=1");
ResultSet set = statement.executeQuery();
if (set.next()) {
Blob blob = set.getBlob("photo");
//獲取二進位制流物件 ★
InputStream stream = blob.getBinaryStream();
//一邊讀一邊寫 寫入src下存為copy.jpg
//將讀到的資料轉換成字元陣列(方法如下)
byte[] arrs = StreamUtils.streamToByteArray(stream);
FileOutputStream fos = new FileOutputStream("src/copy.jpg");
fos.write(arrs);
fos.close();
}
DBUtils.release(connection, statement, set);
}
}
//將輸入流轉換成byte[] 如下
public class StreamUtils {
/**
*
* 將 輸入流 轉換成byte[]
* @param is
* @return
*/
public static byte[] streamToByteArray(InputStream is) throws IOException{
//建立位元組陣列的輸出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b=new byte[1024];
int len;
while((len=is.read(b))!=-1){
baos.write(b, 0, len);//寫到位元組陣列的輸出流
}
is.close();
baos.close();
return baos.toByteArray();
}
}
二、JDBC之批處理操作
描述:
批量處理JDBC語句提高處理速度 當需要成批插入或者更新記錄時。
可以採用Java的批量更新機制,這一機制允許多條語句一次性
提交給資料庫批量處理。通常情況下比單獨提交處理更有效率
JDBC的批量處理語句包括下面兩個方法:
addBatch(String):新增需要批量處理的SQL語句或是引數;
executeBatch():執行批量處理語句;
clearBatch():清空快取的資料
通常我們會遇到兩種批量執行SQL語句的情況:
多條SQL語句的批量處理;
一個SQL語句的批量傳參;
<1> 注意url的配置 和資料庫與java專案的編碼一致utf8
<2> 加入jar包commons-dbutils-1.3.jar
url:
jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
<3>實現批處理如下
/**
* 此類用於演示批處理
* @author liyuting
*
*/
public class TestBatch {
@Test
public void testBatch(){
Connection connection=null;
PreparedStatement statement =null;
try {
connection = JDBCUtils.getConnection();
statement= connection.prepareStatement
("insert into 表名 values(null,?,'男','[email protected]',now())");
for (int i =1; i <=20000; i++) {
statement.setString(1, "李四"+i);
statement.addBatch();//新增到批處理的語句中
if (i%500==0) {//每500條sql語句執行一次
statement.executeBatch();//真正的執行
statement.clearBatch();//清空快取
}
}
} catch (SQLException e) {
e.printStackTrace();
}
finally{
JDBCUtils.release(connection, statement, null);
}
}
}
三、JDBC之資料庫事務(控制多條sql執行中其中一條會出現異常)
<1>描述:
JDBC 事務處理:
當一個連線物件被建立時,預設情況下是自動提交事務:
每次執行一個 SQL 語句時,如果執行成功,
就會向資料庫自動提交,而不能回滾
為了讓多個 SQL 語句作為一個事務執行:
呼叫 Connection 物件的 setAutoCommit(false);
以取消自動提交事務
在所有的 SQL 語句都成功執行後,呼叫 commit(); 方法提交事務
在出現異常時,呼叫 rollback(); 方法回滾事務
若此時 Connection 沒有被關閉, 則需要恢復其自動提交狀態
<2>實現如下:
/**
* 此類用於演示演示事務
* @author liyuting
*
*/
public class TestTransaction {
@Test
public void testBatch(){
Connection connection = null;
try {
//1獲取連線
connection=DBUtils.getConnection();
//2.開啟事務 (start transaction)
connection.setAutoCommit(false);//取消每一行的自動提交
//執行一條修改語句
update(connection,"update users set name='張三' where id=?",1);
int i = 10/1;//模擬異常
//執行第二條修改語句
update(connection,"update users set name='李四' where id=?",2);
//提交事務(commit)
connection.commit();
} catch (SQLException e) {
//回滾事務(rollback)
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}