我们在 Oracle 数据库中使用 VARCHAR2(4000 CHAR) 列来存储 JSON 数据,而不会通过使用 CLOB 过多影响性能。我了解到 4000 CHAR 在技术上限制为 4000 BYTE,这是所有这些字符串列的最大长度。即使 NVARCHAR2 也仅限于这 4000 BYTE。
这就是为什么我们尝试将代码 Java 端的字符串拆分为 4000 字节的块。为了确定数据库中字符串的实际长度,我们使用
String#getBytes(StandardCharsets.UTF_8).length
。这似乎工作不可靠。尽管如此,Oracle 有时会抛出以下错误:
ORA-12899: Wert zu groß für Spalte “OUR_DATABASE”。“HISTORICAL_DATASETS”。“JSON1”(当前值:4006, 最大:4000)
Oracle 使用的编码是 ALS32UTF8 – 根据
SELECT parameter, value FROM nls_database_parameters WHERE parameter LIKE 'NLS_CHARACTERSET'
。
我错过了什么?尽管编码本身有任何额外的开销吗?
在 Java 中,您有一个用于字符串的 length 方法,它将产生字符串中的字符数。这样您就可以知道您的字符串有多少个字符。
您还需要知道字符使用了多少字节。因此,为此,您可以使用 getBytes 方法来获取
byte[]
的 String
表示形式。因此,你可以这样做:
String[] mySplit(String s) {
//Defaulting the limit to 4000
return mySplit(s, 4000);
}
String[] mySplit(String s, int limit) {
//number of characters
int strLength = s.length();
//bytes of the string
byte[] bytes = s.getBytes();
//size of a character
int unitSize = bytes.length / strLength;
//size of packets
int charLimit = s.length() / (limit / unitSize);
//creating a String array for the packets
String[] results = new String[Math.ceil((float)s.length() / charLimit)];
//looping the packets to compute and store them
for (int packet = 0; packet < results.length; packet++) {
//If it's not the last packet, then we get a chunk up to the appropriate limit
if (packet < packet.results - 1) {
results[packet] = s.substring(packet * charLimit, charLimit);
//otherwise we are at the last chunk and we read to the end
} else {
results[packet] = s.substring(packet * charLimit);
}
}
return results;
}
(未经测试)。通过这种方式,您始终可以找出数据包有多大,并将字符串拆分为所述大小的数据包,然后对数据包执行任何您想要的操作,在本例中,将它们存储在数据库中。但我强烈建议您在没有这种切片和粘合的情况下测量应用程序的性能,并比较结果,只是为了仔细检查您的假设。