0

次の 2 つのコードを分析して、コミット時に最初のコードが主キー違反で失敗し、2 番目のコードが失敗しない理由を教えてください。

コミット時に失敗するコード:

try{

        Query q = em.createQuery("DELETE FROM Puntaje");
        q.executeUpdate();
        //em.getTransaction().commit();

        //em.getTransaction().begin();
        Iterator it = l.iterator();
        while(it.hasNext()){
            DataPuntaje dp = (DataPuntaje)it.next();
            Cliente c = new Cliente(dp.getCliente());
            Puntaje p = new Puntaje(dp.getPuntaje(),c);
            c.agregarPuntaje(p);

            em.merge(c);

        }


   System.out.println("test1");
        em.getTransaction().commit();
   System.out.println("test2");
    }

正常に動作するコード:

try{

        Query q = em.createQuery("DELETE FROM Puntaje");
        q.executeUpdate();
        em.getTransaction().commit();

        em.getTransaction().begin();
        Iterator it = l.iterator();
        while(it.hasNext()){
            DataPuntaje dp = (DataPuntaje)it.next();
            Cliente c = new Cliente(dp.getCliente());
            Puntaje p = new Puntaje(dp.getPuntaje(),c);
            c.agregarPuntaje(p);

            em.merge(c);

        }


   System.out.println("test1");
        em.getTransaction().commit();
   System.out.println("test2");
    }

唯一の違いは、最初のものは削除クエリをコミットせず、代わりに最後にまとめてコミットすることです。Cliente と Puntaje は cascade = ALL の 1:N 双方向の関係です。Cliente の挿入されたすべてのインスタンスは同じ ID を持っていますが、マージは最初のインスタンスが永続化された後に挿入するのではなく、更新するのに十分スマートである必要がありますが、最初の例では失敗しているようで、説明が見つかりません。また、H2組み込みデータベースを使用しています。

また、追加したいのですが、Cliente 値が既に挿入されている場合、最初のコードは正常に機能します。これは、テーブルが実際に空であり、削除が実際に何もしていない場合に失敗します。

これは私が得るエラーです:

Internal Exception: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_5 ON PUBLIC.CLIENTE(NICK)"; SQL statement:
INSERT INTO CLIENTE (NICK) VALUES (?) [23505-169]
Error Code: 23505
Call: INSERT INTO CLIENTE (NICK) VALUES (?)
        bind => [cbaldes]
Query: InsertObjectQuery(Clases.Cliente@21cd5b08)
javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_5 ON PUBLIC.CLIENTE(NICK)"; SQL statement:
INSERT INTO CLIENTE (NICK) VALUES (?) [23505-169]
Error Code: 23505
Call: INSERT INTO CLIENTE (NICK) VALUES (?)
        bind => [cbaldes]
Query: InsertObjectQuery(Clases.Cliente@21cd5b08

)

これらはテーブルです:

@Entity
public class Puntaje implements Comparable, Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private int total;

    @ManyToOne(cascade=CascadeType.ALL, optional = false)
    @JoinColumn(name="NICK")
    private Cliente cliente;


@Entity
public class Cliente implements Serializable {

    @Id
    private String nick;

    @OneToMany(cascade=CascadeType.ALL, mappedBy="cliente")
    private List<Puntaje> puntajes;
4

1 に答える 1

2

オブジェクトに対して操作を実行すると、すべての操作がキャッシュにのみ記録されます。JPAは、挿入、更新、削除するすべてのオブジェクトの内部リストを作成します。flushまたはcommitが呼び出されたときに一緒にフラッシュされます。

最初の例を見てみましょう。すべてを削除しました。これにより、リストPuntajeにすべてが追加されます。さて、あなたが電話をすると、私は確かに十分に賢く*、それは挿入されるべきであり、更新されてリストに追加されるべきではないと考えました。commitを呼び出すと、最初に挿入リストからオブジェクトを挿入しようとしますが、予想どおり、古いオブジェクトはまだ削除されていないため失敗します。Puntajedeletedmergeinsert

2番目の例の唯一の違いは、強制的に、挿入前に最初にオブジェクトを削除しているため、失敗しないことです。

flushの代わりに使っても失敗しないと思いますcommit

これが失敗の背後にある理由を理解するのに役立つことを願っています。

于 2012-11-12T06:12:47.130 に答える