Oracle JDBC charset和4000 char限制

我们正在尝试将UTF-16编码的字符串存储到AL32UTF8 Oracle数据库中。

我们的程序完全适用于使用WE8MSWIN1252作为字符集的数据库。 当我们尝试在使用AL32UTF8的数据库上运行它时,它会转到java.sql.SQLException: ORA-01461: can bind a LONG value only for insert into a LONG column

在下面的测试用例中,只要我们的输入数据不会太长,一切正常。

输入字符串可以超过4000个字符。 我们希望保留尽可能多的信息,即使我们意识到必须切断输入。

我们的数据库表使用CHAR关键字定义(见下文)。 我们希望这可以让我们存储多达4000个字符集。 可以这样做吗? 如果是这样,怎么样?

我们尝试使用ByteBuffer将String转换为UTF8但没有成功。 OraclePreparedStatement.setFormOfUse(...)也没有帮助我们。

切换到CLOB不是一种选择。 如果字符串太长则需要剪切。

这是我们目前的代码:

 public static void main(String[] args) throws Exception { String ip ="193.53.40.229"; int port = 1521; String sid = "ora11"; String username = "obasi"; String password = "********"; String driver = "oracle.jdbc.driver.OracleDriver"; String url = "jdbc:oracle:thin:@" + ip + ":" + port + ":" + sid; Class.forName(driver); String shortData = ""; String longData = ""; String data; for (int i = 0; i < 5; i++) shortData += "é"; for (int i = 0; i < 4000; i++) longData += "é"; Connection conn = DriverManager.getConnection(url, username, password); PreparedStatement stat = null; try { stat = conn.prepareStatement("insert into test_table_short values (?)"); data = shortData.substring(0, Math.min(5, shortData.length())); stat.setString(1, data); stat.execute(); stat = conn.prepareStatement("insert into test_table_long values (?)"); data = longData.substring(0, Math.min(4000, longData.length())); stat.setString(1, data); stat.execute(); } finally { try { stat.close(); } catch (Exception ex){} } } 

这是简单表的创建脚本:

 CREATE TABLE test_table_short ( DATA VARCHAR2(5 CHAR); ); CREATE TABLE test_table_long ( DATA VARCHAR2(4000 CHAR); ); 

测试用例在短数据上完美运行。 然而,在长数据上它不断得到错误。 即使我们的longData只有3000个字符长,它仍然无法成功执行。

提前致谢!

在Oracle 12.1之前, VARCHAR2列仅限于在数据库字符集中存储4000字节的数据,即使它被声明为VARCHAR2(4000 CHAR) 。 由于字符串中的每个字符都需要UTF-8字符集中的2个字节的存储空间,因此您无法在列中存储超过2000个字符。 当然,如果你的一些字符实际上只需要1个字节的存储空间,或者其中一些字符需要超过2个字节的存储空间,那么这个数字就会改变。 当数据库字符集是Windows-1252时,字符串中的每个字符只需要一个字节的存储空间,因此您可以在列中存储4000个字符。

由于你有更长的字符串,是否可以将列声明为CLOB而不是VARCHAR2 ? 这将(有效地)消除长度限制(对CLOB的大小有限制,这取决于Oracle版本和块大小,但它至少在多GB范围内)。

如果您恰好使用的是Oracle 12.1或更高版本,则max_string_size参数允许您将VARCHAR2列的最大大小从4000字节增加到32767字节 。

通过将String剪切为require字节长度解决了这个问题。 请注意,这不能通过简单地使用来完成

 stat.substring(0, length) 

因为这会生成一个UTF-8字符串,其长度可能比允许的长三倍。

 while (stat.getBytes("UTF8").length > length) { stat = stat.substring(0, stat.length()-1); } 

注意不要使用stat.getBytes(),因为这取决于set’file.encoding’并产生Windows-1252或UTF-8字节!

如果您使用Hibernate,您可以使用org.hibernate.Interceptor执行此操作!