`
onho
  • 浏览: 16934 次
  • 来自: ...
社区版块
存档分类
最新评论

PreparedStatement中setString方法的异常

    博客分类:
  • java
阅读更多

转自

PreparedStatement中setString方法的异常


其实也不应该说是异常,应该是多种因素导致的使用问题。
一般在有了一定Java编程经验之后,大家都习惯用PreparedStatement代替Statement。
其好处就不用多说了。
但是却在开发中出现了问题。
如有表:
create table test(
 id int,
 name   varchar2(3000)
)
当执行插入语句到
stmt.setString(2, myString);
的时候,出现如下异常:
java.sql.SQLException: 数据大小超出此类型的最大值
而myString变量的内容为超过700的中文字符(测试的英文字符为2000个)。
也就是说一个中文字符占据了3-4个字节,而且英文字符个数也不对,这好像有点不可思议。
分析原因:
1、驱动程序在把SQL语句发给数据库前,PreparedStatement会对字符串进行预处理并进行转义替换;
2、字符集原因。
通过阅读PreparedStatement文档,发现有一个setCharacterStream方法可以解决这个问题:
stmt.setCharacterStream(2,new InputStreamReader(myString, myString.length());
替换之后中文字符可达1400多。


上次对PreparedStatement的setString中字符串长度这个问题没有解决透彻,
也没有深入分析其中的原因。
现在通过Oracle提供的JDBC文档来详细看看问题的来由。
我们都知道Oracle提供了两种客户端访问方式OCI和thin,
在这两种方式下,字符串转换的过程如下:
 
1、JDBC OCI driver:
在JDBC文档中是这么说的:

If the value of NLS_LANG is set to a character set other than US7ASCII or WE8ISO8859P1, then the driver uses UTF8 as the client character set. This happens automatically and does not require any user intervention. OCI then converts the data from the database character set to UTF8. The JDBC OCI driver then passes the UTF8 data to the JDBC Class Library where the UTF8 data is converted to UTF-16. ”
 
2、JDBC thin driver:
JDBC文档是这样的:
“If the database character set is neither ASCII (US7ASCII) nor ISO Latin1 (WE8ISO8859P1), then the JDBC thin driver must impose size restrictions for SQL CHAR bind parameters that are more restrictive than normal database size limitations. This is necessary to allow for data expansion during conversion.
The JDBC thin driver checks SQL CHAR bind sizes when a setXXX() method (except for the setCharacterStream() method) is called. If the data size exceeds the size restriction, then the driver returns a SQL exception (SQLException: Data size bigger than max size for this type) from the setXXX() call. This limitation is necessary to avoid the chance of data corruption when conversion of character data occurs and increases the length of the data. This limitation is enforced in the following situations:
(1)Using the JDBC thin driver
(2)Using binds (not defines)
(3)Using SQL CHAR datatypes
(4)Connecting to a database whose character set is neither ASCII (US7ASCII) nor ISO Latin1 (WE8ISO8859P1)
When the database character set is neither US7ASCII nor WE8ISO8859P1, the JDBC thin driver converts Java UTF-16 characters to UTF-8 encoding bytes for SQL CHAR binds. The UTF-8 encoding bytes are then transferred to the database, and the database converts the UTF-8 encoding bytes to the database character set encoding.”
 
原来是JDBC在转换过程中对字符串的长度做了限制。这个限制和数据库中字段的实际长度没有关系。
所以,setCharacterStream()方法可以逃过字符转换限制,也就成为了解决此问题的方案之一。
而JDBC对转换字符长度的限制是为了转换过程中的数据扩展。
根据实际测试结果,在ZHS16GBK字符集和thin驱动下,2000-4000长度的varchar字段都只能插入1333个字节(约666个汉字)。
 
To sum,解决PreparedStatement的setString中字符串长度问题可以有两种办法:
1、使用setCharacterStream()方法;
2、使用OCI驱动连接Oracle数据库。
分享到:
评论
1 楼 marc 2007-08-15  
我也遇到了这个问题,我用的是9i,这个问题一直没有解决,我用以下几个方法都试过了:
1、换最新的Oracle10g驱动,结果出现更加怪的问题,不管是汉字还是字符,在1000下和2000以上都是可以保存的,而1000-2000之间不能保存,估计是10g驱动和9i不兼容。
2、用OCI驱动,结果发现一个字段超过666个汉字没有关系,如果2个以上字段同时超过666个汉字时候就报错了。

相关推荐

    练习3:使用PreparedStatement插入宠物信息.zip

    3. **设置参数**:使用PreparedStatement的`setXXX()`方法(如`setString()`, `setInt()`等)设置每个占位符的值。这些方法的索引从1开始,对应于SQL语句中的问号位置。例如: ```java pstmt.setString(1, "Fluffy...

    PreparedStatement 详细用法

    2. **参数绑定**:通过`PreparedStatement`的`setXXX`方法(如`setInt`, `setString`等),可以将实际值绑定到SQL语句中的占位符上。 3. **批量更新**:`PreparedStatement`支持批量执行SQL更新语句,可以减少网络...

    如何创建和使用自定义异常

    - 可以通过在自定义异常类中添加成员变量和构造方法来实现。 - 示例:为`CustomerExistsException`添加一个成员变量`customerName`,用于记录发生异常的客户名称。 ```java public class ...

    Java使用PreparedStatement接口及ResultSet结果集的方法示例

    接着,我们创建`PreparedStatement`对象,并通过`setXXX`方法设置占位符对应的值。这些方法会根据数据类型自动转换Java对象为适合数据库存储的格式。最后,我们调用`executeUpdate()`方法执行SQL语句,如果受影响的...

    建议使用微软JDBC Driver连接SQL Database-Jeffery1

    注意,为了防止SQL注入和提高效率,建议使用预编译的`PreparedStatement`,并通过设置参数值来代替直接在SQL语句中插入动态数据。 总的来说,微软的JDBC Driver在连接Azure SQL Database时提供了更可靠、更高效的...

    SQL封装

    3. **参数绑定**:在方法中设置参数,使用PreparedStatement的set方法,如`preparedStatement.setString(1, username)`。 4. **执行SQL并处理结果**:调用`preparedStatement.executeQuery()`或`preparedStatement....

    利用jxl把excel中的数据导入数据库

    3. **设置参数**:对于每行数据,使用`PreparedStatement.setString(int index, String value)`或类似方法设置SQL参数。 4. **执行SQL**:调用`PreparedStatement.executeUpdate()`来执行插入操作。 5. **关闭资源**...

    Windchill中使用JDBC查询

    如果传入的参数数组不为空,它会遍历参数并使用setString方法设置查询中的占位符值。 5. ResultSet的处理 result是一个ResultSet对象,它代表了SQL查询返回的结果集。通过调用pstmt的executeQuery方法获得结果集,...

    增删改查方法和helper类

    在这个例子中,`getConnection()`方法用于获取数据库连接,`closeResources()`方法用于安全地关闭数据库资源,防止资源泄露。 通过使用`DBHelper`类,我们可以将具体的增删改查操作封装到单独的方法中,使得代码更...

    Java Web应用开发:优化dao层查询方法.docx

    在Java Web应用开发中,数据访问对象(Data Access Object, DAO)层是应用架构中的关键部分之一,它负责处理与数据库交互的所有操作。对于一个现有的Java Web项目而言,ProductDao类包含了多个查询方法,如`...

    利用JDBC工具类的方式实现mysql数据库的连接并且完成登录相关功能(防sql注入方式)

    在IT行业中,数据库操作是应用程序开发中的重要环节。在本示例中,我们将探讨如何使用JDBC(Java...在实际项目中,我们还需要考虑其他的最佳实践,如连接池管理,以优化数据库性能,以及异常处理,以确保程序的健壮性。

    jdbc操作oracle数据库(增删改查)

    对于删除、更新和查询操作,同样可以通过`PreparedStatement`设置SQL语句中的条件,然后执行相应的`executeUpdate()`或`executeQuery()`方法。查询结果可以通过`ResultSet`遍历处理。 总的来说,这个例子展示了使用...

    java解析xml并导入数据库(dom4j).doc

    在执行 SQL 语句时,我们使用了 `setString` 方法来设置参数值,例如 `pstmt.setString(1, numero)`。最后,我们使用 `addBatch` 方法将 SQL 语句添加到批量中,并使用 `executeBatch` 方法来执行批量操作。 四、...

    Java编程中中文乱码问题的研究及解决方案

    解决方法是在JSP页面中使用`;charset=UTF-8" %>`指令设定页面编码为UTF-8,或者在Servlet中使用`response.setContentType("text/html;charset=UTF-8")`设置响应的MIME类型和字符集。同时,HTML文件头部添加`...

    运用Java如何存取Oracle中的CLOB类型字段

    在示例代码中,可以看到使用`empty_clob()`函数来创建一个空的CLOB对象,并通过`CLOB.setString()`方法向CLOB中写入数据。此外,还可以通过`PreparedStatement`的`setClob()`方法直接将CLOB对象作为参数传递,以简化...

    java批量插入Oracle数据方法

    在循环中,我们从列表中取出每个`Trafficinfotab`对象,设置`PreparedStatement`中的所有参数,然后调用`addBatch()`方法将当前的插入语句添加到批处理队列中。这一步骤是批量插入的关键,它累积了多个插入语句。 #...

    Java调用存储过程的2种方法

    使用`setString`方法为存储过程的输入参数赋值,参数索引对应于SQL语句中的位置。 5. **注册输出参数**: ```java proc.registerOutParameter(2, Types.VARCHAR); ``` 使用`registerOutParameter`方法来指定...

    jsp+jdbc实现的一个增删改查的操作

    调用`preparedStatement.setString(index, value)`设置参数,然后执行`preparedStatement.executeUpdate()`或`preparedStatement.executeQuery()`。 4. **结果处理**:如果执行的是查询操作,你需要遍历`ResultSet`...

    JDBC增删改查封装方法

    使用PreparedStatement的`executeUpdate()`方法执行插入操作。上述代码将“John Doe”和“john.doe@example.com”插入到users表中。 四、读取数据 读取数据通常使用ResultSet。执行查询后,结果会返回一个...

Global site tag (gtag.js) - Google Analytics