有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java hibernate列唯一性问题

我仍在学习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)我能赶上火车。冬眠例外会话期间可能引发的ConstraintViolationException。saveOrUpdate()调用并尝试处理它

2)在调用会话之前,我可以在DAO中查询已具有该名称的现有实例。saveOrUpdate()

现在我倾向于方法2,因为在方法1中,我不知道如何通过编程来确定违反了哪一个约束(在一个模型中有几个其他唯一的成员)。现在是我的刀。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
    }
}

我这样做对吗?hibernate能否以编程方式(即不作为错误字符串)告诉我哪个值违反了唯一性约束?通过将查询与提交分离,我是在引发线程安全性错误,还是说我是安全的?这通常是怎么做的

谢谢


共 (2) 个答案

  1. # 1 楼答案

    如果:

    • 实体中只有一个约束
    • 会话中只有一个脏对象

    记住,在调用flush()或提交事务之前,对象可能不会被保存

    为了获得最佳的错误报告,我会:

    1. 对于每一个违反约束的情况,使用方法二,这样我就可以给出每个约束的具体错误
    2. 实现一个拦截器,在出现约束异常的情况下重试事务(最大次数),以便在其中一个测试中无法捕获违规行为。这仅取决于事务隔离级别
  2. # 2 楼答案

    我认为你的第二种方法是最好的

    为了能够捕获ConstraintViolation异常,并确定该特定对象导致了该异常,您需要在调用saveOrUpdate后立即刷新会话。如果需要一次插入多个这样的对象,这可能会带来性能问题

    即使您将在每次保存操作时测试表中是否已经存在该名称,但这仍然比每次插入后刷新要快。(您可以随时进行基准测试以确认。)

    这还允许您以一种可以从不同层调用“验证器”的方式来构造代码。例如,如果此唯一属性是新用户的电子邮件,则可以从web界面调用验证方法来确定电子邮件地址是否可接受。如果你选择第一个选项,你只有在尝试插入邮件后才知道它是否可以接受