在之前版本的jaybird(2.2)中,我能够对Firebird服务器执行Services API,以获取活动的事务标记:OIT,OAT,Next等。

在3.0版中,我找不到正确执行操作的方法。只有ISC常量(例如isc_info_oldest_snapshot),但没有方法。

因此,我看到了一种方法:通过StatisticsManager获取数据库头的查询。但这不是那么容易,因为它将返回需要解析的文本:

    StatisticsManager SM = new FBStatisticsManager();  //"PURE_JAVA", "NATIVE", "EMBEDDED"

    SM.setHost("localhost");
    SM.setUser("sysdba");
    SM.setPort(3053);
    SM.setPassword("masterkey");
    SM.setDatabase("c:\\Firebird\\3.0.2\\examples\\empbuild\\EMPLOYEE.FDB");

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    SM.setLogger(baos);
    SM.getHeaderPage();
    String outputstr2 = new String( baos.toByteArray(), java.nio.charset.StandardCharsets.UTF_8 );


现在我需要解析文本:

Database "C:\FIREBIRD\3.0.2\EXAMPLES\EMPBUILD\EMPLOYEE.FDB"
Database header page information:
   Flags            0
   Generation        806
   System Change Number    12
   Page size        8192
   ODS version        12.0
   Oldest transaction    520
   Oldest active        521
   Oldest snapshot        521
   Next transaction    521
   Sequence number        0
   Next attachment ID    857
   Implementation        HW=AMD/Intel/x64 little-endian OS=Windows CC=MSVC
   Shadow count        0
   Page buffers        0
   Next header page    0
   Database dialect    3
   Creation date        Apr 15, 2016 17:38:34
   Attributes

   Variable header data:
   Database backup GUID:    {6F41E937-76D5-4C67-6CAE-F8556AD27BEE}
   Database GUID:    {EE5B2713-7B17-43B0-0CB3-0616B4B8A63D}
   *END*


可能有可能获得直接价值?

upd:旧版本的代码是:

/** [ActiveCount, OAT, OST, OIT, Next] */
public static int[] getTxInfo( final GDS gds,
                               final String host,
                               final int port,
                               final String databasePath,
                               final String user,
                               final String password ) throws Exception {
    final byte[] queryItems = {
            ISCConstants.isc_info_oldest_transaction,
            ISCConstants.isc_info_oldest_active,
            ISCConstants.isc_info_oldest_snapshot,
            ISCConstants.isc_info_next_transaction,
            ISCConstants.isc_info_active_transactions,
            ISCConstants.isc_info_end
    };
    byte[] response = queryDB(
            gds, host, port, databasePath, user, password,
            queryItems, DEFAULT_BUFFER_SIZE
    );
    int i = 0;
    final int[] result = new int[5];
    while ( response[i] != ISCConstants.isc_info_end ) {
        final byte code = response[i++];
        switch ( code ) {
            case ISCConstants.isc_info_active_transactions: {
                //здесь идет столько блоков isc_info_active_transactions, сколько
                //реально активных транзакций в данный момент
                final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
                i += LENGTH_LEN;
                //final int res = gds.iscVaxInteger( response, i, valueLen );
                i += valueLen;
                result[0]++;
                break;
            }
            case ISCConstants.isc_info_oldest_active: {
                final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
                i += LENGTH_LEN;
                final int res = gds.iscVaxInteger( response, i, valueLen );
                i += valueLen;
                result[1] = res;
                break;
            }
            case ISCConstants.isc_info_oldest_snapshot: {
                final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
                i += LENGTH_LEN;
                final int res = gds.iscVaxInteger( response, i, valueLen );
                i += valueLen;
                result[2] = res;
                break;
            }
            case ISCConstants.isc_info_oldest_transaction: {
                final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
                i += LENGTH_LEN;
                final int res = gds.iscVaxInteger( response, i, valueLen );
                i += valueLen;
                result[3] = res;
                break;
            }
            case ISCConstants.isc_info_next_transaction: {
                final int valueLen = gds.iscVaxInteger( response, i, LENGTH_LEN );
                i += LENGTH_LEN;
                final int res = gds.iscVaxInteger( response, i, valueLen );
                i += valueLen;
                result[4] = res;
                break;
            }
            case ISCConstants.isc_info_truncated: {
                //этот код означает "буфер слишком маленький, дайте больше"
                //обычно это бывает когда слишком много активных транзакций

                //сначала пробуем увеличить буфер
                if ( response.length == DEFAULT_BUFFER_SIZE ) {
                    response = queryDB(
                            gds, host, port, databasePath, user, password,
                            queryItems, 32 * DEFAULT_BUFFER_SIZE
                    );
                    result[0] = 0;//на всякий случай
                    //начинаем разбор заново
                    i = 0;
                } else {
                    //32Кб буфера оказалось тоже недостаточно -- пичалька. Но
                    //делать нечего -- просто обойдемся без числа активных транзакций
                    response = queryDB(
                            gds, host, port, databasePath, user, password,
                            new byte[]{
                                    ISCConstants.isc_info_oldest_transaction,
                                    ISCConstants.isc_info_oldest_active,
                                    ISCConstants.isc_info_oldest_snapshot,
                                    ISCConstants.isc_info_next_transaction,
                                    ISCConstants.isc_info_end
                            }, DEFAULT_BUFFER_SIZE
                    );
                    result[0] = -1;
                    //начинаем разбор заново
                    i = 0;
                }
                break;
            }

            default:
                throw new FBSQLException( "Unrecognized response code: " + code + " (response=" + Arrays.toString( result ) + ")" );
        }
    }
    return result;
}


