我在我们的服务层中有这段代码:
@Override
public <T extends BaseEntity> T find(Long id, Class<? extends BaseEntity> clazz) throws Exception {
BaseEntity e = em.find(clazz, id);
if (e != null) {
deserialize(e, e.getClass());
} else
LOG.error("Found null for id " + id);
return (T) e;
}
public void delete(BaseEntity e, String index, String type) throws Exception {
if (e == null)
return;
if (e.getId() == null)
return;
Delete delete = new Delete.Builder(e.getId().toString()).index(index).type(type).build();
getJestClient().execute(delete);
if (em.contains(e)) {
em.remove(e);
} else {
BaseEntity ee = find(e.getId(), e.getClass());
em.remove(ee);
}
}
protected void deserialize(BaseEntity dst, Class<?> dstClass) throws Exception {
Object src = serializer.deserialize(new String(dst.getContent(), "UTF-8"), dstClass);
for (Field f : getClassFields(src.getClass())) {
if (Modifier.isStatic(f.getModifiers())) continue;
if (!f.isAnnotationPresent(Expose.class)) continue;
f.setAccessible(true);
f.set(dst, f.get(src));
LOG.trace("deserializing " + f.getName() + " : " + f.get(src));
}
}
但是,如果我用它来删除实体,它将失败:
Caused by: java.lang.IllegalArgumentException: Removing a detached instance FooEntity
at org.hibernate.ejb.event.EJB3DeleteEventListener.performDetachedEntityDeletionCheck(EJB3DeleteEventListener.java:65)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:107)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:73)
at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:956)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:934)
at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:867)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy42.remove(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy31.remove(Unknown Source)
... 16 more
但这对我来说毫无意义,因为之前的行em.remove(ee)
,实体是通过 find 方法加载的,因此它不能被分离......事务是通过 spring xml 配置实现的
// 编辑:添加反序列化方法。基本上,它将获取与每个对象一起存储的 json 内容并创建对象的副本,然后将字段分配给该副本。getJestClient().execute 是 elasticsearch 的 handler,与 hibernate 和 jpa 无关。
Em 是通过 spring 创建的:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dsFoo">
<property name="driverClassName" value="${foo.census.driverClassName}"/>
<property name="url" value="${foo.census.url}"/>
<property name="username" value="${foo.census.user}"/>
<property name="password" value="${foo.census.password}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emfCensus">
<property name="persistenceUnitName" value="puFoo"/>
<property name="dataSource" ref="dsFoo"/>
</bean>
<bean id="emFoo" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name = "entityManagerFactory" ref="emfFoo"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emfFoo" />
<property name="persistenceUnitName" value="puFoo" />
</bean>
<bean id="repoFoo" class="service.FooService">
<property name="entityManager" ref="emFoo" />
</bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<aop:config>
<aop:pointcut id="repoFooOperation" expression="execution(* service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdviceFoo" pointcut-ref="repoFooOperation"/>
</aop:config>
<tx:advice id="txAdviceFoo" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>