- 浏览: 212016 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
Wangwei86609:
非常好的规则引擎框架,支持决策树和多线程运行规则https:/ ...
规则引擎 -
hzxlb910:
真详细,收藏哈
maven setting.xml配置说明 -
东方胜:
[b][/b]
脚本语言 Tcl -
345161974:
hyw520110 写道345161974 写道这个Visua ...
Visual Tcl Binary 完整版(完美中文支持) -
hyw520110:
345161974 写道这个Visual Tcl Binary ...
Visual Tcl Binary 完整版(完美中文支持)
转载:http://www.iteye.com/topic/74678
Ibatis是一个高效,方便,易于学习的数据访问组件,在性能上比hibernate高,学习难度也比hibernate和jdo要低,而且它比直接使用jdbc方便和易于维护。所以Ibatis深入大家的喜爱,一些对性能有更高的要求的系统(如保险,金融行业系统),或改造遗留系统时,Ibatis是数据访问组件的首选。
在使用Oracle数据库时,读取CLOB和BLOB等大类型的数据一直是个比较犯难的事,一般都是通过JDBC代码来实现对CLOB和BLOB数据的读写,效果和性能都是最好的,但是代码也相当复杂,且代码难以重用。
在使用ibatis作为数据访问组件,也经常会遇到要读取CLOB,BLOB大类型数据。怎样使用Ibatis读取CLOB,BLOB数据也是一个难题,并且Oracle在这方面一直没有解决好。
公司的项目正好有这方面的需要,要求我给予解决。在网上找了很多的资料,都没有一个比较简单易用的解决办法,通过不断的验实,终于得出了比较好的解决办法,所以写成文字,大家可以分享。如果大家以后有这方面的需要就可以直接使用,少走弯路,当然如果大家有更好的办法,希望能告诉我,我当不胜感激。
准备工作:
1. 测试数据库
- CREATE TABLE USERINFO(USERID VARCHAR2(5),
- USERNAME VARCHAR2(20),
- MEMO CLOB,
- constraint PK_USERINFO primary key(USERID));
CREATE TABLE USERINFO(USERID VARCHAR2(5), USERNAME VARCHAR2(20), MEMO CLOB, constraint PK_USERINFO primary key(USERID));
2.域模型对象
UserInfoDTO.java
- import java.io.Serializable;
- public class UserInfoDTO implements Serializable {
- /*用户id*/
- private String userID;
- /*用户名*/
- private String userName;
- /*备注*/
- private String memo;
- public String getMemo() {
- return memo;
- }
- public void setMemo(String memo) {
- this.memo = memo;
- }
- public String getUserID() {
- return userID;
- }
- public void setUserID(String userID) {
- this.userID = userID;
- }
- public String getUserName() {
- return userName;
- }
- public void setUserName(String userName) {
- this.userName = userName;
- }
- }
import java.io.Serializable; public class UserInfoDTO implements Serializable { /*用户id*/ private String userID; /*用户名*/ private String userName; /*备注*/ private String memo; public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } public String getUserID() { return userID; } public void setUserID(String userID) { this.userID = userID; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
3.数据访问对象接口
UserInfoDao.java
- public interface UserInfoDao {
- public List getUsers(UserInfoDTO user) throws DataAccessException;
- public void insertUser(UserInfoDTO user) throws DataAccessException;
- }
public interface UserInfoDao { public List getUsers(UserInfoDTO user) throws DataAccessException; public void insertUser(UserInfoDTO user) throws DataAccessException; }
一、 读取CLOB,BLOB类型数据的几种方法
1. jdbc实现
采用jdbc来读写是最原始,也是最直接的方法
UserInfoDaoImpl.java
- public class UserInfoDaoImpl extends SqlMapClientDaoSupport implements
- UserInfoDao {
- Connection con = null;
- private Connection getConnection() throws SQLException {
- Connection con = null;
- con = this.getSqlMapClientTemplate().getDataSource().getConnection();
- con.setAutoCommit(false);
- return con;
- }
- public void insertUser(UserInfoDTO user) throws DataAccessException {
- try {
- this.con = this.getConnection();
- final String insertSql = "INSERT INTO USERINFO(USERID,USERName,memo) VALUES(?,?,?)";
- final String selectSql = "SELECT MEMO FROM USERINFO WHERE USERID = ? FOR UPDATE";
- final String updateSql = "UPDATE USERINFO SET MEME = ? WHERE USERID = ?";
- PreparedStatement ps = con.prepareStatement(insertSql);
- ps.setString(1, user.getUserID());
- ps.setString(2, user.getUserName());
- ps.setClob(3, CLOB.empty_lob());
- ps.executeUpdate();
- ps.close();
- ps = this.con.prepareStatement(selectSql);
- ps.setString(1, user.getUserID());
- ResultSet rs = ps.executeQuery();
- rs.next();
- CLOB memo = (CLOB) rs.getClob(1);
- memo.setString(1, user.getMemo());
- ps = this.con.prepareStatement(updateSql);
- ps.setClob(1, memo);
- ps.setString(2, user.getUserID());
- ps.executeUpdate();
- ps.close();
- this.con.commit();
- } catch (Exception ex) {
- throw new DataAccessResourceFailureException(ex.getMessage(), ex);
- } finally {
- try {
- if (this.con != null)
- this.con.close();
- } catch (Exception ex) {
- throw new DataAccessResourceFailureException(ex.getMessage(),
- ex);
- }
- }
- }
public class UserInfoDaoImpl extends SqlMapClientDaoSupport implements UserInfoDao { Connection con = null; private Connection getConnection() throws SQLException { Connection con = null; con = this.getSqlMapClientTemplate().getDataSource().getConnection(); con.setAutoCommit(false); return con; } public void insertUser(UserInfoDTO user) throws DataAccessException { try { this.con = this.getConnection(); final String insertSql = "INSERT INTO USERINFO(USERID,USERName,memo) VALUES(?,?,?)"; final String selectSql = "SELECT MEMO FROM USERINFO WHERE USERID = ? FOR UPDATE"; final String updateSql = "UPDATE USERINFO SET MEME = ? WHERE USERID = ?"; PreparedStatement ps = con.prepareStatement(insertSql); ps.setString(1, user.getUserID()); ps.setString(2, user.getUserName()); ps.setClob(3, CLOB.empty_lob()); ps.executeUpdate(); ps.close(); ps = this.con.prepareStatement(selectSql); ps.setString(1, user.getUserID()); ResultSet rs = ps.executeQuery(); rs.next(); CLOB memo = (CLOB) rs.getClob(1); memo.setString(1, user.getMemo()); ps = this.con.prepareStatement(updateSql); ps.setClob(1, memo); ps.setString(2, user.getUserID()); ps.executeUpdate(); ps.close(); this.con.commit(); } catch (Exception ex) { throw new DataAccessResourceFailureException(ex.getMessage(), ex); } finally { try { if (this.con != null) this.con.close(); } catch (Exception ex) { throw new DataAccessResourceFailureException(ex.getMessage(), ex); } } }
2. 使用Spring的org.springframework.jdbc.support.lob.OracleLobHandler类处理
2.1 sql-map-config.xml的配置
- <typeHandler jdbcType="CLOB" javaType="java.lang.String" callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>
<typeHandler jdbcType="CLOB" javaType="java.lang.String" callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>
2.2 sqlMapClient的配置
- <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <property name="configLocation"><value>/sql-map-config.xml</value></property>
- <property name="dataSource"><ref local="dataSource"/></property>
- <property name="lobHandler"><ref local="oracleLobHandler"/></property>
- </bean>
- <bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler"
- lazy-init="true">
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation"><value>/sql-map-config.xml</value></property> <property name="dataSource"><ref local="dataSource"/></property> <property name="lobHandler"><ref local="oracleLobHandler"/></property> </bean> <bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
特别注意:采用这种方法只对数据源是直接连接Oracle 的JDBC驱动方式有效,如果你采用数据连接池作为数据源,则这种办法无效。但是一般大型的项目都是使用连接池的,所以这个方法有很大的局限性。
3. 通过实现Ibatis的TypeHandlerCallback接口来实现
下面是读取的方法:
- public class OracleClobTypeHandlerCallback implements TypeHandlerCallback {
- public void setParameter(ParameterSetter setter, Object obj)
- throws SQLException {
- // TODO Auto-generated method stub
- CLOB clob = CLOB.empty_lob();
- clob.setString(1, (String)obj);
- setter.setClob(clob);
- }
- public Object getResult(ResultGetter getter) throws SQLException {
- CLOB clob = (CLOB) getter.getClob();
- return (clob == null || clob.length() == 0 )? null :clob.getSubString((long)1, (int)clob.length());
- }
- public Object valueOf(String param) {
- // TODO Auto-generated method stub
- return null;
- }
- }
public class OracleClobTypeHandlerCallback implements TypeHandlerCallback { public void setParameter(ParameterSetter setter, Object obj) throws SQLException { // TODO Auto-generated method stub CLOB clob = CLOB.empty_lob(); clob.setString(1, (String)obj); setter.setClob(clob); } public Object getResult(ResultGetter getter) throws SQLException { CLOB clob = (CLOB) getter.getClob(); return (clob == null || clob.length() == 0 )? null :clob.getSubString((long)1, (int)clob.length()); } public Object valueOf(String param) { // TODO Auto-generated method stub return null; } }
sqlMap 的配置
- <resultMap id="userResult" class="com.prs.application.ehld.sample.common.dto.UserInfoDTO">
- <result property="userID" column="USERID" columnIndex="1"/>
- <result property="userName" column="USERNAME" columnIndex="2"/>
- <result property="memo" column="memo" jdbcType="CLOB" javaType = "java.lang.String" typeHandler =" OracleClobTypeHandlerCallback "/>
- </resultMap>
<resultMap id="userResult" class="com.prs.application.ehld.sample.common.dto.UserInfoDTO"> <result property="userID" column="USERID" columnIndex="1"/> <result property="userName" column="USERNAME" columnIndex="2"/> <result property="memo" column="memo" jdbcType="CLOB" javaType = "java.lang.String" typeHandler =" OracleClobTypeHandlerCallback "/> </resultMap>
二、 存在的问题
上面三种方法都存在的问题:
1. 使用jdbc来实现,就失去了使用ibatis带来的便利,同时也失去了自动事务管理的能力,还有需要自己去手工管理连接对象。代码量也相当复杂。
2. 使用spring提供的处理器,不支持采用数据连接池的数据源,有很大的局限性。
3. 通过实现ibatis的回调接口来实现,也有一定的局限性,需要新增一个类,配置也不方便,还可能会出错。
难道ibatis读写LOB大类型数据就没辙了吗?通过试验,发现可以配置ParameterMap和ResultMap就可以方便的实现对LOB的读写了,而且不用去实现任何类。只需要配置就可以了
三、 通过配置ParameterMap和ResultMap来实现对LOB类型的读写
3.1 sqlMap的配置
- <resultMap id="userResult" class="com.prs.application.ehld.sample.common.dto.UserInfoDTO">
- <result property="userID" column="USERID" columnIndex="1"/>
- <result property="userName" column="USERNAME" columnIndex="2"/>
- [color=darkred]<result property="memo" column="memo" jdbcType="CLOB" javaType = "java.lang.String" />[/color]</resultMap>
- <parameterMap id="userPara" class = "com.prs.application.ehld.sample.common.dto.UserInfoDTO">
- <parameter property="userID" jdbcType="VARCHAR" javaType ="java.lang.String"/>
- <parameter property="userName" jdbcType="VARCHAR" javaType ="java.lang.String"/>
- [color=darkred]<parameter property="memo" jdbcType="CLOB" javaType ="java.lang.String"/>[/color]
- </parameterMap>
<resultMap id="userResult" class="com.prs.application.ehld.sample.common.dto.UserInfoDTO"> <result property="userID" column="USERID" columnIndex="1"/> <result property="userName" column="USERNAME" columnIndex="2"/> [color=darkred]<result property="memo" column="memo" jdbcType="CLOB" javaType = "java.lang.String" />[/color]</resultMap> <parameterMap id="userPara" class = "com.prs.application.ehld.sample.common.dto.UserInfoDTO"> <parameter property="userID" jdbcType="VARCHAR" javaType ="java.lang.String"/> <parameter property="userName" jdbcType="VARCHAR" javaType ="java.lang.String"/> [color=darkred]<parameter property="memo" jdbcType="CLOB" javaType ="java.lang.String"/>[/color] </parameterMap>
3.2 插入和读取语句的配置
- <select id="getUserInfoList" resultMap="userResult" >
- SELECT
- USERINFO.USERID ,
- USERINFO.USERName ,
- USERINFO.MEMO
- FROM USERINFO
- </select>
- <insert id="insertUserInfo" parameterMap = "userPara" >
- INSERT INTO USERINFO(USERID,
- USERName,
- memo)
- VALUES([color=darkred]?,?,?[/color]
- )
- </insert>
<select id="getUserInfoList" resultMap="userResult" > SELECT USERINFO.USERID , USERINFO.USERName , USERINFO.MEMO FROM USERINFO </select> <insert id="insertUserInfo" parameterMap = "userPara" > INSERT INTO USERINFO(USERID, USERName, memo) VALUES([color=darkred]?,?,?[/color] ) </insert>
注意:因为使用了ParameterMap作为输入参数,在插入语句中用?号来代替属性值(如:#userId#)
而不是常见的:
INSERT INTO USERINFO(USERID, USERName, memo) VALUES(#userId#, #userName#, #memo# )
但是当paramaterMap的class属性是java.util.Map类时,应该使用#userId#类似的参数,不能用?来代替。
但是这又有一个问题,就是插入的字符串不能超过4000个字符,而CLOB类型的字段可以存4GB大小的字符。只要对userInfo对象的memo成员设置字符串超过了4000个字符,就提示“不能创建更多的套接字”,为什么会报这个错,暂是没有弄清楚。
而需求是要CLOB字段要存6000个汉字,相当于12000个英文字符。可以说是白忙了一场,没有达到目的。
四、 使用Oracle 10g的jdbc驱动程序
因为字符串只要超过了4000个字符就不能插入,所以不得不试着换一下驱动程序看看。一直以来都认为oracel的jdbc 驱动对处理LOB对象有一些问题,想看看10g出来后是不是有所改变。于是上网下载10g的驱动,一阵痛苦的等待后,问题解决,我把字符串设为12万个字符也没有问题了。
另外采用10g 的驱动就算不使用parameterMap也可以成功的插入字符串到CLOB类型字段去,请要注意的是,这样只能插入的字符一定要小于32767个。也就是说我把memo 属性设置多于32766个字符,照样插不进去。这个原因主要是jdbc驱动限制了String的长度的原因。
- <insert id="insertUserInfo" parameterClass = "UserInfoDTO" >
- INSERT INTO USERINFO(USERID,
- USERName,
- memo)
- VALUES(#userID#,
- #userName#,
- #memo#
- )
- </insert>
<insert id="insertUserInfo" parameterClass = "UserInfoDTO" > INSERT INTO USERINFO(USERID, USERName, memo) VALUES(#userID#, #userName#, #memo# ) </insert>
使用10g的驱动,这样能写入32766个字符
五、 怎么读写BLOB
上面都一直在说CLOB,其实把CLOB实现了,那么BLOB也同样简单,只是注意它的java类型,如果一个字段为BLOB类型,那么在parameterMap中jdbcType 为BLOB,
把javaType设为:[]byte就可以了。
例:
- <parameterMap id="userPara" class = "com.prs.application.ehld.sample.common.dto.UserInfoDTO">
- <parameter property="userID" jdbcType="VARCHAR" javaType ="java.lang.String"/>
- <parameter property="userName" jdbcType="VARCHAR" javaType ="java.lang.String"/>
- [color=red]<parameter property="memo" jdbcType="BLOB" javaType ="[]byte"/>[/color]
- </parameterMap>
<parameterMap id="userPara" class = "com.prs.application.ehld.sample.common.dto.UserInfoDTO"> <parameter property="userID" jdbcType="VARCHAR" javaType ="java.lang.String"/> <parameter property="userName" jdbcType="VARCHAR" javaType ="java.lang.String"/> [color=red]<parameter property="memo" jdbcType="BLOB" javaType ="[]byte"/>[/color] </parameterMap>
假设memo在数据库中为BLOB 类型
那么在javaBean中memo的java类型为[]byte
六、 总结
采用10g的驱动,和通过配置parameterMap和resultMap能够轻松和完美的解决LOB大型数据的读写,无需要编写新的java来实现,也没有局限性。
发表评论
-
pushlet
2012-05-31 14:56 1133基于pushlet的文件监控系统的研究与实现 http ... -
@Transactional spring 配置事务
2012-04-25 11:15 2034@Transactional spring 配置事 ... -
Spring的组件自动扫描机制
2012-04-09 17:47 0Spring将所有的bean都纳入到IOC中创建、管理和维护。 ... -
struts&rest
2012-04-03 00:11 750深入浅出REST http://www.infoq. ... -
文件转码
2011-11-16 09:55 1916工程项目太多,各工程或各文件编码不统一时,可运行本工具类,把工 ... -
安装和使用SpringIDE-------III
2011-07-29 10:40 7882. 编写类文件 · ... -
安装和使用SpringIDE-------II
2011-07-29 10:39 655显示图表,如图: 发表于 @ 2006 ... -
安装和使用SpringIDE
2011-07-29 10:36 1096这篇文章谈谈如何安装与使用SpringIDE。作为辅助Sp ... -
使用AJDT简化AspectJ开发
2011-07-29 10:05 975面向方面编程(AOP)可用来解决当今的 许多 应用需求 ... -
利用Apache的CLI来处理命令行
2011-05-16 17:02 956CLI是Jakarta Commons中的一个子类。如果你仅仅 ... -
CGlib简单介绍
2011-04-28 08:37 776CGlib概述:cglib(Code Generation L ... -
Java ClassLoader
2011-04-25 18:24 968当Java编译器编译好.class ... -
Template模式与Strategy模式
2011-04-20 16:23 615template method模式和stra ... -
轻松构建和运行多线程的单元测试
2011-03-18 22:09 938背景 并行程序 并行程序是指控制计算机系统中两个或多个分别 ... -
Cairngorm3中文简介
2011-03-18 22:07 973官方原文地址:http://opensource.adobe. ... -
ibator改造之返回数据库注释和数据库分页
2010-12-23 17:24 2190转载:http://www.iteye.com ... -
quatrz 任务监控管理 (2)
2010-10-28 23:28 1411在《Quartz 任务监控管理 (1)》http://www. ... -
Quartz任务监控管理 (1)
2010-10-28 23:27 1229转载:http://sundoctor.iteye.com/b ... -
Quartz 在 Spring 中如何动态配置时间
2010-10-28 23:25 1629转载: http://sundoctor.iteye.com ... -
使用org.apache.commons.net.ftp包开发FTP客户端,实现进度汇报,实现断点续传,中文支持
2010-10-28 21:09 973使用org.apache.commons.net.ftp包开发 ...
相关推荐
ibatis 读取oracle clob类型
NULL 博文链接:https://bijian1013.iteye.com/blog/2233121
NULL 博文链接:https://huibin.iteye.com/blog/804070
NULL 博文链接:https://wilr.iteye.com/blog/1190524
ibatis 数据缓存,帮你了解ibatis的数据缓存机制。
实现ibatis对数据的连接,增查删改。.xml文件对sql语句的映射。基本知识基本全部覆盖
介绍Ibatis框架中需要同时连接多个资料库的方法,包括.net和Java两种
ibatis学习 ibatis总结 ibatis ibatis ibatis
Ibatis 数据层 轻型框架 Ibatis 数据层 轻型框架 Ibatis 数据层 轻型框架 Ibatis 数据层 轻型框架 Ibatis 数据层 轻型框架
ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料ibatis资料
ibatis 数据缓存,讨论了ibatis 数据缓存方面的概念,即用法,用到ibatis 数据缓存的可以参考一下
Ibatis和Spring整合例子,实现增删改查功能.
火龙果软件工程技术中心 本文内容包括:先决条件导入示例项目引入iBATIS实现StockService组件总结下载参考资料在完成SCAModule建模后用Java对象进行实现时,采用Hibernate和采用iBATIS实现SCAModule的数据持久层,...
ibatis自定义数据类型在不支持中文的数据库存储汉字
ibatis demo,ibatis例子,ibatis示例
iBATIS 级联iBATIS 级联iBATIS 级联
ibatis的原码 ibatis源码 ibatis源码 ibatis源码
Ibatis 数据表对象自动生成器 自动生成针对配置好的每个表的XML文件和VO(DTO)文件
ibatis