будьте в спящем режиме вопрос об уникальности столбца

Я нахожусь все еще в процессе изучения hibernate/hql, и у меня есть вопрос, это - половина проверки работоспособности вопроса/половины о лучших практиках.

Скажем, у меня есть класс A:

@Entity
public class A
{
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    @Column(unique=true)
    private String name = "";

    //getters, setters, etc. omitted for brevity
}

Я хочу осуществить тот каждый экземпляр, который сохраняется, имеет уникальное имя (следовательно @Column аннотация), но я также хочу смочь обработать случай, где уже существует, экземпляр сохранил, который имеет то имя. Я вижу два способа сделать это:

1) Я могу поймать org.hibernate.exception. ConstraintViolationException, который мог быть брошен во время session.saveOrUpdate () вызов и попытка обработать его.

2) Я могу запросить для существующих экземпляров, которые уже имеют то имя в ДАО прежде, чем назвать session.saveOrUpdate ().

Прямо сейчас я склоняюсь к подходу 2, потому что в подходе 1 я не знаю, как программно выяснить, какое ограничение было нарушено (существует несколько других уникальных участников в A). Прямо сейчас мой DAO.save () код примерно походит на это:

public void save(A a) throws DataAccessException, NonUniqueNameException
{
    Session session = sessionFactory.getCurrentSession();

    try
    {
        session.beginTransaction();

        Query query = null;

        //if id isn't null, make sure we don't count this object as a duplicate
        if(obj.getId() == null)
        {
            query = session.createQuery("select count(a) from A a where a.name = :name").setParameter("name", obj.getName());
        }
        else
        {
            query = session.createQuery("select count(a) from A a where a.name = :name " + 
                "and a.id != :id").setParameter("name", obj.getName()).setParameter("name", obj.getName());
        }

        Long numNameDuplicates = (Long)query.uniqueResult();
        if(numNameDuplicates > 0)
            throw new NonUniqueNameException();

        session.saveOrUpdate(a);
        session.getTransaction().commit();
    }
    catch(RuntimeException e)
    {
            session.getTransaction().rollback();
            throw new DataAccessException(e); //my own class
    }
}

Я иду об этом правильным способом? Может быть в спящем режиме говорят мне программно (т.е. не как строка ошибки), какое значение нарушение является ограничением уникальности? Путем разделения запроса от фиксации я приглашаю ошибки потокобезопасности, или действительно ли я в безопасности? Как это обычно делается?

Спасибо!

6
задан Seth 22 March 2010 в 21:23
поделиться

2 ответа

Я думаю, что ваш второй подход является лучшим.

Чтобы с уверенностью перехватить исключение ConstraintViolation, вызванное этим конкретным объектом, вам придется очистить сессию сразу после вызова saveOrUpdate. Это может вызвать проблемы с производительностью, если вам нужно вставить несколько таких объектов за один раз.

Даже если вы будете проверять, существует ли уже имя в таблице при каждом сохранении, это все равно будет быстрее, чем промывка после каждой вставки. (Для подтверждения всегда можно использовать контрольную точку)

Это также позволяет структурировать код таким образом, чтобы можно было вызывать "валидатор" с другого уровня. Например, если уникальным свойством является адрес электронной почты нового пользователя, из веб-интерфейса вы можете вызвать метод валидации, чтобы определить, является ли адрес электронной почты приемлемым. Если бы вы выбрали первый вариант, вы бы узнали, является ли адрес электронной почты приемлемым, только после попытки его вставить.

3
ответ дан 17 December 2019 в 07:02
поделиться

Подход 1 будет приемлемым, если:

  • В объекте есть только одно ограничение.
  • В сеансе есть только один грязный объект.

Помните, что объект не может быть сохранен до тех пор, пока не будет вызвана flush () или пока транзакция не будет зафиксирована.

Для лучшего сообщения об ошибках я бы:

  1. Используйте подход два для каждого нарушения ограничения, поэтому я могу указать конкретную ошибку для каждого из них.
  2. Реализуйте перехватчик, который в случае исключения ограничения повторяет транзакцию (максимальное количество раз), поэтому нарушение не может быть обнаружено ни в одном из тестов. Это необходимо только в зависимости от уровня изоляции транзакции.
1
ответ дан 17 December 2019 в 07:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: