Spring Propagation.REQUIRES_NEW @Transaction commit появляется в журнале только после завершения внешней транзакции

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

@Override
@Transactional
public DataProcessingStatistics copyInitialRevision() {
    try {
        DataProcessingStatistics statistics = new DataProcessingStatistics();
        transaction(statistics);
        statistics.printResult();
        return statistics;
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)  
public void transaction(DataProcessingStatistics statistics) {
    entityAuditTableService.generateTables(statistics);
    oneToManyRelationAuditTableService.generateTables(statistics);
    manyToManyRelationAuditTableService.generateTables(statistics);
}

...

 @Service
 public class EntityAuditTableServiceImpl implements EntityAuditTableService {
...

@Override
public void generateTables(DataProcessingStatistics statistics) {
    List<EntityAuditTable> auditTables = loadAll();
    for (EntityAuditTable auditTable : auditTables) {
        try {
            statistics.addAsProcessed(auditTable, process(auditTable));
        } catch (Exception e) {
            statistics.addAsSkipped(auditTable.getAuditTable(), e);             
        }
    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public int process(EntityAuditTable auditTable) {
    EntityDataTable table = entityDataTableService.create(auditTable.getEntityDataTable().getEntityClass());
    List<EntityDataTableRow> rows = entityDataTableService.readAllData(table);
    List<EntityAuditTableRow> auditTableRows = entityAuditTableRowService.generateTableData(auditTable, rows);
    entityAuditTableRowService.saveAll(auditTableRows);
    return auditTableRows.size();
}

...


 @Service
 public class EntityAuditTableRowServiceImpl implements EntityAuditTableRowService {

...


@Override
@Transactional
public void saveAll(List<EntityAuditTableRow> auditTableRows) {
    jdbcService.saveArraysAs500RowChunks(auditTableRows, new ListSaver<EntityAuditTableRow>(){
        @Override
        public void save(List<EntityAuditTableRow> list) {
            EntityAuditTableRowServiceImpl.this.saveJdbc(list);
            for (EntityAuditTableRow auditTableRow: list) {
                entityChangeService.saveFromRow(auditTableRow);
            }
        }
    });
}

...


@Service
public class JdbcServiceImpl implements JdbcService {

@Override
public <E> void saveArraysAs500RowChunks(List<E> rows, ListSaver<E> saver) {
    for (int i = 0; i < rows.size(); i += 500) {
        save500(rows.subList(i, Math.min(i +500, rows.size())), saver);
    }
}

@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public <E> void save500(final List<E> rows, ListSaver<E> saver) {
    if (rows == null || rows.size() == 0) {
        return;
    }
    if (rows.size() > 500) {
        throw new IllegalStateException("(auditTableRows.size() > 500)");
    }
    saver.save(rows);
}   

...

@Service
public class EntityChangeServiceImpl implements EntityChangeService {


@Override
@Transactional
public void saveFromRow(EntityAuditTableRow auditTableRow) {
    Revision revision = revisionsService.load(auditTableRow.getAuditTableRow().getRevision().getId());
    EntityChange entityChange = create(auditTableRow);
    save(entityChange);
    revision.getEntitiesChanges().add(entityChange);
    revisionsService.save(revision);
}

...
@Service
public class RevisionServiceImpl implements RevisionService {

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Revision create() {
    Revision revisionEntity = createDetached();
    long generateNextIdForClass = idService.generateNextIdForClass(Revision.class);
    revisionEntity.setId(generateNextIdForClass);
    revisionEntity.setTimestamp(new Date());
    save(revisionEntity);
    return revisionEntity;
}

@Override
@Transactional
public void save(Revision revisionEntity) {
    persistenceManagerHibernate.save(revisionEntity);
}

Дело в том, что только после возврата из корневого/начального вызова метода я получаю вставки в журналы для таблицы ENTITY_CHANGED_IN_REVISION/объекта EntityChange:

эта точка:

@Override
@Transactional
public DataProcessingStatistics copyInitialRevision() {
    try {
        DataProcessingStatistics statistics = new DataProcessingStatistics();
        transaction(statistics);
        statistics.printResult();
        return statistics; // only after that return insert log appear
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

эти журналы появляются только после возврата:

Hibernate: insert into ENTITY_CHANGED_IN_REVISION (ENTITY_ID, ENTITY_NAME, GROUP_ENTITY_ID, GROUP_NAME, REV_ID, REVISION_TYPE, ID) values (?, ?, ?, ?, ?, ?, ?)

Hibernate: insert into ENTITY_CHANGED_IN_REVISION (ENTITY_ID, ENTITY_NAME, GROUP_ENTITY_ID, GROUP_NAME, REV_ID, REVISION_TYPE, ID) values (?, ?, ?, ?, ?, ?, ?)

Hibernate: insert into ENTITY_CHANGED_IN_REVISION (ENTITY_ID, ENTITY_NAME, GROUP_ENTITY_ID, GROUP_NAME, REV_ID, REVISION_TYPE, ID) values (?, ?, ?, ?, ?, ?, ?)

Hibernate: insert into ENTITY_CHANGED_IN_REVISION (ENTITY_ID, ENTITY_NAME, GROUP_ENTITY_ID, GROUP_NAME, REV_ID, REVISION_TYPE, ID) values (?, ?, ?, ?, ?, ?, ?)

Hibernate: insert into ENTITY_CHANGED_IN_REVISION (ENTITY_ID, ENTITY_NAME, GROUP_ENTITY_ID, GROUP_NAME, REV_ID, REVISION_TYPE, ID) values (?, ?, ?, ?, ?, ?, ?)

Hibernate: insert into ENTITY_CHANGED_IN_REVISION (ENTITY_ID, ENTITY_NAME, GROUP_ENTITY_ID, GROUP_NAME, REV_ID, REVISION_TYPE, ID) values (?, ?, ?, ?, ?, ?, ?)

Вместо того, чтобы возвращать их после возврата из метода «сохранить 500 строк», который является @Transactional (propagation = Propagation.REQUIRES_NEW):

@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public <E> void save500(final List<E> rows, ListSaver<E> saver) {
    if (rows == null || rows.size() == 0) {
        return;
    }
    if (rows.size() > 500) {
        throw new IllegalStateException("(auditTableRows.size() > 500)");
    }
    saver.save(rows); // invokes EntityChangeServiceImpl.saveFromRow
}   

...

@Service
public class EntityChangeServiceImpl implements EntityChangeService {


@Override
@Transactional
public void saveFromRow(EntityAuditTableRow auditTableRow) {
    Revision revision = revisionsService.load(auditTableRow.getAuditTableRow().getRevision().getId());
    EntityChange entityChange = create(auditTableRow);
    save(entityChange);
    revision.getEntitiesChanges().add(entityChange);
    revisionsService.save(revision);
}

person Vyacheslav    schedule 23.01.2012    source источник


Ответы (2)


Транзакционный метод класса вызывает другой транзакционный метод этого класса без прокси, поэтому транзакция второго метода не используется при вызове.

person Vyacheslav    schedule 09.08.2012

Чтобы применить @Transactional и, таким образом, открыть его, выполнение должно быть выполнено через proxy.

person ssedano    schedule 08.08.2012