哪里

public static byte[] queryDB( final GDS gds,
                              final String host,
                              final int port,
                              final String databasePath,
                              final String user,
                              final String password,
                              final byte[] queryItems,
                              final int bufferLength ) throws Exception {
    return doWithDB(
            gds, host, port, databasePath, user, password,
            new DBOperation<byte[]>() {
                public byte[] doWithDB( final GDS gds,
                                        final IscDbHandle db ) throws GDSException {
                    return gds.iscDatabaseInfo(
                            db,
                            queryItems,
                            bufferLength
                    );
                }
            }
    );
}


够了吗

最佳答案

我已将功能添加到Jaybird 3.0.0,请参见this commit

我添加了两种获取此信息的方法:


使用StatisticsManager

StatisticsManager statsMan = new FBStatisticsManager();
statsMan.setHost("localhost");
statsMan.setDatabase("/path/to/your.fdb");
statsMan.setUser("youruser");
statsMan.setPassword("yourpassword");
DatabaseTransactionInfo info = statsMan.getDatabaseTransactionInfo();

使用现有的Connection获取此信息的便捷方法:

try (Connection connection = dataSource.getConnection()) {
    DatabaseTransactionInfo info = FBStatisticsManager
            .getDatabaseTransactionInfo(connection);
}


唯一的要求是将连接实例解包到FirebirdConnection接口。


如果使用的是Maven,则可以尝试使用Sonatype OSS快照存储库中的最新Jaybird快照:https://oss.sonatype.org/content/repositories/snapshots(您需要将此快照存储库添加到您的maven配置中)。

<dependency>
    <groupId>org.firebirdsql.jdbc</groupId>
    <artifactId>jaybird-jdk18</artifactId>
    <version>3.0.0-SNAPSHOT</version>
</dependency>


否则,您可以使用以下方法下载快照:


jaybird-jdk17 3.0.0-SNAPSHOT
jaybird-jdk18 3.0.0-SNAPSHOT


对于将来的版本,我将考虑是否可以以更通用的方式公开数据库信息查询工具,因此不必使用内部FbDatabase接口。

08-26 02:03