Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用JOOQ和Spring boot 2.0进行手动事务管理?_Spring_Spring Boot_Java 8_Jooq - Fatal编程技术网

如何使用JOOQ和Spring boot 2.0进行手动事务管理?

如何使用JOOQ和Spring boot 2.0进行手动事务管理?,spring,spring-boot,java-8,jooq,Spring,Spring Boot,Java 8,Jooq,使用弹簧靴2.0.4和JOOQ 3.11.3 我有一个需要对事务管理进行细粒度控制的服务器端点;它需要在外部调用前后发出多个SQL语句,并且在与外部站点通信时不能保持DB事务打开 在下面的代码中,testTransactionV4是我最喜欢的尝试 我已经看过JOOQ手册,但是事务管理部分非常简单,似乎暗示这就是实现它的方法 我觉得我在这里工作比我应该在这里工作更努力,这通常是我做错了的一个迹象。有没有更好的“正确”方法来使用Spring/JOOQ进行手动事务管理 此外,对TransactionB

使用弹簧靴2.0.4和JOOQ 3.11.3

我有一个需要对事务管理进行细粒度控制的服务器端点;它需要在外部调用前后发出多个SQL语句,并且在与外部站点通信时不能保持DB事务打开

在下面的代码中,testTransactionV4是我最喜欢的尝试

我已经看过JOOQ手册,但是事务管理部分非常简单,似乎暗示这就是实现它的方法

我觉得我在这里工作比我应该在这里工作更努力,这通常是我做错了的一个迹象。有没有更好的“正确”方法来使用Spring/JOOQ进行手动事务管理

此外,对TransactionBean实现的任何改进都将受到极大的赞赏(并进行投票)

但问题的关键其实只是:“这是正确的方式吗?”


测试点:

@Role.SystemApi
@SystemApiEndpoint
public class TestEndpoint {
  private static Log log = to(TestEndpoint.class);

  @Autowired private DSLContext db;
  @Autowired private TransactionBean txBean;
  @Autowired private Tx tx;

  private void doNonTransactionalThing() {
    log.info("long running thing that should not be inside a transaction");
  }

  /** Works; don't like the commitWithResult name but it'll do if there's
   no better way.  Implementation is ugly too.
   */
  @JsonPostMethod("testTransactionV4")
  public void testMultiTransactionWithTxBean() {
    log.info("start testMultiTransactionWithTxBean");

    AccountRecord account = txBean.commitWithResult( db ->
      db.fetchOne(ACCOUNT, ACCOUNT.ID.eq(1)) );

    doNonTransactionalThing();

    account.setName("test_tx+"+new Date());

    txBean.commit(db -> account.store() );
  }

  /** Works; but it's ugly, especially having to work around lambda final
   requirements on references.   */
  @JsonPostMethod("testTransactionV3")
  public void testMultiTransactionWithJooqApi() {
    log.info("start testMultiTransactionWithJooqApi");

    AtomicReference<AccountRecord> account = new AtomicReference<>();
    db.transaction( config->
      account.set(DSL.using(config).fetchOne(ACCOUNT, ACCOUNT.ID.eq(1))) );

    doNonTransactionalThing();

    account.get().setName("test_tx+"+new Date());

    db.transaction(config->{
      account.get().store();
    });
  }

  /** Does not work, there's only one commit that spans over the long operation */
  @JsonPostMethod("testTransactionV1")
  @Transactional
  public void testIncorrectSingleTransactionWithMethodAnnotation() {
    log.info("start testIncorrectSingleTransactionWithMethodAnnotation");

    AccountRecord account = db.fetchOne(ACCOUNT, ACCOUNT.ID.eq(1));

    doNonTransactionalThing();

    account.setName("test_tx+"+new Date());
    account.store();
  }

  /** Works, but I don't like defining my tx boundaries this way, readability
   is poor (relies on correct bean naming and even then is non-obvious) and is
   fragile in the face of refactoring.  When explicit TX boundaries are needed
   I want them getting in my face straight away.
   */
  @JsonPostMethod("testTransactionV2")
  public void testMultiTransactionWithNestedComponent() {
    log.info("start testTransactionWithComponentDelegation");

    AccountRecord account = tx.readAccount();

    doNonTransactionalThing();

    account.setName("test_tx+"+new Date());
    tx.writeAccount(account);
  }

  @Component
  static class Tx {
    @Autowired private DSLContext db;

    @Transactional
    public AccountRecord readAccount() {
      return db.fetchOne(ACCOUNT, ACCOUNT.ID.eq(1));
    }

