2013-04-12 30 views
5

Tôi đã webservice đơn giản sau đây khai báo là @Stateless EJB chạy trên GlassFish 3.1.2.2 với EclipseLink 2.4.1 bằng cách sử dụng JTA DataSource để kết nối với một cơ sở dữ liệu MySQL:@Dịch vụ web không gian với JPA + JTA: Cách thực hiện thay đổi đối tượng được quản lý?

@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(); 
} 

Entity lớp 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); 
      } 
     } 
    } 

} 

@EmbeddableIdTimeRowPK:

@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 (không có thẻ <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> 

khai Webservice:

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

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

    ... 

} 

Vấn đề là nếu thực thể tồn tại, những thay đổi được chỉ được lưu trữ trong PersistenceContext, nhưng họ không cam kết kho dữ liệu. Có nghĩa là tôi có thể truy xuất dữ liệu chính xác với các thay đổi, nhưng ví dụ nếu tôi khởi động lại AS, các thay đổi sẽ biến mất. Không có lỗi trong nhật ký AS.

Vì vậy, tôi đoán tôi phải thực hiện xử lý giao dịch thủ công ở cấp độ đậu để có được công việc này. Chính xác thì tôi phải thêm gì để làm việc này?

+0

Đậu có được khai báo @Stateless không? –

+0

Vâng, đúng vậy! –

+1

Trong trường hợp này, tôi không thể thấy lỗi ở đây ... '@ Stateless' ngụ ý' @TransactionAttribute (REQUIRED) 'nếu bạn không thay đổi ... Có thể nó nằm trong' MyEntity.setValues ​​() 'hoặc trong bản khai báo 'MyEntity'.Bạn có thể đăng mã 'MyEntity' không? –

Trả lời

2

Sau khi đấu tranh để làm việc này theo cách @EmbeddedId, tôi đã cố gắng triển khai danh sách đó bằng cách tạo ra @Id và thêm một ràng buộc duy nhất cho hai trường chính sau đó.

Entity

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; 

    ... 
} 

Ngoài ra, tôi đã thay đổi động cơ DB từ MyISAM để InnoDB để có hỗ trợ tốt hơn chính nước ngoài. Để thực hiện việc này, tôi đã thêm default-storage-engine = innodb vào /etc/mysql/my.cnf trong phần [mysqld].

Sau khi tạo cấu trúc với DDL DB, tôi đã added a unique constraint cho USERIDDAY:

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

Bây giờ nó hoạt động và dữ liệu được sửa đổi một cách chính xác :) cảm ơn Một khổng lồ bạn tất cả mọi người đã đóng góp cho câu hỏi này!

1

Có lẽ nắm bắt được ở đây:

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

Cố gắng thay đổi nó để sử dụng danh sách của container như trong:

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

Ngoài ra, đó là một sử dụng rất lạ của JPA. Tôi chưa bao giờ thấy danh sách tồn tại theo cách này mà không có @ElementCollection

Các vấn đề liên quan