Ada*_*dam 4 java oracle hibernate oracle11g
我用这样的表设置我的数据库:
CREATE TABLE t_audit_log
(
description VARCHAR2 (2500)
);
Run Code Online (Sandbox Code Playgroud)
在使用它的Java应用程序中,我使用Hibernate将数据类映射到它,并确保我不会生成SQLExceptions,我将此截断算法放在属性getter中:
private static final int MAX_STRING_LEN_2500 = 2499;
public void setDescription(final String newDescription) {
if (newDescription != null
&& newDescription.length() > MAX_STRING_LEN_2500) {
description = newDescription.substring(0, MAX_STRING_LEN_2500);
} else {
description = newDescription;
}
}
Run Code Online (Sandbox Code Playgroud)
对于成千上万的审计日志条目,这个工作正常 - 直到今天.我在日志中发现了这个:
Nov 09, 2015 7:54:40 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 12899, SQLState: 72000
Nov 09, 2015 7:54:40 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: ORA-12899: value too large for column "BLABLA"."T_AUDIT_LOG"."DESCRIPTION"
(actual: 2501, maximum: 2500)
Run Code Online (Sandbox Code Playgroud)
为什么substring()在值中留下了额外的字符?
我怀疑你的数据库设置被设置为使用"字节语义"进行长度操作(这是默认设置NLS_LENGTH_SEMANTICS),在这种情况下,你说你希望字段在编码时长度最多为2500字节,而不是2500字符.假设您的数据库使用UTF-8对字符串进行编码 - 如果您的字符串包含2498个ASCII字符和1个字符U + 20A0(欧元符号),那么这将导致总共2501个字节,但只有2499个字符.
Java length()和substring()操作将以UTF-16代码单元的形式运行 - 这可能与"字符语义" 完全一致.(你不太可能尝试在Basic Multilingual Plane之外存储字符,这是单个字符需要两个UTF-16代码单元的地方,但它是可能的.)
你真的需要弄清楚你想要实际表示的字段长度- 然后你可以弄清楚是否要改变你在Java中执行截断的方式.
修改Oracle NLS_LENGTH_SEMANTICS,如果您使用的是BYTE或CHAR,则不指定,默认为BYTE.有些字符可能需要mor而不是一个字节存储到数据库中,因此请尝试将表修改为
CREATE TABLE t_audit_log
(
description VARCHAR2 (2500 char)
);
Run Code Online (Sandbox Code Playgroud)
然后再试一次.
来自Oracle文档:
NLS_LENGTH_SEMANTICS的会话级值指定用于VARCHAR2和CHAR表列的默认长度语义,用户定义的对象属性以及在会话中创建的数据库对象中的PL/SQL变量.可以通过列,属性和变量定义中的显式长度语义限定符BYTE和CHAR来覆盖此缺省值.
| 归档时间: |
|
| 查看次数: |
893 次 |
| 最近记录: |