springpanner的keep-alive写会话是如何工作的?

6yjfywim  于 2021-07-14  发布在  Java
关注(0)|答案(1)|浏览(305)

我不知道为什么spring-panner的keep-alive for-write会话可以不中断地工作。
我的理解如下:
写会话在实际使用并保留在会话池中之前启动读写事务。
保持活力执行官 select 1 对于您在application.yaml中指定的时间间隔(默认值为30分钟)。
如果在最后一个sql执行后超过10秒,那么panner的读写事务将导致中止。
所以我认为它会在最后一次执行keep-alive 10秒后导致中止。然而,我还没有看到这种情况下中止。
它是如何工作的?

1dkrff03

1dkrff031#

我可以看出这有点混乱,但实际上有两种不同的情况可能会超时,并且可能需要在cloud-panner中使用keep-alive查询。
如果读/写事务处于活动状态且未使用超过10秒,则将中止读/写事务。为了让它活下来,你可以用一个 SELECT 1 查询。但是:您通常不应该这样做,因为您应该尽量使读/写事务尽可能短。这种混乱来自这样一个事实:读/写事务只有在执行了至少一条语句之后才会被认为是活动的。因此,会话池中准备好的事务只在 BeginTransaction ,但他们还没有看到任何声明。因此,这些操作不会启动,也不会中止。
会话将在60分钟后超时。这个 SELECT 1 会话池中每30分钟执行一次的keep-alive查询可以防止会话超时。
现在的下一个问题可能是:关于 SELECT 1 在池中已准备好读/写事务的会话上执行的语句,在 SELECT 1 执行ping查询,然后在10秒后中止?
答案是否定的 SELECT 1 ping查询是使用一次性只读事务执行的。这不会影响同一会话上准备好的读/写事务,因此会话和读/写事务都将保持有效。
不能在会话上同时执行多个事务的限制仅适用于同时处于活动状态的多个读/写事务。
编辑:添加额外的例子来显示什么是允许的和不允许的。
下面的示例使用生成的javapanner客户机( com.google.cloud.spanner.v1.SpannerClient )在一个会话上执行多个事务时,显示哪些是可能的,哪些是不可能的。除最后一条外,以下所有语句都将成功。

SpannerClient client = SpannerClient.create();
// Create a session and a read/write transaction.
Session session = client.createSession(
    DatabaseName.of("my-project", "my-instance", "my-database"));
Transaction transaction = client.beginTransaction(session.getName(),
    TransactionOptions
      .newBuilder()
      .setReadWrite(ReadWrite.getDefaultInstance())
      .build());

// Execute a statement using a single-use read-only transaction.
client.executeSql(
    ExecuteSqlRequest
      .newBuilder()
      .setSession(session.getName())
      .setSql("SELECT * FROM SINGERS")
      .setTransaction(
          TransactionSelector.newBuilder().setSingleUse(
            TransactionOptions
              .newBuilder()
              .setReadOnly(ReadOnly.getDefaultInstance()).build())
          .build())
        .build());

// Execute a statement on the read/write transaction. This will activate
// the transaction.
client.executeSql(
    ExecuteSqlRequest
      .newBuilder()
      .setSession(session.getName())
      .setSql("SELECT * FROM SINGERS")
      .setTransaction(
          TransactionSelector
          .newBuilder()
          .setId(transaction.getId())
          .build())
      .build());

// Execute another statement using a single-use read-only transaction.
client.executeSql(
    ExecuteSqlRequest
      .newBuilder()
      .setSession(session.getName())
      .setSql("SELECT * FROM SINGERS")
      .setTransaction(
          TransactionSelector.newBuilder().setSingleUse(
            TransactionOptions
              .newBuilder()
              .setReadOnly(ReadOnly.getDefaultInstance()).build())
          .build())
        .build());

// Start a read-only transaction on the same session.
Transaction readOnlyTx = client.beginTransaction(session.getName(),
    TransactionOptions
      .newBuilder()
      .setReadOnly(
          ReadOnly
            .newBuilder()
            .setExactStaleness(Duration.newBuilder().setSeconds(10L).build())
            .build())
       .build());
// Execute a statement on the multi-use read-only transaction.
client.executeSql(
    ExecuteSqlRequest
      .newBuilder()
      .setSession(session.getName())
      .setSql("SELECT * FROM SINGERS")
      .setTransaction(
          TransactionSelector
            .newBuilder()
            .setId(readOnlyTx.getId())
            .build())
      .build());

// The initial read/write transaction is still valid.
client.executeSql(
    ExecuteSqlRequest
      .newBuilder()
      .setSession(session.getName())
      .setSql("SELECT * FROM SINGERS")
      .setTransaction(
          TransactionSelector
            .newBuilder()
            .setId(transaction.getId())
            .build())
      .build());

// Start another read/write transaction on the same session.
// This transaction has not been activated yet, as we have not
// executed any statements on it.
Transaction anotherTransaction = client.beginTransaction(session.getName(),
    TransactionOptions
      .newBuilder()
      .setReadWrite(ReadWrite.getDefaultInstance())
      .build());

// Execute another statement on the initial read/write transaction.
// This transaction is still usable even though we just created a
// new read/write transaction on the same session.
client.executeSql(
    ExecuteSqlRequest
      .newBuilder()
      .setSession(session.getName())
      .setSql("SELECT * FROM SINGERS")
      .setTransaction(
          TransactionSelector
          .newBuilder()
          .setId(transaction.getId())
          .build())
      .build());

// Now execute a statement on the second read/write transaction.
// This will silently invalidate the first read/write transaction.
client.executeSql(
    ExecuteSqlRequest
      .newBuilder()
      .setSession(session.getName())
      .setSql("SELECT * FROM SINGERS")
      .setTransaction(
          TransactionSelector
          .newBuilder()
          .setId(anotherTransaction.getId())
          .build())
      .build());

// Now try to execute a statement on the initial read/write transaction.
// Only this statement will fail because it has been invalidated by another
// read/write transaction on the same session.
client.executeSql(
    ExecuteSqlRequest
      .newBuilder()
      .setSession(session.getName())
      .setSql("SELECT * FROM SINGERS")
      .setTransaction(
          TransactionSelector
          .newBuilder()
          .setId(transaction.getId())
          .build())
      .build());

相关问题