Статьи

Давайте рассмотрим, как вставить Clob или Blob через JDBC

LOBs являются PITA во всех базах данных, а также в JDBC. Правильная обработка занимает несколько строк кода, и вы можете быть уверены, что в конце концов ошибетесь. Потому что вы должны подумать о нескольких вещах:

Итак, если вы работаете на низком уровне с использованием JDBC (вместо абстрагирования JDBC через  Hibernate  или  jOOQ ), вам лучше написать небольшую утилиту, которая позаботится о правильной обработке больших объектов .

Недавно мы заново открыли нашу собственную утилиту, которую мы используем для тестирования интеграции jOOQ, по крайней мере, в некоторых базах данных, и подумали, что это может быть очень полезно для пары наших читателей, которые работают непосредственно с JDBC. Рассмотрим следующий класс:

public class LOB implements AutoCloseable {

    private final Connection connection;
    private final List<Blob> blobs;
    private final List<Clob> clobs;

    public LOB(Connection connection) {
        this.connection = connection;
        this.blobs = new ArrayList<>();
        this.clobs = new ArrayList<>();
    }

    public final Blob blob(byte[] bytes) 
    throws SQLException {
        Blob blob;

        // You may write more robust dialect 
        // detection here
        if (connection.getMetaData()
                      .getDatabaseProductName()
                      .toLowerCase()
                      .contains("oracle")) {
            blob = BLOB.createTemporary(connection, 
                       false, BLOB.DURATION_SESSION);
        }
        else {
            blob = connection.createBlob();
        }

        blob.setBytes(1, bytes);
        blobs.add(blob);
        return blob;
    }

    public final Clob clob(String string) 
    throws SQLException {
        Clob clob;

        if (connection.getMetaData()
                      .getDatabaseProductName()
                      .toLowerCase()
                      .contains("oracle")) {
            clob = CLOB.createTemporary(connection, 
                       false, CLOB.DURATION_SESSION);
        }
        else {
            clob = connection.createClob();
        }

        clob.setString(1, string);
        clobs.add(clob);
        return clob;
    }


    @Override
    public final void close() throws Exception {
        blobs.forEach(JDBCUtils::safeFree);
        clobs.forEach(JDBCUtils::safeFree);
    }
}

Этот простой класс имеет несколько приятных лакомств:

  • Это  AutoCloseableзначит, что вы можете освободить свои лобы с помощью оператора try-with-resources
  • Он абстрагируется от создания больших объектов на диалектах SQL. Не нужно помнить путь Oracle

Чтобы использовать этот класс, просто напишите что-то вроде следующего:

try (
    LOB lob = new LOB(connection);
    PreparedStatement stmt = connection.prepareStatement(
        "insert into lobs (id, lob) values (?, ?)")
) {
    stmt.setInt(1, 1);
    stmt.setClob(2, lob.clob("abc"));
    stmt.executeUpdate();
}

Это оно! Нет необходимости хранить ссылки на lob, безопасно освобождать его, если он не равен null, корректно восстанавливаться после исключений и т. Д. Просто поместите  LOB контейнер в оператор try-with-resources вместе с  PreparedStatement и done.

Если вас интересует,  почему вы должны позвонить  Clob.free() или,  Blob.free() в первую очередь, прочитайте нашу статью об этом . Это избавит вас от одного или двухOutOfMemoryErrors