Chinaunix首页 | 论坛 | 博客
  • 博客访问: 85391
  • 博文数量: 3
  • 博客积分: 1425
  • 博客等级: 上尉
  • 技术积分: 210
  • 用 户 组: 普通用户
  • 注册时间: 2005-02-02 00:01
文章分类

全部博文(3)

文章存档

2010年(1)

2009年(1)

2008年(1)

我的朋友

分类: Java

2009-09-01 14:13:44

    最近上线了一个业务管理系统,客户在使用时反映保存不了大量的意见信息,在我们调研时了解到意见一般是写1000字左右,大小不超2000个汉字,所以在数据库设计时,没有使用CLOB数据类型,而是用了varchar2(4000),理论上应该能存2000个汉字的,但是现在系统日志显示插入的值过大。
   
    我们经过几次测试,发现无论字段设多大,666个汉字就是上限了,但是如果是直接往数据库写的话,最大是能写入2000汉字的,没办法,在google了一遍后,才知道其实这是个很常见的问题,“一般直接用PreparedStatement的setString()设置字符串数据时,Oracle的JDBC驱动会将中文转换为2字节或3字节,不固定的,因此经常会越界。”,最好是使用setCharacterStream()方法。
 
    找到了原因,解决问题的办法也知道了,剩下就是怎么在项目中处理了。我们的平台是使用的OJB作为持久层的,已经很老了,因为没有出现过问题,所以也一直没有更换。刚开始时,我们采用了从OJB获得Connection的方式,自己执行保存和更新操作能解决大量汉字保存问题,但是解决问题的方式不能是发现一个才解决一个,那样的话没有哪个客户能满意。我们统计了下,这个系统大概会改几十个地方,是个不小的工作量,而且在这个系统发现了这样的问题,在别的系统中也应该在开发或运维时处理掉,一个个的改不是好办法。
 
    现在只能从使用的OJB组件上下功夫了,OJB其实是个很不错的持久层组件,因为宣传和文档的缺乏才造成现在的没落,不过还好,开源组件的一大好处就是源码开放,我从同事那里找了份我们使用的版本的源码,一步步的从PersistenceBroker开始,查找处理更新和插入的操作,终于在StatementManager.java找到了入口,setObjectForStatement(PreparedStatement stmt, int index, Object value, int sqlType),用来处理为PreparedStatement赋值的问题,继续跟踪发现,在PlatformFactory.getPlatformFor()方法中是根据repository_database.xml中platform的值,来判断使用哪个数据库的Platform的实现类来处理。
 
    然后,我添加了一个org.apache.ojb.broker.platforms.PlatformOracle9iSelfImpl类,继承PlatformOracle9iImpl类,覆盖了setObjectForStatement方法,内容如下:
 public void setObjectForStatement(PreparedStatement ps, int index,
    Object value, int sqlType) throws SQLException {
   if ((sqlType == Types.CHAR || sqlType == Types.VARCHAR)
     && (value instanceof String || value instanceof Character)) {
      String tempValue=value instanceof String?(String) value:value.toString();
      ps.setCharacterStream(index, new StringReader(tempValue),tempValue.length());
   } else {
      super.setObjectForStatement(ps, index, value, sqlType);
   }
 }
 
在使用的时候,只要将该类放在项目的classpath中,修改repository_database.xml中platform的值置为“Oracle9iSelf”即可。
 
阅读(1162) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~