一、Oracle中的varchar2类型

  1. 我们在Oracle数据库存储的字符数据一般是用VARCHAR2。VARCHAR2既分PL/SQL Data Types中的变量类型,也分Oracle Database中的字段类型,不同场景的最大长度不同。

  2. 在Oracle Database中,VARCHAR2 字段类型,最大值为4000(汉字2000);PL/SQL中 VARCHAR2 变量类型,最大字节长度为32767。

  3. 当 VARCHAR2 容纳不下我们需要存储的信息时,就需要用Oracle的大数据类型LOB( Large Object,大型对象)。

二、Oarcle中的LOB类型

  1. 在Oracle中,LOB(Large Object,大型对象)类型的字段现在用得越来越多了。因为这种类型的字段,容量大(最多能容纳4GB的数据),且一个表中可以有多个这种类型的字段,很灵活,适用于数据量非常大的业务领域(如图象、档案等)。

  2. LOB类型分为BLOB和CLOB两种:BLOB即二进制大型对象(Binary Large Object),适用于存贮非文本的字节流数据(如程序、图象、影音等)。

  3. 而CLOB,即字符型大型对象(Character Large Object),则与字符集相关,适于存贮文本型的数据(如历史档案、大部头著作等)。

三、DB中使用CLOB类型字段

(一)、创建表(使用sql或者直接在PL/SQL客户端创建),字段类型CLOB

-- Create table
create table TEMP
(name      VARCHAR2(200),age       NUMBER,temp_clob CLOB
)
tablespace INSIGHTDATA3_TSpctfree 10initrans 1maxtrans 255storage(initial 160Knext 1Mminextents 1maxextents unlimited);

(二)、增删改查

先看一下使用普通方式操作CLOB类型:

SELECT t.name, t.temp_clob FROM temp t; --普通查询 INSERT INTO temp t VALUES ('Grand.Jon', 22, '加入博客园的第一天');

查询因为不是varchar2类型,所以普通查询看不到CLOB类型的字段内容,结果如下

而普通插入操作也会因为Oracle的隐式转换,默认把字符串转换成varchar2类型,一旦字符串内容超过varchar2的最大限度就会报会报ora-01704(字符串太长)错误。

正确操作

--使用PL/SQL语法,采取绑定变量的方式解决,而不是直接拼接SQLDECLARE V_LANG CLOB := '待插入的海量字符串';V_UPDATE CLOB := '更新的海量字符串';
BEGININSERT INTO temp t VALUES ('Grand.Jon', 22, V_LANG);        --增加UPDATE temp t SET t.temp_clob = V_UPDATE WHERE rownum = 1;  --修改SELECT t.NAME, dbms_lob.substr(t.temp_clob) FROM TEMP t;    --查询  将CLOB转成字符类型DELETE temp t WHERE rownum = 1;                             --按列删除  COMMIT;END;
/

对CLOB的操作我们在存储过程中基本上使用 dbms_lob 中 substr , append , write 等方法。

dbms_lob 方法总结

1 dbms_lob.createtemporary(V_SQL,true);     --创建一个临时clob,用来存储拼接的sql
2 dbms_lob.write(v_SQL,'写入信息');          --写入操作
3 dbms_lob.append(v_SQL,',');               --拼接clob
4 dbms_lob.substr(v_SQL);                   --截取clob,不传参数就是全部读取
5 dbms_lob.freetemporary(v_SQL);            --释放clob

查询结果如下:

四、在存储过程中使用CLOB类型实例

需求:以开发的存储过程为例,需要循环遍历时间范围拼接sql,将时间日期按列反转(pivot),如果时间太长(1年以上)sql语句(varchar2)就会超出范围报错,这时候就需要使用CLOB来存储拼接的sql。

