【问题标题】:Hibernate Constraint Violation when persisting associated entities持久化关联实体时违反休眠约束
【发布时间】:2019-12-08 09:03:24
【问题描述】:

我正在为在线电影票务服务开发 Java Spring Web 应用程序。

用户拥有指定数量的积分,并且可以使用这些积分来支付部分门票。如果用户决定取消交易,他的积分将得到补偿。这些点移动称为 PointTransactions。

事务存储在事务表中,而 PointTransactions 存储在带有对父事务的引用的 pointTransactions 表中。

我在持久化在同一方法上引用新事务实体的 PointTransaction 实体时遇到问题。

这是我目前使用的代码:

@Override
@Transactional
public TransactionDTO confirmCheckout(...) {

    /**Validations removed and parameters simplified to improve readability**/

    Transaction transaction = transactionDao.create(...);
    pointsTransactionDao.create(transaction, ...);

    return new TransactionDTO(transaction);
}

DAO 函数已经过适当的测试并且可以独立工作,但是在运行上述代码时,我收到以下异常。

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347)
at ar.edu.itba.paw2018b.persistence.PointTransactionsHibernateDaoImpl.create(PointTransactionsHibernateDaoImpl.java:32)

Caused by: org.postgresql.util.PSQLException: ERROR: insert or update on table "pointtransactions" violates foreign key constraint "pointtransaction_transaction_transid_fk"
Detail: Key (transaction)=(23) is not present in table "transactions".

在运行时查看代码时,我可以确认 ID = 23 的事务是在 confirmCheckout() 方法中创建的事务。 似乎违反了约束,因为在 PointTransaction 记录之前未将 Transaction 记录提交到 DB。

此错误开始于我将我的 EntityManagers 的 PersistenceContext 从默认更改为 ExtendedType,更改是由于我需要延迟初始化我的大部分引用而推动的。我相信这个问题与此密切相关,但是我对 Hibernate 的了解还不够,无法推断出解决该问题的最佳方法。

下面是我的 Daos 和 Models 的代码。

感谢您的宝贵时间。

@Repository
public class TransactionHibernateDaoImpl implements TransactionDao {

    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    @Override
    public Transaction create(User userId, Screening screeningId, String seat, String food, double price, boolean paid, Timestamp date, String confirmationCode, int status) {
        final Transaction transaction = new Transaction(userId,screeningId,seat,food,price,date,paid,confirmationCode, status);
        em.persist(transaction);
        return transaction;
    }
    public void setEm(EntityManager em) {
        this.em = em;
    }
    /** Unrelated Methods **/
}

.

@Repository
public class PointTransactionsHibernateDaoImpl implements PointTransactionsDao {

    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    @Override
    public PointTransactions create(User userid, int conversion, Transaction transaction, int price, int reason, Timestamp date)
    {
        final PointTransactions ptransaction = new PointTransactions(userid,conversion,transaction,price, reason, date);
        em.persist(ptransaction);
        return ptransaction;
    }
    public void setEm(EntityManager em) {
        this.em=em;
    }
    /** Unrelated Methods **/
}

.

@Entity
@Table(name = "pointtransactions")
public class PointTransactions {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @SequenceGenerator(sequenceName = "transactions_transid_seq", name = "transactions_transid_seq", allocationSize = 1)
    @Column(name = "pointtransid", nullable = false)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "userid")
    private User userid;

    @Column
    private int conversion;

    @Column
    private Timestamp date;

    @Column
    private int price;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "transaction")
    private Transaction transaction;

    @Column(nullable = false)
    private int reason;

    public PointTransactions(){}


    public PointTransactions(User userId, int conversion, Transaction transaction, int price, int reason, Timestamp date){
        this.userid = userId;
        this.conversion = conversion;
        this.transaction = transaction;
        this.price = price;
        this.reason = reason;
        this.date = date;
    }
    /** Getters and Setters **/
}

.

@Entity
@Table(name = "transactions")
public class Transaction {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @SequenceGenerator(sequenceName = "transactions_transid_seq", name = "transactions_transid_seq", allocationSize = 1)
    @Column(name = "transid", nullable = false)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "userid")
    private User userid;

    @Column(name = "transactiondate",nullable = false)
    private Timestamp date;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "screeningid")
    private Screening screeningid;

    @Column(nullable = false)
    private String seat;

    @Column(name = "fooddetails", length = 1024)
    private String food;

    @Column(nullable = false)
    private double price;

    @Column(nullable = false)
    private boolean paid = false;

    @Column
    private String confirmationCode;

    @Column
    private int status;

    public Transaction(){}

    public Transaction( User userId, Screening screeningId, String seat, String food, double price, Timestamp date, boolean paid, String confirmationCode, int status){
        this.userid = userId;
        this.date = date;
        this.screeningid = screeningId;
        this.seat = seat;
        this.food=food;
        this.price = price;
        this.paid = paid;
        this.confirmationCode = confirmationCode;
        this.status = status;
    }
/** Getters and Setters **/
}

【问题讨论】:

    标签: java spring hibernate constraints


    【解决方案1】:

    你的观察非常接近,长话短说,PerssitenceContextType.EXTENDED - 意味着你负责管理你的东西;容器不会为你做这件事。

    “ID = 23 的事务是在 confirmCheckout() 方法中创建的” - 您能否检查数据库中的“ID = 23”是否存在?

    我猜不是,这意味着您的更改没有按顺序提交,或者它们应该或它们没有被刷新,所以你最终得到“违反外键约束”pointtransaction_transaction_transid_fk“”

    肮脏的解决方案[自己做这些事情]——即提交/刷新 ID=23 更改,检查它是否保留在数据库中,然后继续进行其余操作。

    这是您正在寻找的长篇故事 - https://vladmihalcea.com/initialize-lazy-proxies-collections-jpa-hibernate/ 真诚地希望得到一张电影票

    【讨论】:

      猜你喜欢
      • 2011-01-11
      • 2012-02-07
      • 2012-01-09
      • 2021-04-03
      • 1970-01-01
      • 2016-07-02
      • 1970-01-01
      • 1970-01-01
      • 2020-02-14
      相关资源
      最近更新 更多