休眠升级后无法写入只读对象
Can't write readonly object after hibernate upgrade
我正在升级到 Hibernate 4.3.8,我 运行 在单元测试中遇到了一个奇怪的问题。
我有一个用户 class 引用了一种语言 class
public class User{
@ManyToOne(cascade=CascadeType.MERGE,optional = true, fetch=FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Fetch(FetchMode.SELECT)
private Language language;
@Column
@NaturalId(mutable=false)
private String email;
}
@Entity
@Immutable
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
@NaturalIdCache(region=CacheRegion.NATURAL)
public class Language{
}
所以,升级后,我开始看到这个异常,因为用户 class 是这样加载的:
User user = (User) getSessionFactory().getCurrentSession()
.bySimpleNaturalId(User.class)
.load(email);
异常:
java.lang.UnsupportedOperationException: Can't write to a readonly object
at org.hibernate.cache.ehcache.internal.strategy.ReadOnlyEhcacheEntityRegionAccessStrategy.update(ReadOnlyEhcacheEntityRegionAccessStrategy.java:115)
at org.hibernate.cache.ehcache.internal.nonstop.NonstopAwareEntityRegionAccessStrategy.update(NonstopAwareEntityRegionAccessStrategy.java:216)
at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:211)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:144)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:244)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:215)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:140)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:138)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4126)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:503)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:468)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:213)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:275)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:151)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:989)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:716)
at org.hibernate.type.EntityType.resolve(EntityType.java:502)
at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:170)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:144)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:244)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:215)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:140)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:138)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4126)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:503)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:468)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:213)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:275)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:151)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
at org.hibernate.internal.SessionImpl.access00(SessionImpl.java:176)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2551)
at org.hibernate.internal.SessionImpl$SimpleNaturalIdLoadAccessImpl.load(SessionImpl.java:2794)
这里有什么建议吗?
所以,这似乎发生了,因为在此过程中的某个地方,当涉及到缓存时,Hibernate 开始以不同的方式处理在相同事务中创建的对象和在不同事务中创建的对象。
因此,如果您有一个单元测试,其中您在创建只读对象的事务中进行一些设置,即使您只写入一次它们,如果它们是在与测试。
解决方案是使用具有 Propagation.REQUIRES_NEW 的事务管理器在中央方法中创建一次性只读对象。你不能为此使用注释,顺便说一句
我正在升级到 Hibernate 4.3.8,我 运行 在单元测试中遇到了一个奇怪的问题。
我有一个用户 class 引用了一种语言 class
public class User{
@ManyToOne(cascade=CascadeType.MERGE,optional = true, fetch=FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Fetch(FetchMode.SELECT)
private Language language;
@Column
@NaturalId(mutable=false)
private String email;
}
@Entity
@Immutable
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
@NaturalIdCache(region=CacheRegion.NATURAL)
public class Language{
}
所以,升级后,我开始看到这个异常,因为用户 class 是这样加载的:
User user = (User) getSessionFactory().getCurrentSession()
.bySimpleNaturalId(User.class)
.load(email);
异常:
java.lang.UnsupportedOperationException: Can't write to a readonly object
at org.hibernate.cache.ehcache.internal.strategy.ReadOnlyEhcacheEntityRegionAccessStrategy.update(ReadOnlyEhcacheEntityRegionAccessStrategy.java:115)
at org.hibernate.cache.ehcache.internal.nonstop.NonstopAwareEntityRegionAccessStrategy.update(NonstopAwareEntityRegionAccessStrategy.java:216)
at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:211)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:144)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:244)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:215)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:140)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:138)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4126)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:503)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:468)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:213)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:275)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:151)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:989)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:716)
at org.hibernate.type.EntityType.resolve(EntityType.java:502)
at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:170)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:144)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:244)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:215)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:140)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:138)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:186)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4126)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:503)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:468)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:213)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:275)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:151)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
at org.hibernate.internal.SessionImpl.access00(SessionImpl.java:176)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2551)
at org.hibernate.internal.SessionImpl$SimpleNaturalIdLoadAccessImpl.load(SessionImpl.java:2794)
这里有什么建议吗?
所以,这似乎发生了,因为在此过程中的某个地方,当涉及到缓存时,Hibernate 开始以不同的方式处理在相同事务中创建的对象和在不同事务中创建的对象。
因此,如果您有一个单元测试,其中您在创建只读对象的事务中进行一些设置,即使您只写入一次它们,如果它们是在与测试。
解决方案是使用具有 Propagation.REQUIRES_NEW 的事务管理器在中央方法中创建一次性只读对象。你不能为此使用注释,顺便说一句