Database 为内存中数据库生成事务id

Database 为内存中数据库生成事务id,database,h2,Database,H2,在撰写本文时,不支持内存中的数据库。我可以使用序列表生成自己的ID,但不清楚如何将现有ID与触发器通信。第一个触发器应生成新ID。同一事务中的后续触发器应共享现有ID 我可以使用线程局部变量来共享现有ID,但这似乎很脆弱。有更好的方法吗?使用序列而不是事务ID怎么样 CREATE SEQUENCE SEQ; 事务中的第一个操作设置会话变量,如下所示: SET @TID = SEQ.NEXTVAL; 此事务中的其他操作使用会话变量: CALL @TID; 我发现了一个非常棘手的解决办法: /

在撰写本文时,不支持内存中的数据库。我可以使用序列表生成自己的ID,但不清楚如何将现有ID与触发器通信。第一个触发器应生成新ID。同一事务中的后续触发器应共享现有ID


我可以使用线程局部变量来共享现有ID,但这似乎很脆弱。有更好的方法吗?

使用序列而不是事务ID怎么样

CREATE SEQUENCE SEQ;
事务中的第一个操作设置会话变量,如下所示:

SET @TID = SEQ.NEXTVAL;
此事务中的其他操作使用会话变量:

CALL @TID;

我发现了一个非常棘手的解决办法:

/**
 * Invoked when a transaction completes.
 */
public abstract class TransactionListener extends Value
{
    private boolean invoked;

    /**
     * Invoked when the transaction completes.
     */
    protected abstract void onCompleted();

    @Override
    public String getSQL()
    {
        return null;
    }

    @Override
    public int getType()
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    public long getPrecision()
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    public int getDisplaySize()
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    public String getString()
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    public Object getObject()
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    public void set(PreparedStatement prep, int parameterIndex) throws SQLException
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    protected int compareSecure(Value v, CompareMode mode)
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    public int hashCode()
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    public boolean equals(Object other)
    {
        throw new AssertionError("Unexpected method invocation");
    }

    @Override
    public boolean isLinked()
    {
        return !invoked;
    }

    @Override
    public void close()
    {
        invoked = true;
        onCompleted();
    }
}

// -------------TRIGGER BELOW-----------

public void fire(final Connection connection, ResultSet oldRow, ResultSet newRow)
    throws SQLException
{
    Statement statement = connection.createStatement();
    long transactionId;
    ResultSet rs = statement.executeQuery("SELECT @TRANSACTION_ID");
    try
    {
        rs.next();
        transactionId = rs.getLong(1);
        if (transactionId == 0)
        {
            // Generate a new transaction id
            rs.close();
            JdbcConnection jdbcConnection = (JdbcConnection) connection;
            final Session session = (Session) jdbcConnection.getSession();
            session.unlinkAtCommit(new TransactionListener()
            {
                @Override
                protected void onCompleted()
                {
                    boolean oldAutoCommit = session.getAutoCommit();
                    session.setAutoCommit(false);
                    try
                    {
                        Statement statement = connection.createStatement();
                        statement.executeQuery("SELECT SET(@TRANSACTION_ID, NULL)");
                        statement.close();
                    }
                    catch (SQLException e)
                    {
                        throw new AssertionError(e);
                    }
                    finally
                    {
                        session.setAutoCommit(oldAutoCommit);
                    }
                }
            });
            rs = statement.executeQuery("SELECT SET(@TRANSACTION_ID, "
                + "audit_transaction_sequence.NEXTVAL)");
            rs.next();
            transactionId = rs.getLong(1);
        }
    }
    finally
    {
        rs.close();
    }
    assert (transactionId != 0);
    // ...
}
下面是它的工作原理:

我们使用Session.unlinkAtCommit来监听事务提交,我假设这个钩子也会回滚,但我还没有验证它 由于我们无法预测触发器调用的数量和顺序,因此必须对每个触发器执行以下检查:

如果@TRANSACTION_ID为null,则注册一个新的事件侦听器并递增序列。 如果@TRANSACTION_ID不为空,则从中获取当前事务ID。 此解决方案的两个主要问题是:

它非常脆弱。如果Session.unlinkAtCommit将来发生更改,则可能会中断事件侦听器。 为了检索事务id,我们必须在每个触发器的顶部重复大量样板代码。
将其实现为内置函数TRANSACTION\u LOCAL\u ID要容易得多。此函数将返回类似于HSQLDB的数据库实例特定事务ID。

我无法预测触发器的调用顺序,因此我不知道何时调用NEXTVAL。有没有一种方法可以注册一个钩子,这样在每个事务开始时NEXTVAL都会被调用一次?很抱歉,我的回答不正确,因为如果其他会话调用NEXTVAL,CURRVAL会发生变化。所以这不起作用。。。相反,如果使用CURRVAL,则可以使用会话变量SET@TID=SEQ.NEXTVAL。这看起来很有希望,但让我相信变量的定义将跨越多个事务,因为它是会话范围的,而不是事务范围的。如何确保每个事务使用不同的ID?我刚刚检查过,如果每个连接有一个事务,那么使用用户变量就可以了。我们需要一个针对每个连接的多个事务的解决方案,特别是考虑到连接池的使用。有什么想法吗?