У меня есть база данных снежинок, и она не поддерживает принудительное применение уникальных ограничений (https://docs.snowflake.com/en/sql-reference/constraints-overview.html).
Я планирую использовать метод в репозитории JPA с настраиваемым SQL-запросом для проверки дубликатов перед вставкой в таблицу.
сущность
@Entity
@Table(name = "STUDENTS")
public class Students {
@Id
@Column(name = "ID", columnDefinition = "serial")
@GenericGenerator(name = "id_generator", strategy = "increment")
@GeneratedValue(generator = "id_generator")
private Long id;
@Column(name = "NAME")
private String studentName;
}
Запрос на создание таблицы Snowflake
CREATE table STUDENTS(
id int identity(1,1) primary key,
name VARCHAR NOT NULL,
UNIQUE(name)
);
Репозиторий
public interface StudentRepository extends JpaRepository<Students, Long> {
//
@Query(value = "???", nativeQuery = true)
List<Student> bulkUpsertStudents(List<Student> students);
}




Вы можете использовать запрос SELECT для проверки повторяющихся значений в столбце name перед вставкой новой записи в таблицу. Например:
@Query(value = "SELECT * FROM STUDENTS WHERE name = :name", nativeQuery = true)
List<Student> findByName(@Param("name") String name);
Этот метод вернет список Student записей с указанным name значением. Если список пуст, это означает, что записей с таким значением name нет, и вы можете смело вставлять новую запись с этим значением name.
List<Student> studentList = new ArrayList<>();
for (Student student : students) {
List<Student> existingStudents = studentRepository.findByName(student.getName());
if (existingStudents.isEmpty()) {
studentsToInsert.add(student);
}
}
studentRepository.bulkUpsertStudents(studentList)
Если вышеуказанное решение не работает. Вы можете использовать оператор MERGE для обновления существующих записей в таблице, если данные изменились. Например, если вы хотите обновить имя Student, если оно изменилось, вы можете использовать следующий оператор MERGE:
@Query(value = "MERGE INTO students t USING (SELECT :name AS name, :newName AS newName) s
ON t.name = s.name
WHEN MATCHED AND t.name <> s.newName THEN UPDATE SET t.name = s.newName
WHEN NOT MATCHED THEN INSERT (name) VALUES (s.name)", nativeQuery = true)
List<Student> bulkUpsertStudents(List<Student> students);
Этот запрос обновит имя каждого Student в списке students, если оно изменилось, и в случае конфликта не будет вставлять новую запись. Это гарантирует, что в таблицу вставляются только уникальные значения имен, без необходимости выполнять отдельный запрос для каждой записи.
Получение этой ошибки: объект ссылается на несохраненный переходный экземпляр - сохраните переходный экземпляр перед очисткой при втором подходе
Хорошо, я понимаю, что обновил код, можете ли вы проверить сейчас?
НА КОНФЛИКТ НИЧЕГО НЕ ДЕЛАТЬ; не поддерживается снежинкой Я искал что-то похожее на это
Мне удалось преодолеть это, используя приведенный ниже подход, но мне нужно проверить производительность запросов.
Метод репозитория saveAll() для сохранения всех сущностей.
Использование пользовательского nativeQuery, как показано ниже.
INSERT OVERWRITE INTO STUDENTS
WITH CTE AS(SELECT ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY ID) AS RNO, ID, NAME FROM STUDENTS)
SELECT ID, NAME FROM CTE WHERE RNO = 1;
Пример кода:
import static io.vavr.collection.List.ofAll;
import static io.vavr.control.Option.of;
import static java.util.function.Predicate.not;
public Validation<ValidationError, List<Students>> saveAll(List<String> students) {
return of(students)
.filter(not(List::isEmpty))
.map(this::mapToEntities) // maps the list to list of database entities
.map(repository::saveAll) // save all
.toValidation(ERROR_SAVING_STUDENTS) // vavr validation in case of error
.peek(x -> repository.purgeStudents()) // purging to remove duplicates
.toValidation(ERROR_PURGING_STUDENTS);
}
Эта проблема возникает только из-за того, что снежинка не может проверить уникальность.
Это вызовет запрос выбора для каждой записи в базу данных. Представьте, что если есть 1000 студенческих записей, будет запущено 1000 запросов. Я думал, есть ли какая-то
insert on conflictподдержка