Oracle 代理身份验证:回滚整个事务
Oracle proxy authentication: Rollback of whole transaction
使用 Glassfish 4.1、Eclipselink 2.5.1、Oracle 11g。
我们在使用 Oracle 代理身份验证 保持 one-to-many (parent-children) 关系时回滚更改时遇到问题。如果在持久化 children 之一时抛出任何异常,parent 仍将持久化到数据库(不会按预期回滚)。我们使用 container-managed JTA entitymanager 从无状态 EJB 保存到 DB:
entitymanager.persist(parent);
cascade = CascadeType.ALL
用在parent这边的关系上。
我们的 persistence.xml 包含 <persistence-unit name="admin_war_1.0-SNAPSHOTPU" transaction-type="JTA">
并且手头的问题是我们在持久层中遇到的唯一问题(到目前为止,其他一切都工作正常)。
parent 实体类似于:
public class KornstoranalyseStd implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "KORNSTORANALYSE_STD_ID", nullable = false)
private Integer kornstoranalyseStdId;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "kornstoranalyseStd", fetch = FetchType.EAGER)
@OrderBy("maskestoerrelse DESC")
private Collection<KornstoranalyseStdSigte> kornstoranalyseStdSigteCollection;
}
而 child 实体是:
public class KornstoranalyseStdSigte implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "KORNSTORANALYSE_STD_SIGTE_ID", nullable = false)
private Integer kornstoranalyseStdSigteId;
@Basic(optional = false)
@NotNull
@Column(name = "MASKESTOERRELSE", nullable = false, precision = 12, scale = 8)
private BigDecimal maskestoerrelse;
@JoinColumn(name = "KORNSTORANALYSE_STD_ID", referencedColumnName = "KORNSTORANALYSE_STD_ID", nullable = false)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private KornstoranalyseStd kornstoranalyseStd;
}
以下代码仅供测试:
KornstoranalyseStd parent = new KornstoranalyseStd();
parent.setKornstoranalyseStdId(1);
List<KornstoranalyseStdSigte> children = new ArrayList<>();
KornstoranalyseStdSigte child = new KornstoranalyseStdSigte();
child.setKornstoranalyseStdSigteId(1);
child.setMaskestoerrelse(new BigDecimal(11));
child.setKornstoranalyseStd(parent);
children.add(child);
parent.setKornstoranalyseStdSigteCollection(children);
getEjbFacade().create(parent);
这是 STSB:
@Stateless
public class KornstoranalyseStdFacade {
@PersistenceContext(unitName = "admin_war_1.0-SNAPSHOTPU")
private EntityManager em;
private EntityManager getEntityManager() {
return em;
}
public void create(KornstoranalyseStd entity) {
getEntityManager().persist(entity);
}
}
在通过 EJB 的所有调用中,我们使用
代理实体管理器
getEntityManager().setProperty("eclipselink.oracle.proxy-type", 1);
getEntityManager().setProperty("PROXY_USER_NAME", loginBean.getUsername());
getEntityManager().setProperty("PROXY_USER_PASSWORD", loginBean.getPassword());
getEntityManager().setProperty("eclipselink.jdbc.exclusive-connection.mode", "Always");
getEntityManager().setProperty("eclipselink.jdbc.exclusive-connection.is-lazy", "true");
以上行在 @AroundInvoke-method
中,因此无论访问什么 EJB-method,都将是 运行。
这个问题只在代理时出现,如果我们省略那部分则不会。看来问题与自动提交的 jdbc-connections 有关。我们在 Glassfish 连接池中尝试了各种参数; relaxAutoCommit=true、AutoCommit=false 等,但没有任何改变。
当 child 持久化失败时,我们如何确保 parent 也回滚?
我在将 entitymanager 与应用程序服务器中定义的数据源一起使用时遇到了类似的问题。为了解决问题,我这样做了:
1- 我在 persistence.xml 中设置了事务类型="RESOURCE_LOCAL" 并定义了持久性单元
2- 我使用了非 jta 数据源 属性,其值为 myDatasourceName
我意识到异常的根源是jta!
快速解决方案似乎是:
- 用
em.flush();
结束 ejb 方法
这也会让父级回滚 - 不要问我为什么。
请注意,保留子实体失败时抛出的异常会有所不同(e.getCause() 会有所不同,以防您向最终用户展示,但它仍将包含在 EJBException 中)。
另一个解决方案是:
- 使用 RESOURCE_LOCAL 和其他答案中所写的非 jta 数据源。您必须在 EJB 中注入 EntityManagerFactory 并自行处理事务。
我没有找到配置我的方法。
使用 Glassfish 4.1、Eclipselink 2.5.1、Oracle 11g。
我们在使用 Oracle 代理身份验证 保持 one-to-many (parent-children) 关系时回滚更改时遇到问题。如果在持久化 children 之一时抛出任何异常,parent 仍将持久化到数据库(不会按预期回滚)。我们使用 container-managed JTA entitymanager 从无状态 EJB 保存到 DB:
entitymanager.persist(parent);
cascade = CascadeType.ALL
用在parent这边的关系上。
我们的 persistence.xml 包含 <persistence-unit name="admin_war_1.0-SNAPSHOTPU" transaction-type="JTA">
并且手头的问题是我们在持久层中遇到的唯一问题(到目前为止,其他一切都工作正常)。
parent 实体类似于:
public class KornstoranalyseStd implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "KORNSTORANALYSE_STD_ID", nullable = false)
private Integer kornstoranalyseStdId;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "kornstoranalyseStd", fetch = FetchType.EAGER)
@OrderBy("maskestoerrelse DESC")
private Collection<KornstoranalyseStdSigte> kornstoranalyseStdSigteCollection;
}
而 child 实体是:
public class KornstoranalyseStdSigte implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "KORNSTORANALYSE_STD_SIGTE_ID", nullable = false)
private Integer kornstoranalyseStdSigteId;
@Basic(optional = false)
@NotNull
@Column(name = "MASKESTOERRELSE", nullable = false, precision = 12, scale = 8)
private BigDecimal maskestoerrelse;
@JoinColumn(name = "KORNSTORANALYSE_STD_ID", referencedColumnName = "KORNSTORANALYSE_STD_ID", nullable = false)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private KornstoranalyseStd kornstoranalyseStd;
}
以下代码仅供测试:
KornstoranalyseStd parent = new KornstoranalyseStd();
parent.setKornstoranalyseStdId(1);
List<KornstoranalyseStdSigte> children = new ArrayList<>();
KornstoranalyseStdSigte child = new KornstoranalyseStdSigte();
child.setKornstoranalyseStdSigteId(1);
child.setMaskestoerrelse(new BigDecimal(11));
child.setKornstoranalyseStd(parent);
children.add(child);
parent.setKornstoranalyseStdSigteCollection(children);
getEjbFacade().create(parent);
这是 STSB:
@Stateless
public class KornstoranalyseStdFacade {
@PersistenceContext(unitName = "admin_war_1.0-SNAPSHOTPU")
private EntityManager em;
private EntityManager getEntityManager() {
return em;
}
public void create(KornstoranalyseStd entity) {
getEntityManager().persist(entity);
}
}
在通过 EJB 的所有调用中,我们使用
代理实体管理器 getEntityManager().setProperty("eclipselink.oracle.proxy-type", 1);
getEntityManager().setProperty("PROXY_USER_NAME", loginBean.getUsername());
getEntityManager().setProperty("PROXY_USER_PASSWORD", loginBean.getPassword());
getEntityManager().setProperty("eclipselink.jdbc.exclusive-connection.mode", "Always");
getEntityManager().setProperty("eclipselink.jdbc.exclusive-connection.is-lazy", "true");
以上行在 @AroundInvoke-method
中,因此无论访问什么 EJB-method,都将是 运行。
这个问题只在代理时出现,如果我们省略那部分则不会。看来问题与自动提交的 jdbc-connections 有关。我们在 Glassfish 连接池中尝试了各种参数; relaxAutoCommit=true、AutoCommit=false 等,但没有任何改变。
当 child 持久化失败时,我们如何确保 parent 也回滚?
我在将 entitymanager 与应用程序服务器中定义的数据源一起使用时遇到了类似的问题。为了解决问题,我这样做了:
1- 我在 persistence.xml 中设置了事务类型="RESOURCE_LOCAL" 并定义了持久性单元
2- 我使用了非 jta 数据源 属性,其值为 myDatasourceName
我意识到异常的根源是jta!
快速解决方案似乎是:
- 用
em.flush();
结束 ejb 方法
这也会让父级回滚 - 不要问我为什么。
请注意,保留子实体失败时抛出的异常会有所不同(e.getCause() 会有所不同,以防您向最终用户展示,但它仍将包含在 EJBException 中)。
另一个解决方案是:
- 使用 RESOURCE_LOCAL 和其他答案中所写的非 jta 数据源。您必须在 EJB 中注入 EntityManagerFactory 并自行处理事务。
我没有找到配置我的方法。