2014-09-25 4 views
0

У меня есть веб-служба, которая хранит данные, и один из методов должен быть в транзакции базы данных. По сути, это выглядит следующим образом:Какую аннотацию использовать для обертывания метода в транзакции базы данных

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 на уровне базы данных?

+0

Что такое 'sql'? Вероятно, он не включен в текущую транзакцию. Вы считали, что вместо этого использовали управляемый JTA EntityManager? – Benjamin

+0

@Benjamin Я использую JOOQ, а 'sql' - это, по сути, тонкая оболочка вокруг« DataSource ». Соединение предоставляется '@Resource (lookup =" java: jboss/jdbc/ws ") private javax.sql.DataSource postgres;'. Я никогда не использовал JTA, поэтому не уверен, что он приносит. Есть ли способ зарегистрировать источник данных для текущей транзакции? – assylias

+0

JTA предоставляет управление транзакциями, 'TransactionSynchronizationRegistry' является частью JTA.Если ваш источник данных объявлен с включенным JTA в wildfly: '', тогда он должен работать. В противном случае я не знаю, что делает ваша обертка JOOQ, которую вы используете ... Вы можете попробовать напрямую с использованием источника данных? – Benjamin

ответ

1

Убедитесь, что ваш источник данных объявляется с JTA включен в wildfly:

<datasource jta="true" jndi-name="java:jboss/jdbc/ws" ...> 
1

Я вообще разделяю логику базы данных на разные фасады.

@Stateless 
public void DBFacade{ 

    @TransactionAttribute(REQUIRES_NEW(
    public void doSomethingIntransaction(){} 
} 

@Stateless 
@Path("/path") 
public class MyFrontendService{ 
    @EJB 
    private DBFacade dbFacade; 

    @PUT 
    @Path("upsert_symbology") 
    @Consumes(MediaType.APPLICATION_JSON) 
    public void updateUserData(){ 
    dbFacade.doSomething(); 
    } 

} 

Зачем вам это делать? Потому что, если вы не хотите, контейнер не будет перехватывать вызов batchUsert(), так как вы напрямую обращаетесь к методу. Однако, если вы используете ejb-инъекцию, инъецированный экземпляр является прокси-сервером для фактического компонента, когда вы вызываете метод на прокси-сервере, он перехватывает контейнер, решает, требуется ли ему активная транзакция, а затем вызывает фактический метод, который он выполняет ссылка. Это единственный способ ejb. Вы должны делегировать фактический вызов.

+0

Мой код работал как есть - проблема в том, что jta не была включена в источнике данных. – assylias

Смежные вопросы