У меня есть транзакционные методы, вызывающие друг друга, но кажется, что транзакция фиксируется после того места, где она должна быть зафиксирована, или после этого появляются по крайней мере журналы вставки. Вот иероглиф вызова:
@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.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);
}