@Lob μ¬μ©μ DBμ μν°ν° νλ νμ μ΄ λ€λ₯Έ κ²½μ° λ°μνλ λ¬Έμ μ ν΄κ²°λ°©λ²
π« λ°°κ²½
μ§ν μ€μΈ νλ‘μ νΈμ κ³Όκ±° μ½λ μ€ HTML λ¬Έμλ₯Ό κ·Έλλ‘ DBμ μ μ₯νλ λ΄μ©μ΄ μμλ€. HTML λ¬Έμ λ΄μ©μ λμ μ΄κ³ , κΈΈμ΄κ° κΈΈμκΈ° λλ¬Έμ κΈ΄ λ¬Έμμ΄ μ μ₯μ μν΄ LOBμ μ¬μ©νκ³ , λ³λ€λ₯Έ λ¬Έμ μμ΄ μλΉμ€λ₯Ό μ΄μ©ν΄ μμλ€. κ·Έλ¬λ€ μ΄λ μκ° μλΉμ€λ₯Ό μ΄μ©ν μ μλ λ¬Έμ κ° λ°μνλ€. μ΄μ κ΄λ ¨ν΄μ νμ ν μμΈκ³Ό ν΄κ²° λ°©λ²μ λν΄μ 곡μ νκ³ μ νλ€.
π μμΈ
λ¬Έμ λ΄μ©μ λΆμν΄ λ³΄λ, 'DBμ μ μΈλ LOB νμ 'κ³Ό 'μν°ν°μ μ¬μ©λ @LOB νμ 'μ΄ λ€λ₯΄κ² μ¬μ©λμκΈ° λλ¬Έμ λ°μν λ¬Έμ μλ€.
μλΉμ€ DBμμλ BLOB νμ μ μ μ©μμΌ°λλ°, λ§μ μν°ν° νλμμλ String νμ μΌλ‘ μ μΈνκΈ° λλ¬Έμ CLOB κ΄λ ¨ λ‘μ§μ΄ μ μ©λλ©΄μ λ°μ΄ν°λ² μ΄μ€μμ κ°μ Έμ¨ λ°μ΄ν°λ₯Ό μ²λ¦¬ν μ μκ² λμ΄ λ¬Έμ κ° λ°μν κ²μ΄λ€.
@Lob μ¬μ© μ μ€νλ§μ νλ νμ μ λ°λΌ μλμΌλ‘ κ΄λ ¨ jdbc κ°μ²΄λ‘ μ°κ²°ν΄ μ£Όλλ°, μ»΄νμΌ λ¨κ³μμλ μ΄λ₯Ό νμΈν μ μμΌλ―λ‘ ν΄λΉ λ¬Έμ λ₯Ό νμ ν μ μμλ€.
λ°μν λ¬Έμ
1. Invalid UTF8
CLOBμ κΈ°λ³Έμ μΌλ‘ UTF8 μΈμ½λ©μ κ°μ νλ€. κ·Έλ¬λ―λ‘ λ°μ΄ν°λ₯Ό κ°μ Έμ¬ λ κΈΈμ΄λ₯Ό κ³μ°νλ κ³Όμ μμ UTF-8μ μ μ©ν΄μ κΈΈμ΄λ₯Ό κ³μ°νλ€.
MariaDbClob.java
public long length() {
// The length of a character string is the number of UTF-16 units (not the number of characters)
long len = 0;
int pos = offset;
// set ASCII (<= 127 chars)
while (len < length && data[pos] > 0) {
len++;
pos++;
}
// multi-bytes UTF-8
while (pos < offset + length) {
byte firstByte = data[pos++];
if (firstByte < 0) {
if (firstByte >> 5 != -2 || (firstByte & 30) == 0) {
if (firstByte >> 4 == -2) {
if (pos + 1 < offset + length) {
pos += 2;
len++;
} else {
throw new UncheckedIOException("invalid UTF8", new CharacterCodingException());
}
} else if (firstByte >> 3 != -2) {
throw new UncheckedIOException("invalid UTF8", new CharacterCodingException());
} else if (pos + 2 < offset + length) {
pos += 3;
len += 2;
} else {
// bad truncated UTF8
pos += offset + length;
len += 1;
}
} else {
pos++;
len++;
}
} else {
len++;
}
}
return len;
}
ν΄λΉ λΆλΆμμ BLOB νμ λ°μ΄ν°λ₯Ό κΈΈμ΄λ₯Ό κ³μ°νλ κ³Όμ μ€ λ¬Έμ κ° λ°μνμ¬ "invalid UTF8" λ©μμ§μ ν¨κ» UncheckedIOException μμΈκ° λ°μνκ² λλ€.
MariaDbBlob.java νμΌμ length() λ©μλλ λ°μ΄ν° κΈΈμ΄ κ·Έλλ‘λ₯Ό λ°ννλ€.
public long length() {
return length;
}
2. Data type BLOB cannot be decoded as Clob
ν΄λΉ λ¬Έμ λ 1λ² λ¬Έμ λ₯Ό μ¬μ°νλ €κ³ νμ λ μ‘°ν κ³Όμ ν μ€νΈμμ λ°μν μμΈμ΄λ€.
(μ€νλ§ λΆνΈ λ²μ μ΄ μ κ·Έλ μ΄λλλ©΄μ length μ΄μ μ νν°λ§λλ κ²μΌλ‘ μΆμΈ‘λλ€.)
ClobCodec.java
@SuppressWarnings("fallthrough")
private Clob getClob(ReadableByteBuf buf, int length, Column column) throws SQLDataException {
switch (column.getType()) {
case BLOB:
case TINYBLOB:
case MEDIUMBLOB:
case LONGBLOB:
if (column.isBinary()) {
buf.skip(length);
throw new SQLDataException(
String.format("Data type %s cannot be decoded as Clob", column.getType()));
}
// expected fallthrough
// BLOB is considered as String if it has a collation (this is TEXT column)
case STRING:
case VARCHAR:
case VARSTRING:
Clob clob = new MariaDbClob(buf.buf(), buf.pos(), length);
buf.skip(length);
return clob;
default:
buf.skip(length);
throw new SQLDataException(
String.format("Data type %s cannot be decoded as Clob", column.getType()));
}
}
column νμ μ νμΈν΄μ, Blob νμ μΈ κ²½μ° SQLDataException μμΈκ° λ°μνλ€.
μ‘°ν κ³Όμ μμ λ°μνλ λ¬Έμ μ΄λ―λ‘, λ°μ΄ν°λ₯Ό μ μ₯νκΈ°λ§ νλ€λ©΄ λ¬Έμ κ° λ°μνμ§ μλλ€.
ν΄κ²°λ°©λ²
HTML λ¬Έμλ₯Ό κ·Έλλ‘ μ μ₯νλ€ λ³΄λ λ°μ΄ν°κ° BLOBλ³΄λ€ CLOB νμ μ μ΄μΈλ¦°λ€κ³ μκ°ν΄μ DB λ°μ΄ν° μ νμ CLOB νμ μΌλ‘ μμ νλ €κ³ νλ€. νμ§λ§ λ³κ²½ κ³Όμ μμ UTF8 λ¬Έμ κ° λ°μνλ©° μμ μ μ€ν¨νλ€.
(μ΄λ―Έ DB λ΄μ λ§μ λ°μ΄ν°κ° μμ¬ μμκ³ , μ μ₯λ λ°μ΄ν° μ€ UTF8λ‘ μΈμν μ μλ λ°μ΄ν°κ° μ‘΄μ¬νμμ)
@Lob μ΄λ Έν μ΄μ μ μ κ±°νλ©΄ Lob μ²λ¦¬ κ³Όμ μ μλ΅νκΈ° λλ¬Έμ ν΄λΉ λ°©λ²μ μ νν΄μ λ¬Έμ λ₯Ό ν΄κ²°νλ€.
κ²°λ‘
@Lobμ μ¬μ©νκΈ° μ μ μ μ₯λ λ°μ΄ν° μ νμ΄ BLOB, CLOB μ€ μ΄λ€ νμ μ΄ λ§μμ§ μ κ³ λ―Όν΄μ μ ν΄μΌ νκ³ , λ°μ΄ν°λ² μ΄μ€ νμ κ³Ό νλ νμ μ λ°λμ λ§μΆ°μΌ νλ€.