    @Transactional
    public void writeAccount(AccountRecord account) {
      account.store();
    }
  }

}
@Role.SystemApi
@SystemApident
公共类测试点{
私有静态日志Log=to(TestEndpoint.class);
@自连线专用上下文数据库;
@自动连接私有事务Bean txBean;
@自动有线专用发送;
私有void doNonTransactionalThing(){
log.info(“不应该在事务内部的长时间运行的东西”);
}
/**有效;不喜欢commitWithResult名称,但如果有
没有更好的方法了。实现也很难看。
*/
@JsonPostMethod(“testTransactionV4”)
public void TestMultiTransaction with TXBean(){
log.info(“使用TXBean启动TestMultiTransaction”);
AccountRecord account=txBean.commitWithResult(db->
db.fetchOne(ACCOUNT,ACCOUNT.ID.eq(1));
doNonTransactionalThing();
account.setName(“test_tx+”+new Date());
提交(db->account.store());
}
/**工作,但它是丑陋的,尤其是必须围绕lambda决赛工作
对参考资料的要求*/
@JsonPostMethod(“testTransactionV3”)
public void TestMultiTransaction with jooqapi(){
log.info(“使用JooQAPI启动TestMultiTransaction”);
AtomicReference帐户=新的AtomicReference();
数据库事务(配置->
set(DSL.using(config.fetchOne(account,account.ID.eq(1)));
doNonTransactionalThing();
account.get().setName(“test_tx+”+new Date());
数据库事务(配置->{
account.get().store();
});
}
/**不起作用,只有一个提交跨越长操作*/
@JsonPostMethod(“testTransactionV1”)
@交易的
public void testIncorrectSingleTransactionWithMethodAnnotation(){
log.info(“start testIncorrectSingleTransactionWithMethodAnnotation”);
AccountRecord account=db.fetchOne(account,account.ID.eq(1));
doNonTransactionalThing();
account.setName(“test_tx+”+new Date());
account.store();
}
/**工作,但我不喜欢这样定义我的tx边界,可读性
很差(依赖于正确的bean命名,甚至不明显),并且
在重构面前很脆弱。当需要明确的TX边界时
我想让他们直接打到我的脸上。
*/
@JsonPostMethod(“testTransactionV2”)
public void testMultiTransactionWithNestedComponent(){
log.info(“启动testTransactionWithComponentDelegation”);
AccountRecord account=tx.readAccount();
doNonTransactionalThing();
account.setName(“test_tx+”+new Date());
tx.writeAccount(账户);
}
@组成部分
静态类Tx{
@自连线专用上下文数据库;
@交易的
公共帐户记录读取帐户(){
返回db.fetchOne(ACCOUNT,ACCOUNT.ID.eq(1));
}
@交易的
公共无效writeAccount(AccountRecord帐户){
account.store();
}
}
}
TransactionBean:

@Component
public class TransactionBean {
  @Autowired private DSLContext db;

  /**
   Don't like the name, but can't figure out how to make it be just "commit".
   */
  public <T> T commitWithResult(Function<DSLContext, T> worker) {
    // Yuck, at the very least need an array or something as the holder.
    AtomicReference<T> result = new AtomicReference<>();
    db.transaction( config -> result.set(
      worker.apply(DSL.using(config))
    ));
    return result.get();
  }

  public void commit(Consumer<DSLContext> worker) {
    db.transaction( config ->
      worker.accept(DSL.using(config))
    );
  }

  public void commit(Runnable worker) {
    db.transaction( config ->
      worker.run()
    );
  }
}
@组件
公共类TransactionBean{
@自连线专用上下文数据库;
/**
不喜欢这个名字,但不知道如何让它成为“提交”。
*/
公共T委员会结果(职能工作人员){
//哎呀,至少需要一个数组或什么东西作为持有者。
AtomicReference结果=新的AtomicReference();
db.transaction(配置->结果集(
worker.apply(DSL.using(config))
));
返回result.get();
}
公共无效提交(消费者工作者){
数据库事务(配置->
accept(DSL.using(config))
);
}
公共void提交(可运行工作程序){
数据库事务(配置->
worker.run()
);
}
}
使用来包装事务部分。Spring Boot提供了一个开箱即用的功能,因此可以随时使用。您可以使用该方法在事务中包装调用

@Autowired
private TransactionTemplate transaction;

@JsonPostMethod("testTransactionV1")
public void testIncorrectSingleTransactionWithTransactionTemplate() {
  log.info("start testIncorrectSingleTransactionWithMethodAnnotation");

  AccountRecord account = transaction.execute( status -> db.fetchOne(ACCOUNT, ACCOUNT.ID.eq(1)));

  doNonTransactionalThing();

  transaction.execute(status -> {
    account.setName("test_tx+"+new Date());
    account.store();
    return null;
  }
}

像这样的事情应该会奏效。不确定lambda是否有效(不要试图实现自己的语法,而要忘记

Just us springs
TransactionTemplate
的语法。用它包装需要进行事务处理的部分。对于JOOQ来说,它仍然像是spring管理的事务,因此不需要更改。