我在拥有WildFly 10的POC中有两层。
使用JaxRS的Web服务调用EJB维护@PersistenceContext
。
它可以处理一系列加密货币的钱包。
每一行都知道它的钱包有@ManyToOne
以便快速使用数据库,但业务逻辑说钱包应该知道它的行。
所以我有一个循环依赖:钱包知道它的Line,每一行都知道它的钱包。
@Stateless
public class WalletBusiness {
// EntityManager is given by Wildfly. It's a managed object
@PersistenceContext
EntityManager em;
public JpaWallet findWallet(int id) {
// transaction is opened in your back
JpaWallet w = em.find(JpaWallet.class, id);
String jpql = "SELECT l FROM JpaLine l JOIN l.wallet w WHERE w.id = :id";
List<JpaLine> lines = em.createQuery(jpql, JpaLine.class)
.setParameter("id", id)
.getResultList();
w.setLines(lines);
return w;
}// and now closed. <=== Argh: is it ???
}
JaxRS Webservice获取电子钱包,然后削减循环依赖。
@GET
@Path("{id}")
public Wallet getWallet(@PathParam("id") int walletId){
JpaWallet wallet = walletBusiness.findWallet(walletId);
// I thought that now, I'm out of the transactionnal context
// Creating a kind of DTO: Data Transfer Object
// Cutting circular reference
wallet.getLines().stream()
.forEach(jpaLine -> jpaLine.setWallet(null));
return wallet;
}
它按预期显示在网络上,但在剪切依赖关系时,我删除了数据库上的Lines!当我认为在退出EJB方法时关闭了持久化上下文时,客户端就毁了。
我在哪里错过了什么?
以下是两个实体:
@Entity
public class JpaWallet implements Wallet {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
int id;
String name;
@Transient // Don't want to save in database. It is a Business attribute, not a database item
List<JpaLine> lines = new ArrayList<>();
@Override
public int getId() {
return this.id;
}
@Override
public String getName() {
return this.name;
}
@Override
public List<JpaLine> getLines() {
return lines;
}
public void setLines(List<JpaLine> lines) {
this.lines = lines;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return this.name;
}
}
@Entity
public class JpaLine implements Line{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
int id;
String symbol;
double quantity;
@ManyToOne
JpaWallet wallet;
@Override
@XmlAttribute(name = "coin")
public String getSymbol() {
return this.symbol;
}
@Override
public double getQuantity() {
return this.quantity;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public void setQuantity(double quantity) {
this.quantity = quantity;
}
public JpaWallet getWallet() {
return wallet;
}
public void setWallet(JpaWallet wallet) {
this.wallet = wallet;
}
@Override
public String toString() {
return this.symbol+ ": "+this.quantity;
}
}
答案 0 :(得分:0)
这是Java EE 7的一个新功能:
JTA为EJB提供事务支持,现在在Java EE 7中为CDI提供管理 用@Transactional注释的bean
Webservice层使用CDI,并且在Webservice中扩展了Transactional上下文。我不喜欢这样:JSF可以生成大量的SQL查询。
我的解决方案是在网络服务中添加注释:
@GET
@Path("{id}")
// CDI is now able to continue the transaction opened by walletBusiness
// Shut it down there
@Transactional(Transactional.TxType.NEVER)
public Wallet getWallet(@PathParam("id") int walletId){
JpaWallet wallet = walletBusiness.findWallet(walletId);
// No more propagation.
wallet.getLines().stream().forEach(jpaLine -> jpaLine.setWallet(null));
return wallet;
}