@EVA001
2018-09-01T16:35:09.000000Z
字数 3667
阅读 669
未分类
在需要存储较长字符串到数据库中时往往需要使用一些特殊类型的字段,在Oracle中即blob和clob字段,一般而言:
注意,上述字段的使用均可以用其他方式替代,比如用MongoDB或者图片直接存储为文件等等,这里不纠结场景的合适与否,只是针对Blob和Clob类型的使用来举例。
主要有三种场景:
总结来看,后两种均以第一种场景为基础,即我们必须明确如何向Blob和Clob字段写入数据。第二种场景实际上是第一种的重复操作,那么对于第三种,需要十分注意,这里意味着需要向表中插入一行记录,操作有部分差异,在此我们就用第三种场景为例来给出示例。
情景再现:
从数据源接收数据,解析完成后产生SQL语句并批量插入数据表,注意,原记录中含有若干个Blob字段(图片编码)和若干个Clob字段(记录信息),其余字段均为一般类型(String,Integer)
在给出代码前,注意几点:
下面就以带特定场景需求的代码来展示写入示例。
数据源每次发送一个XML字符串非常长,代码端每次解析这个串,解析后会成为 N 条记录,其中每条记录要解析为 M 个字段,其中含有 m 个Blob字段和 n 个Clob字段,现在需要把这 N 条记录插入到数据表中。
上述的 N,M,n,m 大小均不定且动态变化(已知某些字段是,但这些字段不一定出现),即大小未知。
// ... ... 整个过程围绕xml节点的迭代来完成while(iter1.hasNext()){Element e = iter1.next();Iterator<Element> iter2 = e.elementIterator();// 每一条SQLwhile(iter2.hasNext()){boolean flag1 = false; // 标志是否含有Clob字段boolean flag2 = false; // 标志是否含有Blob字段String blobId = ""; // 储存所在SQL语句的主键值// ... ...// 开始组装每一条SQL语句Iterator<Element> iter3 = f.elementIterator();while(iter3.hasNext()){// ... ...switch(colname){case "CLOB字段名1" :case "CLOB字段名2" :// ...case "CLOB字段名N" : { //暂存CLOB数据cList.add(colname);cList.add(h.getStringValue());flag1 = true;break; // break switch}case "BLOB字段名1" :case "BLOB字段名2" :// ...case "BLOB字段名N" :{ //暂存BLOB数据bList.add(colname);bList.add(h.getStringValue());flag2 = true;break;}default:{if( this value is the primary key ){blobId = this value}strVALUE.append( this valu , ); // 字段值strNAMES.append( his value , ); // 字段名}}}// 去掉最后一个多余的逗号strVALUE.deleteCharAt( strVALUE.length() - 1);strNAMES.deleteCharAt( strNAMES.length() - 1);// 然后追加处理 empty_clob()和empty_blob()for(int i = 0;i < cList.size(); i=i+2){strNAMES.append(",\""+cList.get(i)+"\"");strVALUE.append(",empty_clob()");}for(int i = 0;i < bList.size(); i=i+2){strNAMES.append(",\""+bList.get(i)+"\"");strVALUE.append(",empty_blob()");}// 最终形态(第一次插入的语句)sqlStr.append("INSERT INTO 表名 ( "+strNAMES+" ) VALUES ( "+strVALUE+" )");pstmt = con.prepareStatement(sqlStr.toString());pstmt.executeUpdate(); // first insert doneif(pstmt != null){pstmt.close();}// 上述第一次插入完成后,开始单独处理特殊类型(第二次插入)// 根据 flag1 判断是否有Clob类型的数据if(flag1){for(int i = 0;i < cList.size(); i=i+2){pstmt = con.prepareStatement("SELECT "+cList.get(i)+" FROM 表名 WHERE 表主键 = "+blobId+" for update");ResultSet rs = pstmt.executeQuery();Writer outStream = null;if (rs.next()) {//得到java.sql.Clob对象后强制转换为oracle.sql.CLOBoracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob(cList.get(i));outStream = clob.getCharacterOutputStream();//传入字符串char[] c = cList.get(i+1).toCharArray();outStream.write(c, 0, c.length);}outStream.flush();outStream.close();con.commit();if(pstmt != null){pstmt.close();}}}// 根据 flag1 判断是否有Blob类型的数据if(flag2){for(int i = 0;i < bList.size(); i=i+2){pstmt = con.prepareStatement("SELECT "+bList.get(i)+" FROM 表名 WHERE 表主键 = "+blobId+" for update" );ResultSet rs = pstmt.executeQuery();OutputStream os = null;if (rs.next()) {// 得到java.sql.Blob对象后强制转换为oracle.sql.BLOBoracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob(bList.get(i));// 通过getBinaryOutputStream()方法获得向数据库中插入图片的流os = blob.getBinaryOutputStream();// 读取想要存储的图片文件(或串值)InputStream is = new ByteArrayInputStream(bList.get(i+1).getBytes());// 依次读取流字节,并输出到已定义好的数据库字段中.int b = 0;while ((b = is.read()) != -1) {os.write(b);}}os.flush();os.close();con.commit();if(pstmt != null){pstmt.close();}}}} // end while} // end while
上述代码段的环境非常特殊,前面已经说了,是一个比较复杂的处理逻辑,代码中有些变量定义没写出来,有些地方也去掉了特定变量换成了文字叙述,所以,上述代码仅仅是为了提供思路,并且包含了一些处理技巧:
如果你有更好的方法或者是对该文章有任何的疑问或想法,请在下方留言,我会第一时间回复的!