У меня есть веб-служба, которая хранит данные, и один из методов должен быть в транзакции базы данных. По сути, это выглядит следующим образом:Какую аннотацию использовать для обертывания метода в транзакции базы данных
public abstract class ControllerBase {
//this is a method that needs to run in a transaction
void batchUpsert(/* ... */) {
try {
sql.query("BEGIN").execute();
sql.query("LOCK TABLE " + tableName + " IN EXCLUSIVE MODE").execute();
//do some stuff
} finally {
sql.query("COMMIT").execute();
}
}
}
И веб-служба определяются в классе к югу и вызывает метод выше:
@Path("symbology")
@Stateless
public class SymbologyController extends ControllerBase {
@PUT
@Path("upsert_symbology")
@Consumes(MediaType.APPLICATION_JSON)
public Response upsertSymbology(List<SymbologyRecord> symbology) {
batchUpsert(SYMBOLOGY, symbology, SYMBOLOGY.SHORT_NAME);
return Response.ok().build();
}
}
Это не чувствует себя хорошо, потому что часть сделки должна управляться на контейнере, а не на отправку BEGIN
и COMMIT
заявлений.
Так что я удалил их и добавил @TransactionAttribute
аннотацию на batchUpsert
метода:
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
void batchUpsert(/* ... */) {
sql.query("LOCK TABLE " + tableName + " IN EXCLUSIVE MODE").execute();
//do some stuff
}
Но контейнер (wildfly), кажется, не создавать транзакцию, и я получаю исключение:
ERROR: LOCK TABLE can only be used in transaction blocks
Я также пробовал аннотацию @TransactionAttribute
, но это тоже не сработало.
Как я могу позволить wildfly знать, что он должен обернуть мой метод в транзакции базы данных?
EDIT
Я просто понял, что статус транзакции активен:
@Resource TransactionSynchronizationRegistry tsr;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
void batchUpsert(/* ... */) {
LOG.info("Transaction active? {}", tsr.getTransactionStatus() == Status.STATUS_ACTIVE);
//...
}
выходы верно. Разве это не должно выполняться эквивалентом заявления BEGIN
на уровне базы данных?
Что такое 'sql'? Вероятно, он не включен в текущую транзакцию. Вы считали, что вместо этого использовали управляемый JTA EntityManager? – Benjamin
@Benjamin Я использую JOOQ, а 'sql' - это, по сути, тонкая оболочка вокруг« DataSource ». Соединение предоставляется '@Resource (lookup =" java: jboss/jdbc/ws ") private javax.sql.DataSource postgres;'. Я никогда не использовал JTA, поэтому не уверен, что он приносит. Есть ли способ зарегистрировать источник данных для текущей транзакции? – assylias
JTA предоставляет управление транзакциями, 'TransactionSynchronizationRegistry' является частью JTA.Если ваш источник данных объявлен с включенным JTA в wildfly: '', тогда он должен работать. В противном случае я не знаю, что делает ваша обертка JOOQ, которую вы используете ... Вы можете попробовать напрямую с использованием источника данных? –
Benjamin