Oracle代理身份验证:回滚整个事务

时间:2015-10-07 12:00:28

标签: jpa oracle11g eclipselink jta

使用Glassfish 4.1,Eclipselink 2.5.1,Oracle 11g。

使用 Oracle代理身份验证持久保持一对多(父子关系)关系时,我们遇到了回滚更改的问题。如果在持久化其中一个子节点时抛出任何异常,则父节点仍将保留到DB(未按预期方式回滚)。我们使用容器管理的JTA实体管理器从无状态EJB保存到DB:

entitymanager.persist(parent);

cascade = CascadeType.ALL用于父方的关系。

我们的persistence.xml包含<persistence-unit name="admin_war_1.0-SNAPSHOTPU" transaction-type="JTA">,手头的问题是我们在持久层中唯一的问题(到目前为止,其他一切工作正常)。

父实体类似于:

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;
}

子实体是:

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的所有调用中,我们用

代理entitymanager
        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方法都会运行。

问题仅在代理时出现,而不是在我们省略该部分时。似乎问题与自动提交的jdbc连接有关。我们在Glassfish连接池中尝试了各种参数; relaxAutoCommit = true,AutoCommit = false等,但没有任何改变。

我们如何确保,当孩子坚持失败时父母也会回滚?

2 个答案:

答案 0 :(得分:1)

在使用entitymanager和在应用程序服务器中定义的datsource时,我遇到了类似的问题。为了解决这个问题我做了这个:

1- i set transaction-type =&#34; RESOURCE_LOCAL&#34;在persistence.xml中,用于定义持久性单元

2-我使用了非jta-data-source属性,其值为myDatasourceName

我意识到异常的根源是jta!

答案 1 :(得分:0)

快速解决方案似乎是:

  • 使用em.flush();
  • 结束ejb方法

这也会让父母回滚 - 不要问我为什么。

请注意,持久化子实体失败时抛出的异常将不同(e.getCause()将不同,以防您向最终用户显示,但它仍将包装在EJBException中。)

另一种解决方案是:

  • 使用RESOURCE_LOCAL和非jta-data-source,如其他答案中所述。您必须在EJB中注入EntityManagerFactory并自己进行事务处理。

我没有办法让我摆脱它。