我们正在尝试将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个字符集。 可以这样做吗?如果是这样,怎么做?
我们尝试使用UTF8
将字符串转换为ByteBuffer
但未成功。 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个字符,它仍然无法成功执行。
提前致谢!
答案 0 :(得分:9)
在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
参数允许您increase the maximum size of a VARCHAR2
column from 4000 bytes to 32767 bytes。
答案 1 :(得分:4)
通过将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!
执行此操作