在存储的CLOB中包括自动增量值

时间:2018-10-12 23:49:58

标签: java sql jdbc h2

我将json对象作为clob存储在表中,该表具有自动增量ID字段。我想在存储时在Clob中包含自动增量ID。有没有办法做到这一点,插入后再不更新记录。 (我在h2引擎上使用了jdbc)

2 个答案:

答案 0 :(得分:1)

基本上有两种解决方案:

  1. 使用序列并检索值,使用ID生成Clob内容,然后使用id和Clob插入
  2. 使用触发器来修改衣服

我已经写了两个小例子来说明如何做到这一点。

我个人认为,在大多数情况下,使用第一个触发器更为可取,使用触发器的解决方案可能非常脆弱且难以正确执行。如果Clob内容是-例如-从对象模型生成的XML或JSON,在我的示例中放置##ID##之类的占位符并不总是可行或很难做到的(例如,如果字段是输入整数)。

1。使用序列

public class WithSequence {

    private static final String URL = "jdbc:h2:mem:seqdb";

    public static void main(String[] args) throws SQLException {
        try (Connection connection = DriverManager.getConnection(URL)) {
            initDb(connection);
            int id = getNextId(connection);
            insertClobWithId(id, connection);
            outputTableContent(connection);
        }
    }

    // creates table and sequence
    private static void initDb(Connection connection) throws SQLException {
        try (Statement ddlStmt = connection.createStatement()) {
            ddlStmt.execute("create table clobwithid ("
                    + " id integer primary key,"
                    + " clobvalue clob"
                    + ")");
            ddlStmt.execute("create sequence seq_clobwithid");
        }
    }

    // obtain next id from sequence
    private static int getNextId(Connection connection) throws SQLException {
        try (Statement stmt = connection.createStatement();
             ResultSet rs = stmt.executeQuery("select next value for seq_clobwithid")) {
            if (rs.next()) {
                return rs.getInt(1);
            } else {
                throw new AssertionError(" next value for should produce value");
            }
        }
    }

    // generate and insert clob
    private static void insertClobWithId(int id, Connection connection) throws SQLException {
        String clobValue = "Something with id=" + id + " and other stuff";
        try (PreparedStatement pstmt = connection.prepareStatement(
                "insert into clobwithid(id, clobvalue) values(?, ?)")) {
            pstmt.setInt(1, id);
            pstmt.setString(2, clobValue);

            pstmt.executeUpdate();
        }
    }

    private static void outputTableContent(Connection connection) throws SQLException {
        try (Statement stmt = connection.createStatement();
             ResultSet rs = stmt.executeQuery("select id, clobvalue from clobwithid")) {
            while (rs.next()) {
                System.out.printf("%d : %s%n", rs.getInt(1), rs.getString(2));
            }
        }
    }
}

2。使用触发器

public class WithTrigger {

    private static final String URL = "jdbc:h2:mem:seqdb";

    public static void main(String[] args) throws SQLException {
        try (Connection connection = DriverManager.getConnection(URL)) {
            initDb(connection);
            insertClob(connection);
            outputTableContent(connection);
        }
    }

    // create database and trigger
    private static void initDb(Connection connection) throws SQLException {
        try (Statement ddlStmt = connection.createStatement()) {
            ddlStmt.execute("create table clobwithid ("
                    + " id integer auto_increment primary key,"
                    + " clobvalue clob"
                    + ")");
            ddlStmt.execute("create trigger bi_clobwithid before insert on clobwithid for each row call \"example.ClobUpdateTrigger\"");
        }
    }

    // insert clob with a placeholder to be modified by the trigger
    private static void insertClob(Connection connection) throws SQLException {
        String clobValue = "Something with id=##ID## and other stuff";
        try (PreparedStatement pstmt = connection.prepareStatement(
                "insert into clobwithid(clobvalue) values(?)")) {
            pstmt.setString(1, clobValue);

            pstmt.executeUpdate();
        }
    }

    private static void outputTableContent(Connection connection) throws SQLException {
        try (Statement stmt = connection.createStatement();
             ResultSet rs = stmt.executeQuery("select id, clobvalue from clobwithid")) {
            while (rs.next()) {
                System.out.printf("%d : %s%n", rs.getInt(1), rs.getString(2));
            }
        }
    }
}

触发器类别为:

public class ClobUpdateTrigger extends TriggerAdapter {

    @Override
    public void fire(Connection connection, ResultSet oldRs, ResultSet newRs) throws SQLException {
        int generatedId = newRs.getInt(1);
        // We need to use reader to avoid internal casting problems
        String insertedClobValue = toString(newRs.getCharacterStream("clobvalue"));
        String updatedClobValue = insertedClobValue != null
                ? insertedClobValue.replace("##ID##", String.valueOf(generatedId))
                : null;
        newRs.updateString("clobvalue", updatedClobValue);
    }

    private static String toString(Reader reader) throws SQLException {
        try {
            StringWriter sw = new StringWriter();
            char[] buffer = new char[1024];
            int read;
            while ((read = reader.read(buffer)) != -1) {
                sw.write(buffer, 0, read);
            }
            return sw.toString();
        } catch (IOException e) {
            throw new SQLException(e);
        }
    }
}

答案 1 :(得分:0)

这是一个解决方案:

(1)使用序列:

CREATE TABLE test1 (my_id INT PRIMARY KEY, my_id_2 INT);
CREATE SEQUENCE my_seq;

INSERT INTO test1 VALUES (my_seq.nextval, my_seq.currval)
SELECT * FROM test1;

输出:

MY_ID   MY_ID_2 
1       1

请注意,这两列具有相同的生成值。


(1a)序列的替代应用:

使用以下脚本使用语句运行SQL:“为my_seq调用下一个值”以获取下一个序列值。

ResultSet rs = statement.executeQuery("call next value for my_seq");
rs.next();
long value = rs.getLong(1); // NOTE: the return value is a long

使用此序列值插入目标表的多个列中。