继承的实体属性有时为null

时间:2014-07-11 20:03:30

标签: java glassfish eclipselink ejb-3.1

我有一个非常奇怪的情况,只能在一个特定的开发者环境中间歇性地重现,我正在寻找关于在哪里寻找原因的想法。

在这种情况下,有一个实体,它是抽象基类的子类。该模型使用JOINED策略。例如,

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@NamedQueries({@NamedQuery(name = "Foo.findNextForProcessing", query = "SELECT f FROM Foo f WHERE f.status IN (some statuses) ORDER BY f.priority DESC, f.id ASC")})
public abstract class BaseEntity implements Serializable, Comparable {

  @Id
  @Generated Value(generator="fooSeq", strategy=GeneratorType.SEQUENCE)
  @SequenceGenerator(name="fooSeq", sequenceName="SEQ_FOO_ID", allocationSize=1)
  private long id;

  @Version
  private int version;

  @Basic(optional = false)
  @Column(nullable = false)
  private int priority;

  @Basic(optional = false)
  @Column(nullable = false)
  @Index
  @Enumerated(EnumType.STRING)
  private FooStatus status;

  @Index
  private String foo;

  //Getters and Setters, ctor, toString, compareTo
}

@Entity
public class Bar extends Foo {

  //No @Version property - uses base class for that

  @Basic(optional = false)
  @Column(nullable = false)
  private String name;

  @Basic(optional = false)
  @Column(nullable = false)
  private String pathName;

  //Getters & Setters, toString - no ctor
}

Bar是在EJB 3.1 SSB的方法中创建的,其注入的PersistenceContext是JTA资源(由Glassfish 3.1.2(Eclipselink 2.3.2v20111125-r10461)支持到Oracle 10g Express 10.2.0.1的JDBC资源/连接池) .0服务器使用ojdbc6瘦驱动程序)。

代码正在记录Bar创建时的详细信息,并确认Bar确实填充了其字段及其父项。

在创建这些内容的同时,@ Singleton bean有一个使用@Asynchronous和@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)注释的方法,该方法使用特定的FooStatus轮询Foo对象。

EJB轮询方法是这样的:

@PersistenceContext(unitName = "APP1")
private EntityManager entityManager;

@Resource
SessionContext sctx;

@EJB
FooBean fooBean;

@Asynchronous
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void run() {
  while(!shouldStop) {
    try {
      sctx.getBusinessObject(Poller.class).innerPoll();
    }catch(EJBException ejbex) {
     ...
    }catch(Exception ex) {
     ...
    }
  }
}

innerPoll()方法是通过调用注入到Poller类的fooBean上的方法来获取Foo的地方。它看起来像这样:

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void innerPoll() throws PollerException {
...
  List<Foo> results = fooBean.fetchNextForProcessing(int maxResultSize);
  for (Foo foo : results) {
    if (foo instanceof Bar) {
      log.debug("priority: " + foo.priority); //Always has a value for priority!
      log.debug("pathName: " +((Bar)foo).pathName); //Prints "pathName: NULL" sometimes! - 
    }
  }
...
}

在fooBean中进行提取的查询如下所示:

TypedQuery<Foo> q = entityManager.createNamedQuery("Foo.findNextForProcessing", Foo.class);
q.setFirstResult(0);
q.setMaxResult(maxResultSize);
return q.getResultList();

命名查询如下所示:

SELECT f FROM Foo f WHERE f.status IN (some statuses) ORDER BY f.priority DESC, f.id ASC

它获取此轮询的结果列表(List)并检查它们是哪个子类(Bar等 - 除了Bar之外还有其他几个Foo的子类)。

对于Bar的实例,如果我们调用((Bar)afoo).toString(),我们观察(仅在这一个devs机器上 - 有时只有!)与Bar关联的属性(pathName,name,等)是NULL,并且正确填写与其基类(foo,status等)相关联的属性。

如果我们在打印出一个Bar并确认aBar.pathName为NULL后强制发生异常,那么run()中的while循环将捕获异常并重新执行innerPoll()调用,我们看到aBar将在其后(和所有)后续提取中填充其属性。

这感觉就像一个计时问题,但奇怪的是,Bar是在其自己的TX中自动创建的,它设置了它及其继承的属性所以我不确定当轮询线程如何选择它时基类属性被填充但是子类属性仍为NULL。这种破坏的行为有时只会发生,并且只发生在这台特定的机器上。

这是否与Eclipselink 1级缓存和版本更改跟踪有关? persistence.xml具有以下参数集:

eclipselink.cache.shared.default=false
eclipselink.jdbc.batch-writing=Oracle-JDBC
eclipselink.order-updates=true
eclipselink.jdbc.native-sql=true

因此,与编织或版本跟踪无关的任何内容都会从其默认值更改。

1 个答案:

答案 0 :(得分:0)

[更新] - 在Glassfish JDBC连接池设置中,取消选中&#34;非事务性连接&#34;设置JTA资源使用的连接池似乎已经解决了问题,并解释了为什么他是唯一受影响的人,因为他是唯一一个已经检查过这个设置但是我还不清楚这是否是一个错误或预期的行为。