插入后如何防止JPA回滚异常?

时间:2017-01-27 20:01:38

标签: java hibernate jpa entity persistence

电子贺卡:

@Entity
@Table (name = "ecard")
public class Ecard {
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    @OneToOne (cascade = CascadeType.ALL)
    @JoinColumn(name = "IdUser", nullable = false)
    private User user;

    @ManyToOne 
    @JoinColumn(name = "IdBank", nullable = false)
    private Bank bank;

    @Column (name = "accountNumber", nullable = false)
    private int accountNumber;

    public ECard(User user, Bank bank, int accNumber) {
       this.user = user;
       this.bank = bank;
       this.accountNumber = accNumber;
    }
}

用户:

     @Entity
    @Table (name="user")
    public class User {
        @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
        private int id;

        @OneToOne (mappedBy = "user")
        private ECard eCard;

        @ManyToOne
        @JoinTable(
            name = "ecard", 
            inverseJoinColumns = @JoinColumn(name = "IdBank", referencedColumnName = "Id"),
            joinColumns = @JoinColumn(name = "IdUser", referencedColumnName = "Id")
        )
        private Bank bank;

public void seteCard(ECard eCard) {
        this.eCard = eCard;
    }

    public void setBank(Bank bank) {
        this.bank = bank;
    }
}

行:

    @Entity
    @Table (name = "bank")
    public class Bank {
        @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
        private int id;

        @Column(name = "name", nullable = false, unique = true)
        private String name;
}

我已经初始化了Bank表,我想插入新用户,并将新的ECard链接到已存在于数据库中的Bank

我是新手,所以我无法理解为什么

我的代码不起作用:

        //I checked and variable bank is okay, it's method argument
        eManager.getTransaction().begin();
        User user = new User();
        ECard eCard = new ECard(user, bank, 1000);

        user.seteCard(eCard);
        user.setBank(bank); // PROBLEM
        eManager.persist(eCard);

        eManager.getTransaction().commit();

我得到了一个回滚例外:

    Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Field 'accountNumber' doesn't have a default value
Error Code: 1364
Call: INSERT INTO ecard (IdBank, IdUser) VALUES (?, ?)
    bind => [2 parameters bound]
Query: DataModifyQuery(name="bank" sql="INSERT INTO ecard (IdBank, IdUser) VALUES (?, ?)")
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:895)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:957)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:630)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558)
    at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:1995)
    at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:296)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeNoSelectCall(DatasourceCallQueryMechanism.java:271)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeNoSelect(DatasourceCallQueryMechanism.java:251)
    at org.eclipse.persistence.internal.queries.StatementQueryMechanism.executeNoSelect(StatementQueryMechanism.java:118)
    at org.eclipse.persistence.queries.DataModifyQuery.executeDatabaseQuery(DataModifyQuery.java:85)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
    at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:798)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2894)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1797)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1779)
    at org.eclipse.persistence.mappings.OneToOneMapping.performDataModificationEvent(OneToOneMapping.java:2181)
    at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:159)
    at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4200)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1439)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1529)
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1167)
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132)
    ... 10 more
Caused by: java.sql.SQLException: Field 'accountNumber' doesn't have a default value
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1074)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4120)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4052)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2503)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2664)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2794)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2375)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2359)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:885)
    ... 34 more
Java Result: 1

当我删除第user.setBank(bank)行时效果很好,但我需要在用户银行中引用,所以删除这一行对我来说并不是那么好。

当我为accountNumber设置默认值时,我在eCard表中获得两行,一个是常规行,第二行是默认accountNumber,同样是IdUser和IdBank

如何避免该异常以及如何在Bank ??

上设置引用

1 个答案:

答案 0 :(得分:0)

您已经通过添加此

ecard声明为您的映射表
@ManyToOne
    @JoinTable(
        name = "ecard", 
        inverseJoinColumns = @JoinColumn(name = "IdBank", referencedColumnName = "Id"),
        joinColumns = @JoinColumn(name = "IdUser", referencedColumnName = "Id")
    )

ecard也用作实体,通过关联bankId和userId以及accountNumber字段来映射用户和银行的信息。 这就是为什么Jpa在用户的持久性中添加2条记录的原因 - 一条用于用户类name = 'ecard'映射中的已定义映射,另一条用于ECard eCard = new ECard(user, bank, 1000);

我建议你将accountNumber字段移到银行类并删除ecard类,因为JoinColumn (name = 'ecard'...中的映射已经假定存在一个只有2列userId和bankId的表ecard并且会处理它以默认方式。

或者删除用户类中的银行字段,因为用户已经引用了引用ecard的{​​{1}}。但是现在您必须手动管理银行和用户之间的关联它在上面的代码中。