5

MySQL データベースに接続するために@StatelessJTA を使用して EclipseLink 2.4.1 を使用して GlassFish 3.1.2.2 で実行される EJBとして宣言された次の単純な Webサービスがあります。DataSource

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response update(TimeRow e) throws Exception {
    if ((e.getKey() == null) || !e.getKey().keyValid()) {
        return Response.status(400).build();
    }

    TimeRow existing = em.find(TimeRow.class, e.getKey());
    if (existing == null) {
        em.persist(e);
    } else {
        existing.setValues(e.getValues());
        em.flush();
    }
    return Response.status(204).build();
}

のエンティティ クラスTimeRow:

@Entity
@NamedQueries({
    @NamedQuery(name="TimeRow.findAllByUser",
         query="SELECT t FROM TimeRow t WHERE t.table.userId = :uid")
})
public class TimeRow implements Serializable {

    @EmbeddedId
    private TimeRowPK key;

    @MapsId("userId")
    @JoinColumn(name = "USERID", referencedColumnName = "userId")
    @ManyToOne
    private UserTable table;
    @Column(name="ROWVALUES")
    private List<Double> values;

    public TimeRow() {
        this.key = new TimeRowPK();
        this.values = new ArrayList<Double>(20);
        extendValuesTo20();
    }

    public TimeRow(String uid, Date date) {
        this.key = new TimeRowPK(date, uid);
        this.table = new UserTable(uid);
        this.values = new ArrayList<Double>(20);
        extendValuesTo20();
    }

    public List<Double> getValues() {
        return values;
    }

    public void setValues(List<Double> values) {
        this.values = values;
        extendValuesTo20();
    }

    private void extendValuesTo20() {
        if (this.values.size() < 20) {
             for (int i = this.values.size(); i < 20; i++) {
                  this.values.add(0.0);
             }
        }
    }

}

@EmbeddableId TimeRowPK:

@Embeddable
public class TimeRowPK implements Serializable {

    public TimeRowPK() { }

    public TimeRowPK(Date date, String userId) {
        this.date = date;
        this.userId = userId;
    }

    @Column(name="DAY")
    private Date date;
    @Column(name = "USERID")
    private String userId;

    public boolean keyValid() {
        return ((date != null) && ((userId != null) && !userId.isEmpty()));
    }

}

persistence.xml(<persistence>タグなし):

<persistence-unit name="test" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/test</jta-data-source>
    <class>com.test.TimeRow</class>
    <class>com.test.TimeRowPK</class>
    <class>...</class>
    <properties>
        <property name="eclipselink.ddl-generation" value="create-tables" />
        <property name="eclipselink.ddl-generation.output-mode" value="database" />
    </properties>
</persistence-unit>

Web サービス宣言:

@Path("row")
@Stateless
public class TimeRowWebService {

    @PersistenceContext(unitName = "test")
    private EntityManager em;

    ...

}

問題は、エンティティが存在する場合、変更は にのみ保存されPersistenceContext、データベースにはコミットされないことです。つまり、変更された正しいデータを取得できますが、たとえば AS を再起動すると、変更が失われます。AS ログにエラーはありません。

したがって、この作業を行うには、Bean レベルの手動トランザクション処理を行う必要があると思います。これを機能させるには、正確に何を追加する必要がありますか?

4

2 に答える 2

2

これを機能させるのに苦労した後、生成された を使用して実装し、その後 2 つのキー フィールドに一意の制約を追加@EmbeddedIdしようとしました。@Id

実在物

public class TimeRow implements Serializable {

    @Id
    @GeneratedValue
    private long id;

    @JoinColumn(name = "USERID", referencedColumnName = "USERID")
    @ManyToOne(optional = false)
    private UserTable table;

    @Basic(optional = false)
    @Column(name = "DAY")
    @Temporal(TemporalType.DATE)
    private Date date;

    @Lob
    @Column(name="ROWVALUES")
    private List<Double> values;

    ...
}

さらに、DB エンジンを からMyISAMに変更して、InnoDB外部キーのサポートを改善しました。これを行うために、セクションの下に を追加default-storage-engine = innodbしました。/etc/mysql/my.cnf[mysqld]

DDL で DB 構造を生成した後、 andに一意の制約を追加しました。USERIDDAY

alter table TIMEROW add unique index(USERID,DAY);

これで機能し、データが正しく変更されました:) この質問に貢献してくれた皆さんに心から感謝します!

于 2013-04-15T16:03:10.530 に答える
1

多分キャッチはここにあります:

public void setValues(List<Double> values) {
    this.values = values;
    extendValuesTo20();
}

次のようにコンテナのリストを使用するように変更してみてください。

public void setValues(List<Double> values) {
    this.values.clear();
    this.values.addAll(values);
    extendValuesTo20();
}

また、JPAの非常に奇妙な使い方です。リストがこのように永続化されているのを見たことがありません@ElementCollection

于 2013-04-12T10:32:20.833 に答える