oracle存储超长文本
一、Oracle中的varchar2类型
我们在Oracle数据库存储的字符数据一般是用VARCHAR2。VARCHAR2既分PL/SQL Data Types中的变量类型,也分Oracle Database中的字段类型,不同场景的最大长度不同。
在Oracle Database中,VARCHAR2 字段类型,最大值为4000(汉字2000);PL/SQL中 VARCHAR2 变量类型,最大字节长度为32767。
当 VARCHAR2 容纳不下我们需要存储的信息时,就需要用Oracle的大数据类型LOB( Large Object,大型对象)。
二、Oarcle中的LOB类型
在Oracle中,LOB(Large Object,大型对象)类型的字段现在用得越来越多了。因为这种类型的字段,容量大(最多能容纳4GB的数据),且一个表中可以有多个这种类型的字段,很灵活,适用于数据量非常大的业务领域(如图象、档案等)。
LOB类型分为BLOB和CLOB两种:BLOB即二进制大型对象(Binary Large Object),适用于存贮非文本的字节流数据(如程序、图象、影音等)。
而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存储超长文本相关推荐
- oracle存储技术,oracle存储体系总结
最近因工作需要,需要理解oracle单表容量问题,所以,对oracle存储体系进行了学习归纳,图示: 其中块的结构图如下: 块首部(block header)包含块类型的有关信息(表块.索引块等).块 ...
- Oracle 存储大文本
Oracle 存储大文本 string sql = string.Format( "update t_bas_publishtype set content=:content where ...
- hive取mysql数据oracle数据,Hive安装过程(mysql/oracle存储元数据)详解
Hive安装过程(mysql/oracle存储元数据) 前置条件: - mysql数据库已经安装成功 - hadoop环境已经配置正确,且可以提供正常服务 说明: -由于资源有限,下面配置的hadoo ...
- Raid Level,该如何为Oracle存储选择才好?
Ask Maclean Liu Oracle>正文 Raid Level,该如何为Oracle存储选择才好? 原创maclean_0072011-05-21 18:56:23评论(0)65人阅读 ...
- oracle 存储结构 语法 第一阶段
现在开始进攻oracle 存储结构了 ,先从最基本的语法做起! 1 .创建存储过程 create or replace procedure test(var_name_1 in type,var_na ...
- Oracle存储架构
所谓存储架构,这里是指Oracle数据库磁盘空间组织.管理和使用相关的逻辑设计及实现等方面内容.更具体一点,就是讲Oracle数据库是如何组织.分配.管理和使用磁盘文件内的存储空间的.Oracle数据 ...
- 解决Oracle存储生僻字、oracle生僻字,oracle偏僻字、数据库生僻字,数据库偏僻字
处理前,乱码,如下图所示 通过以下方法处理: -- 解决Oracle存储生僻字.oracle生僻字,oracle偏僻字.数据库生僻字,数据库偏僻字 -- 只能保证业务系统能正常读取生僻字-- 第一步: ...
- Oracle 存储单位 m³ 存成m3的解决办法
Oracle 存储单位 m³, 存成m3的解决办法: (1) 首先 字段类型不能为 VARCHAR2,应该为 NVARCHAR2 (2)sql语句,值前加 N ,标识字符,如: update ...
- oracle存储换硬盘,Oracle 10g RAC 数据存储更换
说明 目前数据库为10gRAC 环境(10.2.0.4) ,操作系统为 ,采用ASM 磁盘组,需要对存储进行迁移,计划迁移采用oracle rman 迁移方案,确保迁移安全可控.本次迁移涉及ocr,v ...
最新文章
- MySQL数据库启动报The server quit without updating PID file
- 深度学习入门指北——从硬件到软件
- android tag 快捷_Android Studio快捷键生成TAG、Log.x日志输出介绍
- 非极大值抑制_非极大值抑制(Non-Maximum Suppression)
- 科普 | 一文完全理解AUC-ROC曲线
- HYSBZ - 2565 最长双回文串(回文自动机)
- ssm 返回json配置_摆脱困境:将运行时配置作为JSON返回
- 重复值处理 - 清洗 DataFrame 中的各种重复类型 - Python代码
- 京东方将首次向华为供应on-cell OLED面板 用于Mate 40系列
- java3d读取3ds文件,基于Java3D与3DSMAX的虚拟校园设计
- Linux实操篇-用户管理
- Android性能优化第(七)篇---StrickMode严苛模式检测耗时与内存问题
- 【史上最最最高仿】V2EX论坛源码—React + Golang开源库,求高手拍砖提建议~
- 服务器和微信公众号的区别,微信小程序和公众号的区别,看这三点就懂了
- LeetCode 1128.等价多米诺骨牌
- freeswitch1.10.7 安装部署排坑
- 金山WPS:云端协同 AI赋能 WPS树起了Office新四大件|企服三会系列报道
- 光标自动定位到输入框
- 机器学习错误率、准确率、精确率、召回率
- 人类一败涂地做图教程_《人类:一败涂地》鼠绘图文教程 详细技巧分享