Skip to main content

10.1 Annotation-Based Transactions

Annotation-based transactions place boundaries on methods or classes, removing manual begin, commit, and rollBack calls from business code. This is the usual approach in the Service layer.

Suitable For​

  • A business method naturally defines a transaction boundary.
  • Automatic rollback on exceptions and commit on normal return are desired.
  • The project uses Spring, Solon, Guice, or Hasor, or can create proxies with TransactionHelper.support().

Not Suitable For​

  • Methods are not invoked through a proxy.
  • One method must start multiple transactions according to runtime conditions.
  • You need manual control over the commit or rollback order of transaction statuses.

Basic Usage​

OrderService.java
import net.hasor.dbvisitor.jdbc.JdbcTemplate;
import net.hasor.dbvisitor.transaction.Transactional;

public class OrderService {
private final JdbcTemplate jdbcTemplate;

public OrderService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@Transactional
public void createOrder(long orderId, long skuId) throws java.sql.SQLException {
jdbcTemplate.executeUpdate(
"insert into orders(id) values(?)",
orderId
);
jdbcTemplate.executeUpdate(
"insert into order_item(order_id, sku_id) values(?, ?)",
new Object[] { orderId, skuId }
);
}
}

Behavior:

  • When createOrder returns normally, both inserts commit together.
  • If either SQL statement throws, the transaction is marked for rollback and neither insert commits.

Enable Annotation-Based Transactions​

@Transactional is only a marker; an interceptor or proxy must handle the invocation for it to take effect.

Plain Java Programs​

Create a proxy with TransactionHelper.support
import javax.sql.DataSource;
import net.hasor.dbvisitor.jdbc.JdbcTemplate;
import net.hasor.dbvisitor.transaction.support.TransactionHelper;

DataSource dataSource = ...;
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

OrderService target = new OrderService(jdbcTemplate);
OrderService orderService = TransactionHelper.support(target, dataSource);

orderService.createOrder(10001L, 20001L);

TransactionHelper.support(target, dataSource) creates a proxy for target. Only calls through that proxy trigger transaction interception.

tip

Do not expect this.createOrder(...) within the class to trigger a transaction; self-invocation does not pass through the proxy.

This page uses dbVisitor's own @Transactional. When using Spring annotations and transaction managers, follow Spring's rollback rules; do not mix the two annotation systems.

Framework Projects​

Specify Propagation and Isolation​

Start an independent transaction with READ_COMMITTED isolation
import net.hasor.dbvisitor.transaction.Isolation;
import net.hasor.dbvisitor.transaction.Propagation;
import net.hasor.dbvisitor.transaction.Transactional;

@Transactional(
propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.READ_COMMITTED
)
public void writeAuditLog(long orderId, String action) throws java.sql.SQLException {
jdbcTemplate.executeUpdate(
"insert into order_audit(order_id, action) values(?, ?)",
new Object[] { orderId, action }
);
}

When invoked within an outer transaction, this method suspends it and starts an independent transaction on a new connection. This suits audit logs or operation records that should commit independently even if the outer transaction fails.

Control Rollback Rules​

By default, exceptions from business methods trigger rollback. Use noRollbackFor or noRollbackForClassName to exclude specific exceptions:

Retain the attempt record when stock validation fails
@Transactional(noRollbackFor = { IllegalArgumentException.class })
public void reserveStock(long skuId, int quantity) throws java.sql.SQLException {
jdbcTemplate.executeUpdate(
"insert into stock_try_log(sku_id, quantity) values(?, ?)",
new Object[] { skuId, quantity }
);

if (quantity <= 0) {
throw new IllegalArgumentException("quantity must be positive");
}
}

IllegalArgumentException still propagates, but this exception does not mark the transaction for rollback.

Annotation Attributes​

AttributeTypeDefaultDescription
propagationPropagationREQUIREDHow to join, create, or suspend transactions
isolationIsolationDEFAULTDatabase isolation level
readOnlybooleanfalseMark read-only; dbVisitor rolls back when commit is requested
noRollbackForClass<? extends Throwable>[]{}Exception types that do not trigger rollback
noRollbackForClassNameString[]{}Fully qualified exception names that do not trigger rollback

Further Reading​

  • Propagation: Choose between REQUIRED, REQUIRES_NEW, and NESTED.
  • Isolation: Decide when to set an explicit isolation level.
  • Cross-API Transactions: Mix JdbcTemplate, Mapper, and the builder API within an annotated transaction.