- 论坛徽章:
- 0
|
最近上线了一个业务管理系统,客户在使用时反映保存不了大量的意见信息,在我们调研时了解到意见一般是写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”即可。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/3961/showart_2043002.html |
|