org.hibernate.id.IdentifierGenerationException:尝试从空的一对一属性分配 id(使用 session.merge)

org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property (with session.merge)

我有问题。 我的应用出现错误:org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property

我的pojos 用户:

@Entity
@Table(name = "user")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User implements Serializable {
private static final long serialVersionUID = -5415891222321582213L;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "userId", length = 100)
private int userId;
...
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private UserDetail userDetail;

用户详细信息:

@Entity
@Table(name = "userdetail")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class UserDetail implements Serializable {
private static final long serialVersionUID = 2155190440305692224L;

@Id
@GenericGenerator(
    name = "gen",
    strategy = "foreign",
    parameters = @Parameter(name = "property", value = "user")
    )
@GeneratedValue(generator = "gen")
@Column(name = "userId", length = 100)
private int userId;
...
@OneToOne
@PrimaryKeyJoinColumn
private User user;

表用户:

CREATE TABLE `user` (
    `userId` INT(100) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NULL DEFAULT NULL,
    `surname` VARCHAR(255) NULL DEFAULT NULL,
    `email` VARCHAR(255) NULL DEFAULT NULL,
    `password` VARCHAR(255) NULL DEFAULT NULL,
    PRIMARY KEY (`userId`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

表用户详细信息

CREATE TABLE `userdetail` (
    `userId` INT(100) NOT NULL,
    `country` VARCHAR(255) NULL DEFAULT NULL,
    `city` VARCHAR(255) NULL DEFAULT NULL,
    `address` VARCHAR(255) NULL DEFAULT NULL,
    PRIMARY KEY (`userId`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

DAO层:

private Session session = HibernateUtil.getHibernateUtil().getSession();
@Override
public void create(T t) throws DaoException {
        Object object = session.merge(t);
        session.save(object);
        log.info("Update: " + t);
}

服务层

private Session session = HibernateUtil.getHibernateUtil().getSession();
private Transaction transaction = null;
private Dao<T> dao = new BaseDao<T>();
@Override
public void create(T t) throws DaoException {
    try {
        transaction = session.beginTransaction();
        dao.create(t);
        transaction.commit();
        log.info("Create: " + t);
    } catch (HibernateException e) {
        log.error("Error creating " + getPersistentClass() + " in Dao " + e);
        transaction.rollback();
        throw new DaoException(e);
    }
}

保存用户的类

User user = new User(name, surname, email, password);
UserDetail userDetail = new UserDetail(country, city, address);
user.setUserDetail(userDetail);
userDetail.setUser(user);
userService.create(user);

HiberUtil

public class HibernateUtil {
    private static Logger log = Logger.getLogger(HibernateUtil.class);
    private static HibernateUtil util = null;
    private static SessionFactory sessionFactory = null;
    private static final ThreadLocal<Session> sessions = new ThreadLocal<Session>();

    private HibernateUtil() {
        try {
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        log.info("Hibernate Configuration loaded");
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
        log.info("Hibernate serviceRegistry created");
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        } catch (Throwable e) {
            log.error("Initial SessionFactory creation failed. " + e);
            System.exit(0);
        }
    }

    public Session getSession () {
        Session session = sessions.get();
        if (session == null) {
            session = sessionFactory.openSession();
            sessions.set(session);
        } 
        return session;
    }

    public static synchronized HibernateUtil getHibernateUtil(){
        if (util == null){
            util = new HibernateUtil();
        }
        return util;
    }
}

如果我在 DAO 层中更改:

@Override
public void create(T t) throws DaoException {
        session.save(t);
        log.info("Create: " + t);
}

我收到错误:org.hibernate.HibernateException:非法尝试将集合与两个打开的会话相关联

所以我有 4 个问题:

  1. 如果我没理解错的话,当userdeteil save userId from User 为null 因为UserId 没有从表中获取icnrement Id,是真的吗?

  2. 是否需要session.merge

  3. 如果需要合并,如何正确org.hibernate.id.IdentifierGenerationException:试图从空的一对一属性分配 id

  4. 如果不需要合并,正确度如何"org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions"

注意:删除与合并是好的,创建与合并其他实体(不是用户也不是 UserDeteil)是好的。

要使其正常工作,请从您的 DAO class 的更新方法中删除 Object object = session.merge(t);。这是更新的更新方法

@Override
public void update(T t) throws DaoException {
        session.saveOrUpdate(t);
        log.info("Update: " + t);
}

这将修复您的 org.hibernate.id.IdentifierGenerationException 异常。

  • 对于第 1 点:您的记录未保存,您正在调用 merge() 方法,则传入merge方法的对象return 保存(这里)。 merger():将给定对象的状态复制到 具有相同标识符的持久对象。在你的情况下没有 持久对象。
  • 对于第2点:这里不需要merge方法,使用save或者 session
  • 的 saveOrUpdate 方法
  • 对于第 3 点:N/A

这里有一个很好的例子One-To-One association mapping

我解决了我的问题。 在我的 BaseDao 和 BaseService 中,我删除了:

private Session session = HibernateUtil.getHibernateUtil().getSession();

我在 BaseDao 和 BaseService 中添加了所有方法:

HibernateUtil.getHibernateUtil().getSession();

所以我删除了这两个会话 我的方法,示例创建,变成了:

@Override
public void create(T t) throws DaoException {
        HibernateUtil.getHibernateUtil().getSession().save(t);
        log.info("Create: " + t);
}