PROCEDURE P_AND_CPT_RATIOOTH_APP_BAK2_N(V_APPIDS IN VARCHAR2,V_TYPE IN VARCHAR2,V_CHANNEL IN VARCHAR2,V_TABLE IN VARCHAR2,V_START IN VARCHAR2,V_END IN VARCHAR2,RESULT OUT mycursor
) ISV_SQL CLOB;
V_SQLWHERE VARCHAR2(32767) default  '';
V_SQLWHERE_CHANNEL VARCHAR2(32767) default '';
V_SQL_DATES  CLOB;
V_Sdate  DATE;
V_Edate  DATE;
V_TABLE_DATE VARCHAR2(50);
V_TABLE_TYPE VARCHAR2(50);
V_START_DATE VARCHAR2(50);
V_END_DATE   VARCHAR2(50);V_DAY VARCHAR2(50);BEGINselect column_name into V_TABLE_DATE from user_tab_columns where table_name=''||V_TABLE||'' and column_id=1;select column_name into V_TABLE_TYPE from user_tab_columns where table_name=''||V_TABLE||'' and column_id=5;dbms_lob.createtemporary(V_SQL,true);--创建一个临时lobdbms_lob.createtemporary(V_SQL_DATES,true);--创建一个临时lobIF V_APPIDS is NOT NULL THENV_SQLWHERE := 'AND t.appid in ('||V_APPIDS||')';END IF;IF V_CHANNEL IS NOT NULL THENV_SQLWHERE_CHANNEL := 'AND t.channel = '''||V_CHANNEL||'''';END IF;IF V_TABLE_DATE = 'MON' THENV_START_DATE := SUBSTR(V_START,0,6);V_END_DATE :=  SUBSTR(V_END,0,6);v_sdate := to_date(V_START_DATE, 'yyyymm');v_edate := to_date(V_END_DATE, 'yyyymm');WHILE (v_sdate <= v_edate) LOOPdbms_lob.append(v_SQL_DATES,to_char(v_sdate, 'yyyymm'));--把临时字符串付给v_strIF v_sdate != v_edate THENdbms_lob.append(v_SQL_DATES,',');--把临时字符串付给v_strEND IF;v_sdate := add_months(v_sdate,1);END LOOP;ELSE  --周和日 类型 都是 DAYv_sdate := to_date(V_START, 'yyyymmdd');v_edate := to_date(V_END, 'yyyymmdd');V_END_DATE :=  V_END;IF SUBSTR(V_TYPE,0,1)='d' THENV_START_DATE := to_char(v_sdate, 'yyyymmdd');WHILE (v_sdate <= v_edate) LOOPdbms_lob.append(v_SQL_DATES,to_char(v_sdate, 'yyyymmdd'));--把临时字符串付给v_strIF v_sdate != v_edate THENdbms_lob.append(v_SQL_DATES,',');--把临时字符串付给v_strEND IF;v_sdate := v_sdate+1;END LOOP;ELSIF SUBSTR(V_TYPE,0,1)='w' THENselect to_char(V_Sdate,'d') INTO V_DAY from dual;IF V_DAY!=2 THENV_Sdate:=V_Sdate-7;END IF;V_START_DATE := to_char(v_sdate, 'yyyymmdd');WHILE (v_sdate <= v_edate) LOOPselect to_char(V_Sdate,'d') INTO V_DAY from dual;IF V_DAY=2 THENdbms_lob.append(v_SQL_DATES,to_char(v_sdate, 'yyyymmdd'));--把临时字符串付给v_strIF V_Edate-v_sdate >7 THENdbms_lob.append(v_SQL_DATES,',');--把临时字符串付给v_strEND IF;END IF;v_sdate := v_sdate+1;END LOOP;END IF;END IF;dbms_lob.append(v_sql,'SELECT * FROM( SELECT *FROM '||V_TABLE||' tWHERE t.'||V_TABLE_TYPE||' = '''||V_TYPE||'''AND t.'||V_TABLE_DATE||' >= '''||V_START_DATE||'''AND t.'||V_TABLE_DATE||' <= '''||V_END_DATE||''''||V_SQLWHERE||'         '||V_SQLWHERE_CHANNEL||' ) t1pivot(sum(MARKETSHARE)for '||V_TABLE_DATE||' in(');dbms_lob.append(v_sql,v_SQL_DATES);dbms_lob.append(v_sql,'))');dbms_output.put_line(v_sql);      OPEN result FOR v_sql;   dbms_lob.freetemporary(v_sql);--释放lobdbms_lob.freetemporary(v_SQL_DATES);--释放lob--dbms_output.put_line(V_SQLDATE);-- dbms_output.put_line(v_SQL_DATES);--记录操作日志及错误日志
END;

五、使用Java开发操作CLOB字段

(一)、原生JDBC处理CLOB类型

  • 增加,一般会插入一个空的clob到数据库对应的字段,然后锁定该列,用Write将待插入字符串写入进去。

      重点:这两步操作要放在同一个事务里面。具体增加的方法如下:

public boolean save(Article article){boolean result = true;Connection conn = ConnectionUntils.getInstance();String sql = "insert into temp values(?,?,empty_clob())";//锁住该列,防止并发写入时候该字段同时被多次写入造成错误String sqlClob = "select temp_clob from temp t where t.name=? for update";PreparedStatement pst =null;ResultSet rs = null;Writer writer = null;try {conn.setAutoCommit(false);//设置不自动提交,开启事务pst = conn.prepareStatement(sql);pst.setString(1,article.getName());pst.setString(2,article.getAge());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;}

update操作,update时候主要利用PreparedStatement的setClob方法:

public boolean update(String name,String content){int result = 0;Connection conn = ConnectionUntils.getInstance();String sql = "update temp set temp_clob=? where name=?";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.setString(2,name);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(String name){Article article = new Article();Connection conn = ConnectionUntils.getInstance();String sql = "select name,age,temp_clog from temp where name = ?";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("temp_clog");Reader rd = clob.getCharacterStream();char [] str = new char[12];while(rd.read(str) != -1) {builder.append(new String(str));}article.setContent(builder.toString());article.setName(rs.getString("name"));article.setAge(rs.getInt("age"));}} catch (SQLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally{ConnectionUntils.close(rs, pst, conn);}return article;}

(二)、Hibernate、Mybatis框架操作

  • 这个因为框架都封装集成好了,所以我们使用的时候直接配置变量的类型为CLOB就可以。

  譬如:Mybatis

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

貌似Hibernate5内部做了对应的处理,可以直接当string类型一样处理即可。

六、总结

  虽然CLOB能解决VARCHAR2字符大小的限制,但是我们的DBA们都不建议用这些来处理,可能效率问题吧,大的文件应该放在服务器上,然后Database中存响应地址即可。

        if ( U.read(me.Blog) ) $("#推荐").click();if ( U.copy(me.Blog) ) $("#u Blog").console("原文链接:http://www.cnblogs.com/Grand-Jon/p/7389427.html ");else me.Fuck(U);

oracle存储超长文本相关推荐

  1. oracle存储技术,oracle存储体系总结

    最近因工作需要,需要理解oracle单表容量问题,所以,对oracle存储体系进行了学习归纳,图示: 其中块的结构图如下: 块首部(block header)包含块类型的有关信息(表块.索引块等).块 ...

  2. Oracle 存储大文本

    Oracle 存储大文本   string sql = string.Format( "update t_bas_publishtype set content=:content where ...

  3. hive取mysql数据oracle数据,Hive安装过程(mysql/oracle存储元数据)详解

    Hive安装过程(mysql/oracle存储元数据) 前置条件: - mysql数据库已经安装成功 - hadoop环境已经配置正确,且可以提供正常服务 说明: -由于资源有限,下面配置的hadoo ...

  4. Raid Level,该如何为Oracle存储选择才好?

    Ask Maclean Liu Oracle>正文 Raid Level,该如何为Oracle存储选择才好? 原创maclean_0072011-05-21 18:56:23评论(0)65人阅读 ...

  5. oracle 存储结构 语法 第一阶段

    现在开始进攻oracle 存储结构了 ,先从最基本的语法做起! 1 .创建存储过程 create or replace procedure test(var_name_1 in type,var_na ...

  6. Oracle存储架构

    所谓存储架构,这里是指Oracle数据库磁盘空间组织.管理和使用相关的逻辑设计及实现等方面内容.更具体一点,就是讲Oracle数据库是如何组织.分配.管理和使用磁盘文件内的存储空间的.Oracle数据 ...

  7. 解决Oracle存储生僻字、oracle生僻字,oracle偏僻字、数据库生僻字,数据库偏僻字

    处理前,乱码,如下图所示 通过以下方法处理: -- 解决Oracle存储生僻字.oracle生僻字,oracle偏僻字.数据库生僻字,数据库偏僻字 -- 只能保证业务系统能正常读取生僻字-- 第一步: ...

  8. Oracle 存储单位 m³ 存成m3的解决办法

    Oracle 存储单位 m³, 存成m3的解决办法: (1) 首先 字段类型不能为  VARCHAR2,应该为 NVARCHAR2 (2)sql语句,值前加  N  ,标识字符,如: update   ...

  9. oracle存储换硬盘,Oracle 10g RAC 数据存储更换

    说明 目前数据库为10gRAC 环境(10.2.0.4) ,操作系统为 ,采用ASM 磁盘组,需要对存储进行迁移,计划迁移采用oracle rman 迁移方案,确保迁移安全可控.本次迁移涉及ocr,v ...

最新文章

  1. MySQL数据库启动报The server quit without updating PID file
  2. 深度学习入门指北——从硬件到软件
  3. android tag 快捷_Android Studio快捷键生成TAG、Log.x日志输出介绍
  4. 非极大值抑制_非极大值抑制(Non-Maximum Suppression)
  5. 科普 | 一文完全理解AUC-ROC曲线
  6. HYSBZ - 2565 最长双回文串(回文自动机)
  7. ssm 返回json配置_摆脱困境:将运行时配置作为JSON返回
  8. 重复值处理 - 清洗 DataFrame 中的各种重复类型 - Python代码
  9. 京东方将首次向华为供应on-cell OLED面板 用于Mate 40系列
  10. java3d读取3ds文件,基于Java3D与3DSMAX的虚拟校园设计
  11. Linux实操篇-用户管理
  12. Android性能优化第(七)篇---StrickMode严苛模式检测耗时与内存问题
  13. 【史上最最最高仿】V2EX论坛源码—React + Golang开源库,求高手拍砖提建议~
  14. 服务器和微信公众号的区别,微信小程序和公众号的区别,看这三点就懂了
  15. LeetCode 1128.等价多米诺骨牌
  16. freeswitch1.10.7 安装部署排坑
  17. 金山WPS:云端协同 AI赋能 WPS树起了Office新四大件|企服三会系列报道
  18. 光标自动定位到输入框
  19. 机器学习错误率、准确率、精确率、召回率
  20. 人类一败涂地做图教程_《人类:一败涂地》鼠绘图文教程 详细技巧分享

热门文章

  1. h5微信页面在手机微信端和微信web开发者工具中都能正常显示,但是在pc端微信浏览器上打不开(显示空白)...
  2. 小程序底部兼容iphoneX
  3. Android 11.0 12.0系统默认授予读写权限给第三方app
  4. 适配器快充方案——智融SW351X
  5. 【leetcode】开密码锁
  6. 基于GEE黑龙江省大宗农作物空间分布(注释+全套代码)
  7. Camera--(7)手机双摄像头原理及产业解析
  8. 机器学习-波澜壮阔40年
  9. win10任务栏WIFI小图标不见了--解决办法
  10. H5新增input属性值