JDBC读取MySQL的BLOB类型

     在处理维基百科数据的时候从数据库提取text需要读取BLOB数据,一切简单问题规模变大之后都会变得棘手。。

     在多次读取BLOB时我建议使用第一种方法,同时要记着把第11行的outStream设null及时收回,否则就等着Heap Space喊饿吧~第二种方法不推荐是因为String result = new String(b,"utf-8");会经常因为string转化时数组越界挂掉,当然真正原因还是需要从源码分析。。

     今天写了个SQL查数据库,需要根据id分组,然后将同一分组中某几列的值都平铺开来,网络上查了下,MySQL中的 GROUP_CONCAT 函数,还是很好用的,SQL 大致写成如下:

1 select `id` , GROUP_CONCAT(concat(`key`,':',`value`) ORDER BY `key`  SEPARATOR ","as prefs from `table_name` GROUP BY `id`

     效果还算不错,但是在Java程序中查询这条SQL时,却出现了一些小意外,分组排列的字段显示不出来,我当时使DBUtils 查的,用MapListHandler 来读出的该字段,读出来全是乱码, 于是跟到源码里,调了半天不知道问题,后来同事提示才发现,由于同一组中,个数太多,导致这些值产生的字符串很长,于是MySQL会自动把这列的结果类型转换成BLOB,这种类型读取的方式很特别,若用JDBC中 getObject(int index)方法读取的话,就会是乱码(DBUtils这里就是用的JDBC中的  getObject(int index) 来读取数据)。

     读取数据库中BLOB数据类型的方法,我在网上找了一下,找到两种,根据自身情况也实现了一下,我需要将BLOB类型 转换成String,代码如下

第一种方法:

01 public String getBlob(String SQL){
02         Connection conn = null;
03         PreparedStatement stmt = null;
04         ResultSet rs = null;
05             try {
06                 conn = dataSource.getConnection();//c3p0连接池
07                 stmt = conn.prepareStatement(SQL);//SQL: select info from table1 (其中info字段是blob类型)
08                 rs = stmt.executeQuery();
09                  
10                 InputStream in = rs.getBinaryStream(1);
11                 ByteArrayOutputStream outStream = new ByteArrayOutputStream();
12                 byte[] data = new byte[4096];
13                 int count = -1;
14                 while((count = in.read(data,0,4096)) != -1)
15                     outStream.write(data, 0, count);
16                  
17                 data = null;
18                 String result = new String(outStream.toByteArray(),"utf-8");
19             catch (SQLException sqle) {
20                 log.warn("Exception XXX", sqle);
21             }finally{
22                 conn.close();
23                 stmt.close();
24             }
25     }

第二种方法:

01 public String getBlob(String SQL){
02         Connection conn = null;
03         PreparedStatement stmt = null;
04         ResultSet rs = null;
05             try {
06                 conn = dataSource.getConnection();//c3p0连接池
07                 stmt = conn.prepareStatement(SQL);//SQL: select info from table1 (其中info字段是blob类型)
08                 rs = stmt.executeQuery();
09                  
10                 Blob bb = rs.getBlob(i);
11                 byte[] b = bb.getBytes(1, (int)bb.length());
12                  
13                 String result = new String(b,"utf-8");
14             catch (SQLException sqle) {
15                 log.warn("Exception XXX", sqle);
16             }finally{
17                 conn.close();
18                 stmt.close();
19             }
20     }

     这里看第二种方法要简单点,但是第一种貌似是用来直接将结果写入文件中,因为我这里需要转换成String,所以偏第二种。

     最后我想在 DBUtils里面读取的时候就直接帮我转换的,研究了一下源代码后,貌似这么改可以做到,加一层判断,若结果类型为BLOB 则用上述读法。若不是还是按原来的逻辑走,修改的是以修改 org.apache.commons.dbutils.BasicRowProcessor 中的将结果封装诚Map的方法为例(RowProcessor为用于处理数据封装的,还有封装其他数据结构的方法你也可以根据需要改),改的不好,见笑了:

01 public Map<String, Object> toMap(ResultSet rs) throws SQLException {
02         Map<String, Object> result = new CaseInsensitiveHashMap();
03         ResultSetMetaData rsmd = rs.getMetaData();
04         int cols = rsmd.getColumnCount();
05  
06         for (int i = 1; i <= cols; i++) {
07             //通过ResultSetMetaData类,可判断该列数据类型
08             if(rsmd.getColumnTypeName(i).equals("BLOB")){
09                 Blob bb = rs.getBlob(i);
10                 byte[] b = bb.getBytes(1, (int)bb.length());
11                  
12                 try {
13                     //将结果放到Map中
14                     result.put(rsmd.getColumnName(i), new String(b,"utf-8"));
15                 catch (UnsupportedEncodingException e) {
16                     // TODO Auto-generated catch block
17                     e.printStackTrace();
18                 }
19             }else{
20                 //不是则按原来逻辑运算
21                 result.put(rsmd.getColumnName(i), rs.getObject(i));
22             }
23         }
24  
25         return result;
26     }

    原创博客,转载请注明 http://my.oschina.net/BreathL/blog/63359

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值