1

使用:Glassfish 3.1.2、EclipseLink。

次の3つのクラスのJPAモデルがあります。

@Entity public class Customer implements Serializable {

@Id private Integer id;

@OneToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, orphanRemoval=true)
private Person person;

[...]

@Entity public class Person implements Serializable {

@Id private Integer id;

[...]

@Entity public class Request implements Serializable {

@Id private Integer id;

@ManyToOne private Person person;

次の戦略で顧客を削除しようとしています(CMTを使用)。

<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="MyPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
        <property name="eclipselink.ddl-generation" value="create-tables"/>
        <property name="eclipselink.ddl-generation.output-mode" value="database"/>

        <property name="eclipselink.logging.level" value="FINE"/>
        <property name="eclipselink.logging.parameters" value="true"/>
        <property name="eclipselink.logging.logger" value="DefaultLogger"/>                  
        <property name="eclipselink.logging.timestamp" value="true"/>
        <property name="eclipselink.logging.session" value="false"/>
        <property name="eclipselink.logging.thread" value="false"/>
    </properties>
</persistence-unit>

[...]

@PersistenceContext(unitName="MyPU")
private EntityManager entityManager;   

@Resource private SessionContext context;

[...]

public void delete(Entity object) {

    try{

        object = this.getEntityManager().merge(object);
        this.getEntityManager().remove(object);

    } catch (Exception e){

        this.context.setRollbackOnly();
    }
}

CustomerオブジェクトがRequestにアタッチされているPersonオブジェクトにアタッチされている場合、 Personの削除カスケードは失敗し、トランザクションはロールバックされますが、Customerはデータベースから削除されます。次のエラーが表示されます。

INFO: [EL Fine]: 2012-12-28 10:53:38.1--Connection(27132168)--DELETE FROM CUSTOMER WHERE (ID = ?)
bind => [97]
INFO: [EL Fine]: 2012-12-28 10:53:38.125--Connection(27132168)--DELETE FROM PERSON WHERE (ID = ?)
bind => [111]
INFO: [EL Fine]: 2012-12-28 10:53:38.126--SELECT 1
WARNING: DTX5014: Caught exception in beforeCompletion() callback:
Local Exception Stack:
INFO: [EL Warning]: 2012-12-28 10:53:38.127--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERRO: atualização ou exclusão em tabela "person" viola restrição de chave estrangeira "fk_request_person_id" em "request"
Detalhe: Chave (id)=(111) ainda é referenciada pela tabela "request".
Error Code: 0
Call: DELETE FROM PERSON WHERE (ID = ?)
bind => [111]
Query: DeleteObjectQuery(111)
[...]
SEVERE: javax.ejb.EJBException: Transaction aborted
[...]

では、カスケード削除が失敗した場合、どうすれば顧客の削除をキャンセルできますか?

4

1 に答える 1

0

ここで問題が発生する可能性があることが 2 つあります。

  • トランザクション境界が正しく指定されていません

これが原因で、アプリケーション サーバーが BEGIN ステートメントを正しく発行していない可能性があります。これは、Postgres には問題があり、Oracle には問題がないことを説明しています (暗黙的にトランザクションを開始します)。サービス メソッドに正しいアノテーションが付けられていることを確認してください。万事順調なら多分

  • データソースに問題があります。

JTA 互換のデータソースですか? Postgres 用の正しいドライバーを使用していますか? チェックアウトできるように、構成を投稿してください。

あなたにも役立つかもしれない興味深いリンクを見つけました。これは、Postgres が自動コミット モードのままであることについてです (ただし、Spring を使用している場合)。

http://archives.postgresql.org/pgsql-jdbc/2007-07/msg00115.php

于 2013-01-02T19:34:48.000 に答える