1. 程式人生 > >java對Clob大資料欄位型別的增刪改查

java對Clob大資料欄位型別的增刪改查

前言

  前幾天臨時支援,幫pc端寫幾個介面,主要是對一個表的CRUD操作,雖然快兩年多沒寫後臺相關的東西了,但還不至於連一個表的基本的CRUD操作都忘了。但悲劇往往就來的這麼及時,表中有一個欄位是Clob型別的,以前沒怎麼處理過這種大欄位型別,網上查了下資料,感覺寫的五花八門,沒有一個完整的、適用的方法。通過參照別人的出來,加上自己的實踐,終於搞定。在此分享出來,希望給以後遇到同樣問題的人提供一些幫助。處理Clob型別的像hibernate、mybatis框架本身也提供了一些簡單的工具幫我們處理,先介紹使用最原始的的jdbc來處理。對於Blob型別的處理就不再介紹,同樣處理即可。
  Clob型別的欄位最多可儲存2G的資料,不過超過5M的資料,我建議還是放到檔案裡面,資料庫放對應檔案的地址。至於兩種方式的利弊,不是本文重點,大家自行查之。  

例項 

環境

  • oracle11g
  • tomcat 7.0
  • jdk 1.8

資料庫表結構

這裡寫圖片描述

jdbc方式

首先一個基本的jdbc連線類,還是貼下吧:

