Starter for using jOOQ to access SQL databases with JDBC, providing auto-configuration and Spring integration
—
Integration between jOOQ and Spring's transaction management system, allowing jOOQ operations to participate seamlessly in Spring-managed transactions.
Allows Spring transactions to be used with jOOQ by implementing jOOQ's TransactionProvider interface.
/**
* TransactionProvider implementation that integrates jOOQ with Spring's transaction management
* Automatically configured when PlatformTransactionManager is available
*/
public class SpringTransactionProvider implements TransactionProvider {
/**
* Create a new SpringTransactionProvider with the given transaction manager
* @param transactionManager Spring's platform transaction manager
*/
public SpringTransactionProvider(PlatformTransactionManager transactionManager);
/**
* Begin a new transaction context
* Creates a nested transaction with PROPAGATION_NESTED
* @param context the jOOQ transaction context
*/
@Override
public void begin(TransactionContext context);
/**
* Commit the current transaction
* @param ctx the jOOQ transaction context
*/
@Override
public void commit(TransactionContext ctx);
/**
* Rollback the current transaction
* @param ctx the jOOQ transaction context
*/
@Override
public void rollback(TransactionContext ctx);
}Adapter that wraps Spring's TransactionStatus for use with jOOQ's Transaction interface.
/**
* Adapts a Spring TransactionStatus for jOOQ Transaction interface
* Used internally by SpringTransactionProvider
*/
class SpringTransaction implements Transaction {
/**
* Create a new SpringTransaction wrapping the given TransactionStatus
* @param transactionStatus Spring's transaction status
*/
SpringTransaction(TransactionStatus transactionStatus);
/**
* Get the wrapped Spring TransactionStatus
* @return the underlying TransactionStatus
*/
TransactionStatus getTxStatus();
}Usage Examples:
@Service
@Transactional
public class OrderService {
@Autowired
private DSLContext dsl;
public void processOrder(Order order) {
// Insert order - participates in Spring transaction
dsl.insertInto(ORDER)
.set(ORDER.ID, order.getId())
.set(ORDER.CUSTOMER_ID, order.getCustomerId())
.set(ORDER.TOTAL, order.getTotal())
.execute();
// Insert order items - same transaction
for (OrderItem item : order.getItems()) {
dsl.insertInto(ORDER_ITEM)
.set(ORDER_ITEM.ORDER_ID, order.getId())
.set(ORDER_ITEM.PRODUCT_ID, item.getProductId())
.set(ORDER_ITEM.QUANTITY, item.getQuantity())
.execute();
}
// Update inventory - still same transaction
updateInventory(order.getItems());
}
private void updateInventory(List<OrderItem> items) {
for (OrderItem item : items) {
dsl.update(INVENTORY)
.set(INVENTORY.QUANTITY, INVENTORY.QUANTITY.minus(item.getQuantity()))
.where(INVENTORY.PRODUCT_ID.eq(item.getProductId()))
.execute();
}
}
}@Service
public class BatchProcessingService {
@Autowired
private DSLContext dsl;
@Autowired
private PlatformTransactionManager transactionManager;
public void processBatch(List<Data> dataList) {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
for (Data data : dataList) {
// jOOQ operations automatically participate in the transaction
dsl.insertInto(BATCH_DATA)
.set(BATCH_DATA.VALUE, data.getValue())
.set(BATCH_DATA.PROCESSED_AT, LocalDateTime.now())
.execute();
}
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}@Service
public class UserService {
@Autowired
private DSLContext dsl;
@Autowired
private AuditService auditService;
@Transactional
public void createUser(User user) {
// Main transaction
dsl.insertInto(USER)
.set(USER.NAME, user.getName())
.set(USER.EMAIL, user.getEmail())
.execute();
// Audit in same transaction by default
auditService.logUserCreation(user.getId());
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createUserWithSeparateAudit(User user) {
// Main transaction
dsl.insertInto(USER)
.set(USER.NAME, user.getName())
.set(USER.EMAIL, user.getEmail())
.execute();
// Audit in separate transaction - will commit even if main fails
auditService.logUserCreationSeparate(user.getId());
}
}
@Service
public class AuditService {
@Autowired
private DSLContext dsl;
@Transactional(propagation = Propagation.REQUIRED)
public void logUserCreation(Long userId) {
// Participates in existing transaction
dsl.insertInto(AUDIT_LOG)
.set(AUDIT_LOG.USER_ID, userId)
.set(AUDIT_LOG.ACTION, "CREATE")
.execute();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logUserCreationSeparate(Long userId) {
// Always runs in new transaction
dsl.insertInto(AUDIT_LOG)
.set(AUDIT_LOG.USER_ID, userId)
.set(AUDIT_LOG.ACTION, "CREATE")
.execute();
}
}@Service
public class PaymentService {
@Autowired
private DSLContext dsl;
@Transactional(rollbackFor = Exception.class)
public void processPayment(Payment payment) throws PaymentException {
try {
// Validate payment
validatePayment(payment);
// Record payment attempt
dsl.insertInto(PAYMENT_ATTEMPT)
.set(PAYMENT_ATTEMPT.AMOUNT, payment.getAmount())
.set(PAYMENT_ATTEMPT.STATUS, "PROCESSING")
.execute();
// Process with external service
processWithGateway(payment);
// Update status on success
dsl.update(PAYMENT_ATTEMPT)
.set(PAYMENT_ATTEMPT.STATUS, "SUCCESS")
.where(PAYMENT_ATTEMPT.ID.eq(payment.getId()))
.execute();
} catch (PaymentException e) {
// Transaction will be rolled back automatically
// Both INSERT and UPDATE will be undone
throw e;
}
}
@Transactional(noRollbackFor = BusinessException.class)
public void processPaymentWithBusinessExceptionHandling(Payment payment) {
// Business exceptions won't trigger rollback
// Only runtime exceptions and errors will
}
}@Transactional annotations and programmatic transaction managementTransactionAwareDataSourceProxy to ensure connection reuse within transactionsPROPAGATION_NESTED by default for jOOQ-initiated transactions@Transactional attributesInstall with Tessl CLI
npx tessl i tessl/maven-org-springframework-boot--spring-boot-starter-jooq