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

Hibernate瞬态实例异常解决:多对多关联持久化问题

已解决 - 更新内容

我删除了merge User的操作,不再将Room添加到User的rooms列表中。

public void save(Room room, User user) {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
        session.beginTransaction();
        room.getUsers().add(user);
        session.merge(room);
        session.getTransaction().commit();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        session.close();
    }
}

并在RoomRepository外部更新User实例,以获取最新的User对象:

public void updateUser() {
    this.user = userRepository.updateUser(user);
}

UserRepository中的代码:

public User updateUser(User user) {
    User result = null;
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
        session.beginTransaction();
        result = session.get(User.class, user.getId());
        session.getTransaction().commit();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        session.close();
    }
    return result;
}

这可能不是最佳实践,我需要考虑如何重构这段代码。


问题描述

我有Room和User两个类,它们之间是多对多关联关系。

User类代码

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "users")
public Set<Room> rooms = new HashSet<>();

Room类代码

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "sala_usuario",
      joinColumns = @JoinColumn(name = "id_salas"),
      inverseJoinColumns = @JoinColumn(name = "cod_user"))
private Set<User> users = new HashSet<>();

异常堆栈信息

java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: model.Room
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:161)
at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:374)
at org.hibernate.query.sqm.internal.QuerySqmImpl.list(QuerySqmImpl.java:1073)
at org.hibernate.query.Query.getResultList(Query.java:94)
at repository.MessageRepository.findRoomMessages(MessageRepository.java:41)
at app.ChatController.loadMessages(ChatController.java:123)
at app.ChatController.lambda$initialize$0(ChatController.java:45)

原RoomRepository的save方法

public void save(Room room, User user) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        try {
            session.beginTransaction();
            user.getRooms().add(room);
            room.getUsers().add(user);
            session.merge(room);
            session.merge(user);
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
}

当用户打开Room并尝试通过一对多关联获取消息时触发该异常,尽管Room实例已持久化,但Hibernate仍认为它是瞬态的。

原ORM查询方法

public List<Message> findRoomMessages(Room room) {
        List<Message> result = null;
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        try {
            session.beginTransaction();
            CriteriaBuilder cb = session.getCriteriaBuilder();
            CriteriaQuery<Message> query = cb.createQuery(Message.class);
            Root<Message> root = query.from(Message.class);
            query.select(root).where(cb.equal(root.get("room"), room));
            result = session.createQuery(query).getResultList();
            session.getTransaction().commit();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            session.close();
        }
        return result;
    }

原生SQL临时解决方法

public List<Message> findRoomMessages(Room room) {
        List<Message> result = null;
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        try {
            session.beginTransaction();
            result = session.createNativeQuery("SELECT * FROM mensajes WHERE id_sala = :pid_sala", Message.class)
                            .setParameter("pid_sala", room.getId()).list();
            session.getTransaction().commit();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            session.close();
        }
        return result;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 03:15:41