Как сохранить уникальный ключ, сгенерированный в сущности JPA с помощью ValueGenerator, в нескольких экземплярах приложения springmvc во время балансировки нагрузки

#spring-mvc #jpa #oracle11g #spring-data-jpa #multiple-instances

#spring-mvc #jpa #oracle11g #spring-data-jpa #несколько экземпляров

Вопрос:

У меня есть объект jpa, у которого уже есть идентификатор, сгенерированный как uuid, и требуется еще один уникальный читаемый человеком идентификатор. итак, я сгенерировал ref_key с ValueGenerator помощью .

 @Id@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "uuid-char")@Column(name="ID")
private UUID id;

@GeneratorType(type = UniqueIdGenerator.class, when = GenerationTime.INSERT)
@Column(name = "REF_KEY", updatable = false, insertable = true, unique = true, nullable = false)
private String refKey;
  

Для генерации этого уникального ref_key я использовал временную метку и простой счетчик. Код приведен ниже

 public class UniqueIdGenerator implements ValueGenerator {

    private static volatile String lastTimestamp = "";
    private static volatile int counter = 1;
    private String valuePrefix = "UNI_";

    @Override
    public String generateValue(Session session, Object owner) {
        return generateUniqueId(valuePrefix);
    }

    private static synchronized String generateUniqueId(String prefix) {
        String id;
        Date dNow = new Date();
        SimpleDateFormat ft = new SimpleDateFormat("yyMMdd_HHmmss");
        String datetimeId = ft.format(dNow);
        if (lastTimestamp.equalsIgnoreCase(datetimeId)) {
            id = prefix   datetimeId   "_"   counter;
            counter  ;
        } else {
            id = prefix   datetimeId;
            counter = 1;
        }
        lastTimestamp = datetimeId;
        return id;
    }
}
  

Все это отлично работает с одним экземпляром. Но для этого приложения для балансировки нагрузки развертывается несколько экземпляров, поэтому очень высока вероятность того, что один и тот же идентификатор будет сгенерирован и вставлен в БД в один и тот же момент. Как я могу избежать получения дубликатов в БД? Какой может быть лучший подход?

В БД использовался Oracle 11g.

Я попробовал несколько разных вещей, прежде чем перейти к этому подходу, например, используя последовательность из конца базы данных, но это не сработало, и вся часть модели / объекта упаковывается отдельно, я не смог попасть в БД из этой части. Что еще можно сделать, чтобы создать уникальное значение счетчика и вставить его в БД в соответствии с экземплярами. Пожалуйста, помогите.

Комментарии:

1. «Мне не удалось попасть в БД из этой части» — см. Эту статью о том, как «попасть в БД»

2. Спасибо crizzis, я также реализовал все из этой статьи, та же реализация не работала для меня. Этот генератор последовательностей работает с аннотацией @Id. И в моем случае Id уже был доступен. итак, GenericGenrator не сработал.

3. Достаточно справедливо, но generateValue дает вам доступ к Session значению, что вы можете выполнить буквально любой запрос, который вам нравится. Просто используйте session.createSQLQuery("SELECT mySequence.NEXTVAL FROM dual")

4. пробовал и это, crizzis, но это не сработало, насколько я помню, я получал исключение SQL с недопустимыми идентификаторами, пытаясь получить список результатов или uniqueResult и т. Д. Пробовал CreateQuery, CreateSQLQuery, createNativeQuery… но ничего не сработало.

5. Ну, если вы получаете «недопустимый идентификатор», это означает, что вы пытаетесь получить доступ к объекту БД, который не существует. НО это также означает, что вам только что удалось получить доступ к БД. Вам просто нужно выдать действительный запрос.