使用Mybatis分别在Oracle数据库和MySQL数据库中存取BLOB类型

© Young 2016-04-04 14:34
Welcome to My GitHub

概要

使用Mybatis在MySQL数据库中存取BLOB类型数据比较简单唯一需要注意的是乱码的问题,但是在Oracle中存取BLOB类型数据则相对来说有一些复杂…

使用Mybatis在MySQL数据库中存取BLOB类型数据

1、实体里边使用String类型即可,实体类代码片段:
/* 文章内容 */
private String content;
2、在Mybatis的mapper配置文件中,resultMap应该是:
<!-- 实体类全属性和表全字段对应关系 -->
<resultMap id="articleResult" type="knowledge.article.model.Article" >
    <!-- 其它属性省略 -->
    <result property="content" column="CONTENT" typeHandler="common.architect.ConvertBlobTypeHandler"/> 
</resultMap>
3、typeHandler="common.architect.ConvertBlobTypeHandler"主要是为了解决乱码的问题,类具体代码如下:
package common.architect;


import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;


/**
 * 自定义typehandler,解决mybatis存储blob字段后,出现乱码的问题
 * 配置mapper.xml:
 * <result typeHandler="common.architect.ConvertBlobTypeHandler"/>
 */
public class ConvertBlobTypeHandler extends BaseTypeHandler<String> {  
    //###指定字符集  
    private static final String DEFAULT_CHARSET = "utf-8";


    @Override  
    public void setNonNullParameter(PreparedStatement ps, int i,  
            String parameter, JdbcType jdbcType) throws SQLException {  
        ByteArrayInputStream bis;  
        try {  
            //###把String转化成byte流  
            bis = new ByteArrayInputStream(parameter.getBytes(DEFAULT_CHARSET));  
        } catch (UnsupportedEncodingException e) {  
            throw new RuntimeException("Blob Encoding Error!");  
        }     
        ps.setBinaryStream(i, bis, parameter.length());  
    }


    @Override  
    public String getNullableResult(ResultSet rs, String columnName)  
            throws SQLException {  
        Blob blob = rs.getBlob(columnName);  
        byte[] returnValue = null;  
        if (null != blob) {  
            returnValue = blob.getBytes(1, (int) blob.length());  
        }  
        try {  
            //###把byte转化成string  
            return new String(returnValue, DEFAULT_CHARSET);  
        } catch (UnsupportedEncodingException e) {  
            throw new RuntimeException("Blob Encoding Error!");  
        }  
    }


    @Override  
    public String getNullableResult(CallableStatement cs, int columnIndex)  
            throws SQLException {  
        Blob blob = cs.getBlob(columnIndex);  
        byte[] returnValue = null;  
        if (null != blob) {  
            returnValue = blob.getBytes(1, (int) blob.length());  
        }  
        try {  
            return new String(returnValue, DEFAULT_CHARSET);  
        } catch (UnsupportedEncodingException e) {  
            throw new RuntimeException("Blob Encoding Error!");  
        }  
    }


    @Override
    public String getNullableResult(ResultSet arg0, int arg1)
            throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }  
}
4、读取和插入SQL就和其它基本类型一样处理就可以了,就拿单记录插入SQL举例:
<!-- 增加一条记录(返回主键) -->
<insert id="insert" parameterType="article">
    INSERT INTO 
    NEW_KNOWLEDGE_ARTICLE (
        <!-- 其它属性省略 -->
        CONTENT 
    ) VALUES (
        <!-- 其它属性省略 -->
        #{content,jdbcType=BLOB}
    )
    <!-- MySQL插入返回主键和Oracle不一样,留意一下 -->
    <selectKey keyProperty="id" resultType="Long" order="AFTER">
        select LAST_INSERT_ID() 
    </selectKey> 
</insert>

使用Mybatis在Oracle数据库中存取BLOB类型数据

1、实体里边使用只能使用Object类型,不能使用byte[],也不能使用BLOB,我试过会有问题…实体类代码片段:
/* 文章内容 */
private Object content;
2、由于在前台需要展示文章内容,所以不管你是用jsp或者其它模板,这里还需要转换成String类型才行,转换代码片段:
try{  
    BLOB blob = (BLOB)this.getContent();
    contentStr = new String(blob.getBytes((long)1, (int)blob.length()));  
} catch(SQLException e) {  
    e.printStackTrace();  
}
3、在Mybatis的mapper配置文件中,resultMap应该是:
<!-- 实体类全属性和表全字段对应关系 -->
<resultMap id="articleResult" type="knowledge.article.model.Article" >
    <!-- 其它属性省略 -->
    <result property="content" column="CONTENT" jdbcType="BLOB"/> 
</resultMap>
4、此外Oracle数据库插入BLOB类型数据的时候,要先插入一个empty_blob()占位符,然后再查询出来这个大字段用流的方式写入,所以用Mybatis在Oracle数据库中插入BLOB类型

数据时要在DAO以及mapper配置文件中分两步处理。mapper配置文件片段(表示引入某个全字段SQL片段):

<!-- 增加一条记录(返回主键) -->
<insert id="insert" parameterType="article">
    <!-- Oracle插入返回主键和MySQL不一样,留意一下 -->
    <selectKey resultType="long" order="BEFORE" keyProperty="id">
        SELECT seq_new_knowledge_article.NEXTVAL FROM DUAL
    </selectKey>
    INSERT INTO 
    NEW_KNOWLEDGE_ARTICLE T (
    <include refid="allColumn"/>
    ) VALUES (
        #{id},
        #{addTime,jdbcType=TIME},
        #{editTime,jdbcType=TIME},
        #{type,jdbcType=VARCHAR},
        #{title,jdbcType=VARCHAR},
        #{author,jdbcType=VARCHAR},
        #{summary,jdbcType=VARCHAR},
        #{keywords,jdbcType=VARCHAR},
        #{localUrl,jdbcType=VARCHAR},
        empty_blob(),
        #{showPic,jdbcType=VARCHAR},
        #{lookNum,jdbcType=INTEGER},
        #{memo,jdbcType=VARCHAR},
        #{lastLookTime,jdbcType=TIME}
    )
</insert>
<!-- 辅助插入BLOB -->
<select id="helperInsertBlob" resultMap="articleResult">
    SELECT 
    <include refid="allColumn"/>
    FROM NEW_KNOWLEDGE_ARTICLE T
    WHERE T.ID = #{id}
    FOR UPDATE
</select>


//DAO处理方法
/**
 * 新增
 * @param article
 * @return
 */
public Long insert(Article article){
    sqlSessionTemplate.insert("newKnowledgeArticle.insert", article);
    Article result = this.helperInsertBlob(article.getId());
    BLOB blob = (BLOB)result.getContent();  
    OutputStream ops = null;  
    ops = blob.getBinaryOutputStream();//暂时使用这个废弃的方法  
    //ops = content.setBinaryStream(0);//ojdbc14支持,ojdbc6,5都不支持  
    String contentStr = (String)article.getContent();
    byte[] data = contentStr.getBytes();  
    ops.write(data);  
    ops.close();  
    return article.getId();
}


/**
 * 辅助新增BLOB
 * @param id
 * @return
 */
private Article helperInsertBlob(@Param("id")long id){
    return sqlSessionTemplate.selectOne("newKnowledgeArticle.helperInsertBlob",id);
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注