Hibernate,@ ManyToOne插入和ehCache

时间:2013-05-24 04:52:38

标签: java hibernate jpa ehcache

我有父母 - >儿童关系,@ManyToOne / @OneToMany关系。

我正在处理对父代的更新,代码大致如下:

  • 获取父母
    • 从(按顺序 - ehCache,db,或创建,如果没有找到)
  • 处理更新,如果找不到,则在父级上创建子级
  • 保存到数据库
  • 存储在缓存中

运行时,我发现发生以下序列

  • 首次更新完成 - parent&孩子都创建了一个缓存
  • 第二次更新 - 从缓存中检索到的父项,添加了新的子项
    • 第二次更新完成后,子项的ID仍为null。但是,更新已成功完成。 (针对hibernate日志和db验证)
  • 第三次更新 - DataIntegrityViolationException被抛出,因为来自第二次更新的孩子再次被插入。

我认为这必须与父缓存的事实有关,而不是从数据库返回。我不确定这里的正确过程应该是什么。

相关信息:

  • 父母< - >子回溯引用被正确定义和注释。
  • 在父级的初始INSERT之后,我尝试从数据库中重新获取父级,并缓存它,以查看它是否有所作为 - 它没有。
  • 交易边界必须在这里发挥作用,因为在我的注释为@Transactional的测试中最初没有失败。 (一个难得的教训)

什么是正确的处理方式 - 特别是,为了避免每次都从数据库中加载Parent,同时仍然正确跟踪子实体?

代码示例如下所示。

@Entity // Parent
class Fixture {

    @OneToMany(cascade=CascadeType.ALL, mappedBy="fixture", fetch=FetchType.EAGER) @Getter @Setter
    @MapKey(name="instrumentPriceId")
    private Map<String,Instrument> instruments = Maps.newHashMap();

    private Instrument addInstrument(Instrument instrument)
    {
        instruments.put(instrument.getInstrumentPriceId(), instrument);
        instrument.setFixture(this);
        log.info("Created instrument {}",instrument.getInstrumentPriceId());
        return instrument;
    }

    /**
     * Returns an instrument with the matching instrumentId.
     * If the instrument does not exist, it is created, appended to the internal collection,
     * and then returned.
     * 
     * This method is guaranteed to always return an instrument.
     * This method is thread-safe.
     * 
     * @param instrumentId
     * @return
     */
    public Instrument getInstrument(String instrumentId)
    {
        if (!instruments.containsKey(instrumentId))
        {
            addInstrument(new Instrument(instrumentId));
        }
        return instruments.get(instrumentId);
    }
}

@Entity // Child
public class Instrument {

    @Column(unique=true)
    @Getter @Setter
    private String instrumentPriceId;

    @ManyToOne(optional=false)
    @Getter @Setter @JsonIgnore
    private Fixture fixture;

    public Instrument(String instrumentPriceId)
    {
        this.instrumentPriceId = instrumentPriceId;
    }
}

并且,更新处理器代码:

class Processor {
@Autowired
@Qualifier("FixtureCache")
private Ehcache fixtureCache;

@Autowired
private FixtureRepository fixtureRepository;

void update(String fixtureId, String instrumentId) {
    Fixture fixture = getFixture(fixtureId);
    // Get the instrument, creating it & appending
    // to the collection, if it doesn't exist
    fixture.getInstrument(instrumentId);

    // do some updates...ommitted

    fixtureRepository.save(fixture);

    fixtureCache.put(new Element(fixtureId, fixture));      
}

/**
* Returns a fixture.
* Returns from the cache first, if present
* If not present in the cache, the db is checked.
* Finally, if the fixture does not exist, a new one is 
* created and returned 
*/
Fixture getFixture(String fixtureId) {
    Fixture fixture;
    Element element = fixtureCache.get(fixtureId);
    if (element != null)
    {
        fixture = element.getValue();
    } else {
        fixture = fixtureRepostiory.findOne(fixtureId);
        if (fixture == null) 
        {
            fixture = new Fixture(fixtureId);
        }
    }
    return fixture;
}

}

1 个答案:

答案 0 :(得分:1)

答案很简单。

update方法中,我忽略了save()操作的结果。 通常,如果您不打算再次使用对象,这很好。 (这很常见,因为你在工作单元结束时保存)。

然而,当我继续使用我的'父母'时,我需要观察返回的值:

所以这个:

fixtureRepository.save(fixture);
fixtureCache.put(new Element(fixtureId, fixture));      

成为这个:

fixture = fixtureRepository.save(fixture);
fixtureCache.put(new Element(fixtureId, fixture));