如何使弹性EJB可能抛出像PSQLException这样的系统异常

时间:2016-03-12 19:51:18

标签: java-ee exception-handling ejb rollback glassfish-4.1

我有一个在GlassFish 4.1中运行的EJB,它可能会像PSQLException一样抛出系统异常。在一个特定情况下,尝试使用现有唯一键值将记录写入db时,将抛出重复键Exception。我已尝试捕获所有异常以及在应用程序异常中将org.postgresql.util.PSQLException(和其他)添加为ejb-jar.xml中的异常类,但该调用始终回滚事务。我希望我的EJB能够适应这些异常。如果我可以捕获异常甚至忽略它们,我的应用程序可以从这些问题中恢复。我怎样才能做到这一点?

这是一个例子。我有一个Servlet,当我用Web浏览器点击它时调用这个EJB方法:

public void initialize() {  
    try {  
        User user = new User(0, "John", "Doe");  
        em.persist(user);  
        em.flush();  
    } catch(Exception e) {  
        e.printStackTrace();  
    }

我的ejb-jar.xml包含:

<application-exception>
   <exception-class>org.postgresql.util.PSQLException</exception-class>
    <rollback>false</rollback>
    <inherited>true</inherited>
</application-exception>

适用于我的解决方案是由高风险提供的。 “解决方案是简单地将'initialize'标记为非事务性,并将这些内容放入一个单独的方法中,为每次尝试启动一个新事务。”

更新:此解决方案无法正常运行。我的应用程序中出现错误,使其看起来有效。修复错误后,我回到了同样的问题。似乎PSQLException不可捕获,因为它是一个SystemException。我尝试了容器管理和bean管理的方法。我不同意尝试第二次持久记录应该导致SystemException。在分布式环境中,可能会发生这种情况。这应该是可以恢复的情况。

更新:我使用下面发布的解决方案解决了我的问题。

2 个答案:

答案 0 :(得分:0)

这绝对与JPA无关,它与PostgreSQL如何处理事务中的错误状态有关。

在您的情况下,它似乎要么在数据库级别自动回滚,要么将事务标记为处于不一致状态。你不能/不应该从业务层内部恢复的东西。

解决方案是简单地将'initialize'标记为非事务性,并将这些内容放入一个单独的方法中,为每次尝试启动一个新事务。

编辑:我的回答仅适用于您实际上设法捕获catch块中的异常,如果不这样,则意味着您只是在提交期间获得异常,在这种情况下上述解决方案也适用。

答案 1 :(得分:0)

这是我选择的适合我的解决方案。而不是注入PersistenceContext:

@PersistenceContext
private EntityManager em;

我正在注入一个DataSource资源:

@Resource(lookup = "jdbc/sloocefw")
private DataSource dataSource;

这使我能够创建自己的SQL语句(这是重要的)让我在尝试插入带有重复键的行时捕获SQLException。

public void initialize() {  
    try (Connection connection = dataSource.getConnection()) {
        PreparedStatement ps = connection.prepareStatement("INSERT INTO user (id, firstName, lastName) VALUES (" + id + ", 'John', 'Doe')");
        ps.executeUpdate();
    } catch(SQLException e) {
        e.printStackTrace();
    }
}

我现有的用户实体bean管理id(自动增量)。我需要更改为手动管理(如上例所示)或使用数据库自​​动增量。

我更愿意使用实体bean,但是当我使用实体bean时,尝试插入重复键会导致无法捕获的SystemException。