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数据库。
来源:http://onho.iteye.com/blog/85389
分享到:
相关推荐
此实例意在解决预处理命令PreparedStatement的setString()方法,在sql2008数据库中写入数据时,会自动补足空格的问题, 同时此实例也解决了当存在自动补足空格的问题时,使用nvarchar可以使查找出来的数据与原输入...
preparedStatement.setString (1, username); ResultSet resultSet = preparedStatement.executeQuery (); if(!resultSet.next()) occupied=false; preparedStatement.close (); ConnDB.terminate(); } ...
在实际应用中,如果需要获取动态构建的SQL,可能需要自定义一个`PreparedStatement`的代理类,覆盖`execute`或`executeQuery`方法,然后在这个代理类中拼接和打印出最终的SQL。但这需要对JDBC有深入的理解,并且需要...
3. **设置参数**:使用PreparedStatement的`setXXX()`方法(如`setString()`, `setInt()`等)设置每个占位符的值。这些方法的索引从1开始,对应于SQL语句中的问号位置。例如: ```java pstmt.setString(1, "Fluffy...
例如,当我们尝试使用`java.util.Date`对象将日期传递给`PreparedStatement`的`setDate()`方法时,程序可能会抛出异常。这是因为`setDate()`方法期望的是`java.sql.Date`类型的参数。 #### 解决方案 针对这个问题...
2. **参数绑定**:通过`PreparedStatement`的`setXXX`方法(如`setInt`, `setString`等),可以将实际值绑定到SQL语句中的占位符上。 3. **批量更新**:`PreparedStatement`支持批量执行SQL更新语句,可以减少网络...
我们知道进行编码和转码工作都是集中在JDBC的两个接口PreparedStatement和ResultSet上进行的,主要涉及PreparedStatement的setString方法以及ResultSet的getString方法。前面我们讲过需要加入一个连接封装层来对...
当我们在应用程序中需要向数据库中插入日期(`Date`类型)时,就需要用到`PreparedStatement`中的`setDate()`或`setTimestamp()`方法。本文将详细介绍这两种方法的使用方式及注意事项。 #### 一、`...
在这个例子中,首先定义了一个包含占位符的SQL语句,接着通过`connection`对象的`prepareStatement`方法创建`PreparedStatement`实例,然后通过`setInt`和`setString`方法设置参数值,最后调用`executeQuery`方法...
Java 中 PreparedStatement 和 Statement 的区别 Java 中的 PreparedStatement 和 Statement 都是用于执行 SQL 语句的接口,但是它们之间存在一些关键的区别。 首先,从数据库执行 SQL 语句的角度来看,使用 ...
在这个例子中,`setShort`方法将Java类型`short`的值`44`设置为`PreparedStatement`对象的第二个参数。驱动程序会将这个值作为JDBC类型`SMALLINT`发送给数据库。 #### 七、总结 通过以上介绍可以看出,`...
JDBC 中的 PreparedStatement 接口提供了三种执行 SQL 语句的方法:executeQuery、executeUpdate 和 execute。这些方法的使用取决于 SQL 语句所产生的内容。 _executeQuery 方法_ executeQuery 方法用于产生单个...
本文将详细介绍`Connection`和`PreparedStatement`的使用时机与关闭策略,帮助开发者更好地理解和掌握这两者的使用方法。 #### Connection(连接) - **定义**:`Connection`接口是Java中所有数据库操作的基础。它...
jdbc2.0版 PreparedStatement接口的用法
//SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。 private ResultSet resultSet;//结果集 public boolean addSupplier(SupplierData s)//添加供应商 { ...
在Java编程中,数据库操作是常见任务之一,而`PreparedStatement`和`Statement`是Java JDBC(Java Database Connectivity)中用于执行SQL语句的两种主要接口。它们都是`java.sql`包下的类,用来与数据库进行交互,但...
Statement和PreparedStatement是JDBC中的两种不同的语句对象,用于执行数据库操作。虽然它们都可以执行SQL语句,但是它们之间存在着很大的区别。 首先, Statement对象执行的SQL语句是直接编译的,而...
preparedStatement.setString(2, password); // 执行查询 ResultSet rs = preparedStatement.executeQuery(); // 处理结果集 if (rs.next()) { return true; } ``` #### 连接与查询数据库 通过上述示例可以看出...
preparedStatement.setString(2, hashedPassword); preparedStatement.executeUpdate(); ``` 这里假设我们有一个名为`users`的表,包含`username`和`password`字段,且密码通常会进行哈希处理存储。 **三、登录验证...
- 可以通过在自定义异常类中添加成员变量和构造方法来实现。 - 示例:为`CustomerExistsException`添加一个成员变量`customerName`,用于记录发生异常的客户名称。 ```java public class ...