public class ConnectionUntils {
    private static Connection conn;
    private ConnectionUntils(){
        try {
            throw new Exception("can't be instance");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public
static Connection getInstance(){ if(conn == null){ initConnection(); } return conn; } private static void initConnection() { try { Class.forName("oracle.jdbc.driver.OracleDriver");// 載入Oracle驅動程式 String url = "jdbc:oracle:" + "thin:@127.0.0.1:1521:orcl"
; String user = "lsh"; String password = "lsh"; conn = DriverManager.getConnection(url, user, password);// 獲取連線 } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } /* * 測試連線成功 */ /*public static void main(String[] args) { PreparedStatement pst = null; ResultSet rs = null; String sql = "select count(a_id) from article"; Connection con = getInstance(); try { pst = con.prepareStatement(sql); rs = pst.executeQuery(); if(rs.next()){ System.out.println(rs.getInt(1)); } } catch (SQLException e) { e.printStackTrace(); }finally { close(rs,pst,con); } }*/ public static void close(ResultSet rs, PreparedStatement pst, Connection connection) { try { if(rs!=null){ rs.close(); rs=null; } if(pst!=null){ pst.close(); pst=null; } if(connection!=null){ connection.close(); } } catch (SQLException e) { e.printStackTrace(); } } }

接下來是具體的增刪改查方法,先說增加,一般會插入一個空的clob到資料庫對應的欄位,然後鎖定該列,用Write將待插入字串寫入進去。重點:這兩步操作要放在同一個事務裡面。具體增加的方法如下:

public boolean save(Article article){
    boolean result = true;
    Connection conn = ConnectionUntils.getInstance(); 
    String sql = "insert into article values(?,?,empty_clob())";
    //鎖住該列,防止併發寫入時候該欄位同時被多次寫入造成錯誤
    String sqlClob = "select a_content from article where a_id=? for update";
    PreparedStatement pst =null;
    ResultSet rs = null;
    Writer writer = null; 
    try {
        conn.setAutoCommit(false);//設定不自動提交,開啟事務
        pst = conn.prepareStatement(sql);
        pst.setInt(1,article.getId());
        pst.setString(2,article.getName());
        pst.executeUpdate();

        pst= conn.prepareStatement(sqlClob);
        pst.setInt(1, article.getId());

        rs = pst.executeQuery();
        CLOB clob = null;
        if(rs.next()){
            try {
                clob = (CLOB) rs.getClob(1);
                writer = clob.getCharacterOutputStream(); //拿到clob的字元輸入流
                writer.write(article.getContent());
                writer.flush(); 
                writer.close();  
            } catch (IOException e) {
                e.printStackTrace();
            }
        } 
        conn.commit();
    } catch (SQLException e) { 
        result = false;
        try {
            conn.rollback();//當commit或者rollback後會自動釋放該列的鎖定
        } catch (SQLException e1) { 
            e1.printStackTrace();
        }
        e.printStackTrace();
    } finally {
        conn.setAutoCommit(true);//還原
        ConnectionUntils.close(rs, pst, conn);
    } 
    return result;
}

用Junit 測試:

@Test
public void testSave(){
    dao = new CrudClob();
    Article article = new Article();
    article.setId(1);
    article.setName("水滸傳");
    StringBuilder str = new StringBuilder();
    for(int i=0;i<6000000;i++){
        str.append("我是正文,我是正文,我是正文,我是正文,我是正文");
    } 
    article.setContent(str.toString());
    boolean result = dao.save(article);
    System.out.print(result);
}

將資料庫剛才插入的一條資料匯出到檔案:
這裡寫圖片描述

article.sql裡面包括表結構和剛插入的一條資料,大小411MB,在我電腦上耗時36秒左右:

這裡寫圖片描述

接下來看update操作,update時候主要利用PreparedStatement的setClob方法:

public boolean update(int id,String content){
    int result = 0;
    Connection conn = ConnectionUntils.getInstance(); 
    String sql = "update article set a_content=? where a_id=?";
    PreparedStatement pst =null;
    try {
        CLOB clob   = oracle.sql.CLOB.createTemporary(conn, false,oracle.sql.CLOB.DURATION_SESSION);
        clob.setString(1L, content);
        pst = conn.prepareStatement(sql); 
        pst.setClob(1, clob);
        pst.setInt(2,id);
        result = pst.executeUpdate();
    } catch (SQLException e) { 
        e.printStackTrace();
    }finally{
        ConnectionUntils.close(null, pst, conn);
    }
    if(result==0)
        return false;
    return true;
} 

查詢就主要是從結果集ResultSet中定位到對應的欄位後,往外讀:

public Article select(int id){
    Article article = new Article();
    Connection conn = ConnectionUntils.getInstance(); 
    String sql = "select a_id,a_name,a_content from article where a_id = ?";
    PreparedStatement pst =null;
    ResultSet rs = null;
    try {
        pst = conn.prepareStatement(sql);
        pst.setInt(1,id);
        rs = pst.executeQuery();
        StringBuilder builder = new StringBuilder();
        if(rs.next()){
            Clob clob = rs.getClob("a_content");
            Reader rd = clob.getCharacterStream();
            char [] str = new char[12];
            while(rd.read(str) != -1) {
                builder.append(new String(str));
            }
            article.setContent(builder.toString());
            article.setId(id);
            article.setName(rs.getString("a_name"));
        }
    } catch (SQLException e) { 
        e.printStackTrace();
    } catch (IOException e) { 
        e.printStackTrace();
    }finally{
        ConnectionUntils.close(rs, pst, conn);
    }
    return article;
}

刪除的方法和普通表一樣,就不在貼出。

hibernate方式

  hibernate處理挺簡單的,hibernate4處理,clob型別在實體類裡面對應定一個一個Clob型別的欄位,對映:   

<property name="content" type="clob">
            <column name="a_content"/>
</property>

在插入對應欄位的地方建立一個clob即可。

Hibernate.getLobCreator(session).createBlob(str);

hibernate5就更簡單了,hibernate內部做了對應的處理,我們直接當string型別一樣處理即可。

@Entity
public class Article { 
    @Id 
    @Column(name="a_id")
    private int id;

    @Column(name="a_name")
    private String name;

    @Column(name="a_content") 
    private String content;

    public int getId() {
        return id;
    }
}

存的時候直接設定大資料到content,直接呼叫session.save()即可。

mybatis方式

  mybatis處理也非常簡單,沒必要貼程式碼,只需要配置mapper對映的時候配置一個處理器就會自動幫我們轉型別處理。和String型別一樣處理即可。

<result column="a_content" property="content" jdbcType="Clob"  typeHandler="org.apache.ibatis.type.ClobTypeHandler"/> 

所有的程式碼已經打包上傳,如果有任何疑問請郵件:[email protected]

下載地址

相關推薦

javaClob資料型別刪改

前言   前幾天臨時支援,幫pc端寫幾個介面,主要是對一個表的CRUD操作,雖然快兩年多沒寫後臺相關的東西了,但還不至於連一個表的基本的CRUD操作都忘了。但悲劇往往就來的這麼及時,表中有一個欄位是Clob型別的,以前沒怎麼處理過這種大欄位型別,網上查

mysql 初體驗 -----(資料刪改

上篇隨筆說到了如何去安裝和 DOS命令 一些最簡單的操作,以及如何去鍵一個數據庫和如何建表。   這次接著來談mysql 裡資料和欄位的增刪改查 有增刪改查就會有資料型別以及資料型別的屬性 mysql資料型別和資料屬性有很多,先接觸一些最基本和最實用的的。   mysql 資料

sqlite3中刪改

[size=medium]android[/size]今天在做資料庫升級時,碰到要對原來資料庫中一張表的一個欄位名進行修改,但是用:alter table tablename rename column oldColumnName to newColumnName;始終不成功

【轉載】解決Java關鍵字作為json資料名問題

轉自:https://blog.csdn.net/jjj11223344/article/details/79957559   在java命名規範中,我們不能採用Java關鍵字如 public、static等命名,但是在服務端資料命名時我們往往會採用某一欄位的英文來命名,這有時候就

Java JDBC中,MySQL型別JAVA型別的轉換

1. 概述   在使用Java JDBC時,你是否有過這樣的疑問:MySQL裡的資料型別到底該選擇哪種Java型別與之對應?本篇將為你揭開這個答案。 2. 型別對映    java.sql.Types定義了常用資料庫(MySQL、Oracle、DB2等)所用到的資料型別

c# oracle插入資料過長超出限制的解決方案

通過建立儲存過程的方法解決問題,如下所示,儲存過程的名字為insertGEO,有4個輸入引數,Childrens,RingInParent直接通過sql語句插入時,欄位值過長會報錯,所以先在資料庫中建立儲存過程 create or replace procedure insertGEO (v_i

JPA之資料對映與延遲載入

1、修改Person.java中的程式碼 package cn.sunft.bean; import java.util.Date; import javax.persistence.Basic; import javax.persistence.Column; imp

解決Java關鍵字作為json資料名問題

在java命名規範中,我們不能採用Java關鍵字如 public、static等命名,但是在服務端資料命名時我們往往會採用某一欄位的英文來命名,這有時候就不可避免的和java關鍵字有衝突。這裡介紹一個Java註解來解決這一問題,將json資料中的欄位進行轉換,如:@Seria

Spring mvc無法接受到資料處理

1 :Spring mvc 用@RequestBody 方式,接收方法如下: @RequestMapping(value = "testRecieve") @ResponseBod

由於Mybatis實體資料不匹配而不到的解決辦法

使用MyBatis進行查詢操作時無法查詢出相應的結果,但是純sql又能查出資料時,需要考慮下是不是欄位對應實體類的屬性出現問題,解決方法有如下兩點 1、通過在查詢的sql語句中定義欄位名的別名,讓欄位名的別名和實體類的屬性名一致,這樣就可以表的欄位名和實體類的屬性名一一

資料庫中的無法刪改

   前沿       進行機房重構有一段時間了,進行機房資料庫是必不可少的,我們在執行機房的同時也要把相應的資料存入資料庫,同樣,我們也需要資料庫裡的資料進行增刪改,可是我遇到了一個關於資料庫的問題... &nb

arcengine 連線sde,並sde內資料進行管理(刪改

1、連線sde,用的是連線檔案,怎麼建立連線檔案,arcgis 工具箱, 如果service引數使用的預設的埠號5151,則必須在建立連線檔案之前必須建立和開啟sde服務,而如果使用sde:sqlserver:ip地址或計算機名,則不需要建立和開啟服務。 locati

關於js象中的,屬性的刪改問題

增刪改查 alt func 字面量 person per 技術分享 spa fine 刪除主要是delet方法; 1 function Person(){}; 2 var person = new Person();

java連接Oracle數據庫實現刪改並在Navicat中顯示

execute etag while args 自動 rest getc from lose 創建TEST表 eclipse中的java項目 代碼 數據庫方法類 DBUtil: package util; import java.sql.Connection;

listview展示網路資料+網路圖片+資料庫刪改+fragment

MainActivity package com.bwie.renzhili; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentPagerAdapter; import andr

xml檔案的sax解析(刪改

  crud(增刪改查): c:creat r:retrieve u:update d:delete 以下筆記來自於韓順平老師的講解。 現在是用java來操作。 第一步:新建java工程。file-new-Java Project,輸入工程的名字,點選finish. 第二步:放

C#在MVC模式下單表專案執行總結的刪改

C#在MVC模式下對單表進行的增刪改查 1,首先建立一個新專案WebApplication1 2, 接著建立實體類product, 然後通過EF Code First建立資料庫初始資料。派生出DbContext的EF上下文。masterEntities對db檔案的實現 m

java+SQL做學生資訊管理系統(刪改)學生新作

java+SQL做學生資訊管理系統(增刪改查) 過程中需要用到的所有工具資料庫以及資料庫管理器等等 密碼:q80t 大學學習java後做的第一個小專案忍不住分享一下,也是我自己的面向物件程式設計的實踐作業啦,有點水,不是很優。廢話不多數,下面進入正題 介面的編

Java通過mongo-java-driver-3.0+操作mongodb資料庫(刪改

本文以mongo-java-driver-3.5.0.jar為例 1 需要的jar包:https://pan.baidu.com/s/1jI3kB9W 密碼:79hv mongo-java-driver-3.5.0.jar junit-4.9.jar 2

java集合框架:List基本應用:刪改

package collection; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; publi