public class SpringTransactionProvider implements TransactionProvider { private static final JooqLogger log = JooqLogger.getLogger(SpringTransactionProvider.class); @Autowired DataSourceTransactionManager txMgr; @Override public void begin(TransactionContext ctx) { log.info("Begin transaction"); // This TransactionProvider behaves like jOOQ's DefaultTransactionProvider, // which supports nested transactions using Savepoints // but use PROPAGATION_REQUIRED AS DEFAULT TransactionStatus tx = txMgr.getTransaction(new DefaultTransactionDefinition(PROPAGATION_REQUIRED)); ctx.transaction(new SpringTransaction(tx)); } @Override public void commit(TransactionContext ctx) { log.info("commit transaction"); txMgr.commit(((SpringTransaction) ctx.transaction()).tx); } @Override public void rollback(TransactionContext ctx) { log.info("rollback transaction"); txMgr.rollback(((SpringTransaction) ctx.transaction()).tx); } }
--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi Lukas,when you say @Transactional is not supported you mean @Transactional attributes not supported I suppose.
Actually my SpringTransactionProvider allow use of @Transactional annotations( creating a jooq Transaction in a transparent way) the only missing things are @Transactional parameters.
I suspect actually due SpringTransactionProvider is created at spring boot time it can't intercept specific instance call parameters.Anyway I'm looking forward to #4836.I've added some comments here.
public class SpringTransactionProvider implements TransactionProvider { private static final JooqLogger log = JooqLogger.getLogger(SpringTransactionProvider.class); @Autowired DataSourceTransactionManager txMgr; @Override public void begin(TransactionContext ctx) { log.info("Begin transaction"); // This TransactionProvider behaves like jOOQ's DefaultTransactionProvider, // which supports nested transactions using Savepoints
TransactionStatus tx = txMgr.getTransaction(new DefaultTransactionDefinition(PROPAGATION_NESTED)); ctx.transaction(new SpringTransaction(tx));
} @Override public void commit(TransactionContext ctx) { log.info("commit transaction"); txMgr.commit(((SpringTransaction) ctx.transaction()).tx); } @Override public void rollback(TransactionContext ctx) { log.info("rollback transaction"); txMgr.rollback(((SpringTransaction) ctx.transaction()).tx); } }
I wouldn't call it "Mix" it's more a delegation process. Spring intercept @Transactional annotation and delegate jooq to manage it, but actually I don't know how jooqcan manage "start a new transaction" instead of "use current one" in some cases.
Code is almost identical to the reference one intoThe hot part is the following where is not possible do manage different propagation style cause this parameter is not in ctx.Of course I can implement provider as needed but I don't know how to have @Transactional parameters as input here, to create transaction in right way.
I could investigate about this...
--
You received this message because you are subscribed to a topic in the Google Groups "jOOQ User Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jooq-user/FVFKKVPheh4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jooq-user+...@googlegroups.com.
try(DSLContext ctx = dbCon.usingCtx()) {
ctx.transaction(configuration -> {
TransactionProvider jooqTransactionProvider = configuration.transactionProvider();
DSLContext innerCtx;
if(jooqTransactionProvider instanceof SpringTransactionProvider) {
SpringTransactionProvider stp = (SpringTransactionProvider)jooqTransactionProvider;
SpringTransactionProvider localTsp = stp.derive(configuration.connectionProvider(), TransactionDefinition.ISOLATION_SERIALIZABLE);
Configuration derivedCfg = configuration.derive(localTsp);
innerCtx = DSL.using(derivedCfg);
}
else {
// Use default configuration and transaction definition
innerCtx = DSL.using(configuration);
}
innerCtx.insertInto()....
});
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
I didn’t think I patched the current transaction, I thought I created a new inner transaction with a different/derived config.
So if I do a config.derive before starting the transaction then I am fine?
The main problem as I can see it right now is that the TransactionDefinition is hardcoded in the SpringTransactionProvider. For most things that is fine but this is a special case where I must use a different transaction isolation.
Configuration derivedCfg;
TransactionProvider jooqTransactionProvider = cfg.transactionProvider();
if (jooqTransactionProvider instanceof SpringTransactionProvider) {
SpringTransactionProvider stp = (SpringTransactionProvider) jooqTransactionProvider;
SpringTransactionProvider localStp = stp.derive(cfg.connectionProvider(), TransactionDefinition.ISOLATION_SERIALIZABLE);
derivedCfg = cfg.derive(localStp);
} else {
// Use default configuration and transaction definition
derivedCfg = cfg;
}
try (DSLContext ctx = new DefaultDSLContext(derivedCfg)) {
ctx.transaction(() -> ctx.insertInto(table("")).columns(field("")).values("").execute()); // <-- just dummy example
}
try (DSLContext ctx = dbCon.transactionWithIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE)) {
ctx.transaction(() -> savedResult.set(saveMethod(ctx, entity))
);
return savedResult.get();
}
/**
* An example <code>TransactionProvider</code> implementing the {@link TransactionProvider} contract for use with
* Spring.
*
* @author Lukas Eder
*/
public class SpringTransactionProvider extends ThreadLocalTransactionProvider implements TransactionProvider {
private static final JooqLogger LOGGER = JooqLogger.getLogger(SpringTransactionProvider.class);
private DataSourceTransactionManager txMgr;
private int transactionDefinition;
public SpringTransactionProvider(ConnectionProvider provider, DataSourceTransactionManager txMgr) {
super(provider);
this.txMgr = txMgr;
this.transactionDefinition = PROPAGATION_NESTED;
}
public SpringTransactionProvider(ConnectionProvider provider, DataSourceTransactionManager txMgr, int transactionDefinition) {
super(provider);
this.txMgr = txMgr;
this.transactionDefinition = transactionDefinition;
}
@Override
public void begin(TransactionContext ctx) {
LOGGER.info("Begin transaction");
// This TransactionProvider behaves like jOOQ's DefaultTransactionProvider,
// which supports nested transactions using Savepoints
TransactionStatus tx = txMgr.getTransaction(new DefaultTransactionDefinition(transactionDefinition));
ctx.transaction(new SpringTransaction(tx));
}
@Override
public void commit(TransactionContext ctx) {
LOGGER.info("commit transaction");
txMgr.commit(((SpringTransaction) ctx.transaction()).tx);
}
@Override
public void rollback(TransactionContext ctx) {
LOGGER.info("rollback transaction");
txMgr.rollback(((SpringTransaction) ctx.transaction()).tx);
}
public SpringTransactionProvider derive(ConnectionProvider provider, int transDefinition) {
return new SpringTransactionProvider(provider, txMgr, transactionDefinition);
}
}
--
/**
* An example <code>TransactionProvider</code> implementing the {@link TransactionProvider} contract for use with
* Spring.
*
* @author Lukas Eder
*/
public class SpringTransactionProvider extends ThreadLocalTransactionProvider implements TransactionProvider {
private static final JooqLogger LOGGER = JooqLogger.getLogger(SpringTransactionProvider.class);
private DataSourceTransactionManager txMgr;
private int propagationBehavior;
private int isolationLevel;
public SpringTransactionProvider(ConnectionProvider provider, DataSourceTransactionManager txMgr) {
super(provider);
this.txMgr = txMgr;
this.propagationBehavior = PROPAGATION_NESTED;
this.isolationLevel = ISOLATION_DEFAULT;
}
public SpringTransactionProvider(ConnectionProvider provider, DataSourceTransactionManager txMgr, int propagationBehavior, int isolationLevel) {
super(provider);
this.txMgr = txMgr;
this.propagationBehavior = propagationBehavior;
this.isolationLevel = isolationLevel;
}
@Override
public void begin(TransactionContext ctx) {
LOGGER.info("Begin transaction");
// This TransactionProvider behaves like jOOQ's DefaultTransactionProvider,
// which supports nested transactions using Savepoints
DefaultTransactionDefinition def = new DefaultTransactionDefinition(propagationBehavior);
if(isolationLevel != ISOLATION_DEFAULT) {
def.setIsolationLevel(isolationLevel);
}
TransactionStatus tx = txMgr.getTransaction(def);
ctx.transaction(new SpringTransaction(tx));
}
@Override
public void commit(TransactionContext ctx) {
LOGGER.info("commit transaction");
txMgr.commit(((SpringTransaction) ctx.transaction()).tx);
}
@Override
public void rollback(TransactionContext ctx) {
LOGGER.info("rollback transaction");
txMgr.rollback(((SpringTransaction) ctx.transaction()).tx);
}
public SpringTransactionProvider derive(ConnectionProvider provider, int propagationBehavior, int isolationLevel) {
return new SpringTransactionProvider(provider, txMgr, propagationBehavior, isolationLevel);
}
}
try (DSLContext ctx = dbCon.useCustomTransaction(TransactionDefinition.PROPAGATION_NESTED, TransactionDefinition.ISOLATION_SERIALIZABLE)) {
ctx.transaction(() -> savedResult.set(
saveEntity(ctx, entity))
);
return savedResult.get();
}
The noisy code creating the derived config is moved into a helper class so that I don't need to have this spread around my DAOs:try (DSLContext ctx = dbCon.transactionWithIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE)) {
ctx.transaction(() -> savedResult.set(saveMethod(ctx, entity))
);
return savedResult.get();
}