Hibernate: сгенерированный идентификатор остается в непостоянном объекте после исключения SQLIntegrityConstraintViolationException - PullRequest
0 голосов
/ 25 сентября 2018

Привет всем!

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

Пример теста (весенняя загрузка + hibernate + база данных oracle):

@Entity
@SequenceGenerator(name = "TEST_ENTITY_GENERATOR", allocationSize = 1, sequenceName = "TEST_ENTITY_SEQ")
public class TestEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TEST_ENTITY_GENERATOR")
    private Long id;

    @Column(nullable = false)
    private String name;

    public Long getId() {
        return id;
    }
}

@Repository
public interface TestEntityRepository extends JpaRepository<TestEntity, Long> {

}


@RunWith(SpringRunner.class)
@SpringBootTest
public class RemainingIdTest {

    @Autowired
    private TestEntityRepository testEntityRepository;

    @Test
    public void test() {
        TestEntity entity = new TestEntity();
        try {
            Assertions.assertThat(entity.getId()).isNull();
            testEntityRepository.save(entity);
            Assertions.fail("Save must fail");
        } catch (DataIntegrityViolationException e) {
            Assertions.assertThat(entity.getId()).isNotNull();
        }
    }
}

1 Ответ

0 голосов
/ 25 сентября 2018

Возможное решение - использовать org.hibernate.event.spi.PreInsertEventListener, где мы можем связать транзакцию с процессором, который очистит вашу сущность в случае сбоя транзакции.

Пример:

@Component
public class IdentifierCleaner implements PreInsertEventListener {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @PostConstruct
    private void init() {
        SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
        EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
        registry.getEventListenerGroup(EventType.PRE_INSERT).appendListener(this);
    }

    @Override
    public boolean onPreInsert(PreInsertEvent event) {
        Object entity = event.getEntity();
        event.getSession().getActionQueue().registerProcess(((success, session) -> {
            if (!success) {
                event.getPersister().resetIdentifier(
                        entity,
                        event.getId(),
                        event.getPersister().getVersion(entity),
                        event.getSession()
                );
            }
        }));
        return false;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...