Jaybird 3 和 Firebird 交易信息



在以前的jaybird(2.2(版本中,我能够对Firebird服务器执行服务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:FIREBIRD3.0.2EXAMPLESEMPBUILDEMPLOYEE.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,请参阅此提交。

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

  1. 使用StatisticsManager

    StatisticsManager statsMan = new FBStatisticsManager();
    statsMan.setHost("localhost");
    statsMan.setDatabase("/path/to/your.fdb");
    statsMan.setUser("youruser");
    statsMan.setPassword("yourpassword"); 
    DatabaseTransactionInfo info = statsMan.getDatabaseTransactionInfo();
    
  2. 使用现有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-快照

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

select * from MON$DATABASE会查询"OIT, OAT, Next">

或者,您可以通过select * from MON$TRANSACTIONS获取更多详细信息

c:Program FilesFirebirdFirebird_2_1docREADME.monitoring_tables.txt中查看更多内容

MON$DATABASE (connected database)
  - MON$DATABASE_NAME (database pathname or alias)
  - MON$PAGE_SIZE (page size)
  - MON$ODS_MAJOR (major ODS version)
  - MON$ODS_MINOR (minor ODS version)
  - MON$OLDEST_TRANSACTION (OIT number)
  - MON$OLDEST_ACTIVE (OAT number)
  - MON$OLDEST_SNAPSHOT (OST number)
  - MON$NEXT_TRANSACTION (next transaction number)
  - MON$PAGE_BUFFERS (number of pages allocated in the cache)
  - MON$SQL_DIALECT (SQL dialect of the database)
  - MON$SHUTDOWN_MODE (current shutdown mode)
      0: online
      1: multi-user shutdown
      2: single-user shutdown
      3: full shutdown
  - MON$SWEEP_INTERVAL (sweep interval)
  - MON$READ_ONLY (read-only flag)
  - MON$FORCED_WRITES (sync writes flag)
  - MON$RESERVE_SPACE (reserve space flag)
  - MON$CREATION_DATE (creation date/time)
  - MON$PAGES (number of pages allocated on disk)
  - MON$BACKUP_STATE (current physical backup state)
      0: normal
      1: stalled
      2: merge
  - MON$STAT_ID (statistics ID)
MON$TRANSACTIONS (started transactions)
  - MON$TRANSACTION_ID (transaction ID)
  - MON$ATTACHMENT_ID (attachment ID)
  - MON$STATE (transaction state)
      0: idle
      1: active
  - MON$TIMESTAMP (transaction start date/time)
  - MON$TOP_TRANSACTION (top transaction)
  - MON$OLDEST_TRANSACTION (local OIT number)
  - MON$OLDEST_ACTIVE (local OAT number)
  - MON$ISOLATION_MODE (isolation mode)
      0: consistency
      1: concurrency
      2: read committed record version
      3: read committed no record version
  - MON$LOCK_TIMEOUT (lock timeout)
      -1: infinite wait
      0: no wait
      N: timeout N
  - MON$READ_ONLY (read-only flag)
  - MON$AUTO_COMMIT (auto-commit flag)
  - MON$AUTO_UNDO (auto-undo flag)
  - MON$STAT_ID (statistics ID)

注 1:这些表中的某些数据仅在通过SYSDBARDB$ADMIN或数据库所有者用户连接时可用。示例:附件(连接(表将使其他用户的连接不可见,并为非管理员用户的请求跳过。

注意 2:从监视表中读取可能相对较慢,尤其是从包含连接相关(AKA 附件相关(信息的表中读取。慢,阻塞。因此,不建议过于频繁地读取监视表。

相关内容

  • 没有找到相关文章

最新更新