У меня есть следующая сущность:
@Entity
@Table(name = "product",
indexes = {@Index(name = "productIndex", columnList = "family, group, type", unique = true)})
public class Product implements Serializable {
@Id
@Column(name = "id")
private Long id;
@Column(name = "family")
private String family;
@Column(name = "group")
private String group;
@Column(name = "type")
private String type;
}
И я пытаюсь очистить свою таблицу базы данных и вставить новые строки:
@Transactional
public void update(List<Product> products) {
productRepository.deleteAll();
productRepository.batchInsert(products);
}
ProductRepository это:
public interface ProductRepository extends JpaRepository<Product, Long>, BatchRepository<Product> { }
И BatchRepository:
@Repository
public class BatchRepository<T> {
@PersistenceContext
private EntityManager entityManager;
@Override
public int batchInsert(List<T> entities) {
int count = 0;
for (T entity : entities) {
entityManager.persist(entity);
count++;
if (count % 2000 == 0) {
entityManager.flush();
entityManager.clear();
}
}
entityManager.flush();
entityManager.clear();
return count;
}
}
Попытка выполнить вставку не удалась с java.sql.BatchUpdateException: ORA-00001: unique constraint (productIndex) violated, но не должно ли предыдущее удаление сделать это нарушение невозможным?
@Transactional
public void update(List<Product> products) {
productRepository.deleteAll();
insertProducts(products);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertProducts(List<Product> products) {
productRepository.batchInsert(products);
}




По моему мнению, вы должны выполнять операцию deleteAll() отдельно, поскольку вы используете аннотацию @Transactional, и изменения не фиксируются до тех пор, пока аннотированная функция не вернется успешно. Из-за этого ваши первичные ключи все еще дублируются.
Вы можете написать другой метод для вставки данных и добавить к нему аннотацию @Transactional(propagation = Propagation.REQUIRES_NEW). Затем вызовите метод в вашем методе update(...).
ваше предложение не работает
Не могли бы вы поделиться фрагментом кода, как вы его реализовали.
обновил вопрос с ним!
Вы получаете эту ошибку, потому что вы поместили уникальное ограничение в индекс таблицы "productIndex"
Вы пытаетесь удалить все записи в первой строке
@Transactional
public void update(List<Product> products) {
productRepository.deleteAll();
productRepository.batchInsert(products);
}
но я думаю, что записи остаются в индексе с именем "productIndex"
да, это в основном то, что происходит, но я также ищу способ обновить эту индексную таблицу... Я думал, что это было автоматически обработано
Можете ли вы попробовать этот код
public void update(List<Product> products) {
deleteAll()
insertProducts(products);
}
@Transactional
public void deleteAll() {
productRepository.deleteAll();
}
@Transactional
public void insertProducts(List<Product> products) {
productRepository.batchInsert(products);
}
с этим кодом удаление выполняется, даже если вставка не удалась. Это не то, чего я хочу
Я думаю, что нашел несколько ответов, которые решают вашу проблему.
Аннотируйте свой транзакционный метод следующим образом:
@Modifying(flushAutomatically = true)
Это обеспечит сброс вызова deleteAll, т.е. индексы обновляются перед следующим вызовом batchInsert.
Используйте deleteAllInBatch из JpaRepository вместо deleteAll.
Вручную вызовите flush после deleteAll в транзакционном методе.
Более специализированным SQL-решением будет пакетная вставка новых записей во временную таблицу. Тогда вы можете либо:
product и переименуйте временную в product.SELECT * FROM #temp_table INTO product - поместить все записи из временной таблицы в product.Дайте мне знать, если что-то из этого работает. Удачи!
решение 2 работает! Спасибо!
это, вероятно, так, но я делаю и то, и другое в одной и той же транзакции, потому что я хочу, чтобы она отменяла изменения в случае возникновения какой-либо ошибки. Есть ли способ обновить индексы?