You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate NonUniqueObjectException求助:关联已有警员至多张罚单时报错

Fixing Hibernate NonUniqueObjectException When Reusing Existing Entities

Hey there! Let's break down why you're running into that NonUniqueObjectException and how to fix it. This error usually pops up when Hibernate's Session detects two different object instances with the same database identifier (OID) — which violates its first-level cache rules, and it's super common when reusing existing entities for associations like your Cop-Ticket scenario.

Common Causes in Your Scenario

  • Re-saving a persistent entity: If you've already loaded a Cop from the database (it's in persistent state within the current Session) and then call save() or persist() on it again, Hibernate freaks out because it already tracks that instance.
  • Using a detached entity for association: If your Cop instance comes from a closed Session (it's detached) and you try to associate it with a new Ticket in a fresh Session, Hibernate might already have another instance of that Cop loaded, causing a conflict.
  • Incorrect DAO methods: Your DAO might be using save() universally, even for entities that already exist in the database.

Step-by-Step Solutions

1. Match Method to Entity State

Hibernate entities have three core states, and you need to use the right method for each:

  • Transient (new entity, no ID): Use save() or persist() to create it in the database.
  • Persistent (already tracked by Session): You don't need to call save() at all! Just modify the entity's properties, and Hibernate will automatically sync changes to the database when the Session flushes.
  • Detached (was persistent, but Session closed): Use merge() to copy the detached entity's state into a persistent instance that Hibernate can track.

2. Update Your DAO Logic

Tweak your DaoCop (and Ticket DAO) to handle existing entities properly. For example:

public class DaoCop {
    private Session session;

    public DaoCop(Session session) {
        this.session = session;
    }

    public Cop saveOrUpdateCop(Cop cop) {
        if (cop.getId() == null) {
            // New entity, save to database
            session.save(cop);
        } else {
            // Existing entity: merge if detached, sync if persistent
            cop = (Cop) session.merge(cop);
        }
        return cop;
    }

    // Load existing Cop by ID (returns persistent entity tracked by Session)
    public Cop getCopById(Long copId) {
        return session.get(Cop.class, copId);
    }
}

3. Properly Associate Existing Cop with Multiple Tickets

When linking an existing Cop to new Tickets, make sure you're using a persistent instance of the Cop in the current Session:

// Open a new Session and start transaction
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

try {
    DaoCop daoCop = new DaoCop(session);
    DaoTicket daoTicket = new DaoTicket(session);

    // Load the existing Cop (persistent state, tracked by current Session)
    Cop existingCop = daoCop.getCopById(1L);

    // First Ticket: associate with the persistent Cop
    Ticket ticket1 = new Ticket();
    ticket1.setCop(existingCop);
    daoTicket.saveOrUpdateTicket(ticket1);

    // Second Ticket: use the SAME persistent Cop instance
    Ticket ticket2 = new Ticket();
    ticket2.setCop(existingCop);
    daoTicket.saveOrUpdateTicket(ticket2);

    tx.commit();
} catch (Exception e) {
    tx.rollback();
    e.printStackTrace();
} finally {
    session.close();
}

If your Cop instance is detached (from a previous closed Session), merge it first before associating:

// Detached Cop from a closed Session
Cop detachedCop = ...;

// Merge into current Session to get a persistent instance
Cop persistentCop = (Cop) session.merge(detachedCop);

// Now associate persistentCop with Tickets as shown above

Key Takeaways

  • Never call save() on an entity that already exists in the database unless it's a brand-new transient instance.
  • Always use persistent entities (loaded in the current Session) for associations to avoid conflicts.
  • Use merge() for detached entities to sync their state with the Session's tracked instance.

内容的提问来源于stack exchange,提问作者Riley Christian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:30:43