Spring Data Custom Implementation:实体未管理

时间:2013-08-05 23:58:17

标签: java spring spring-data

我创建了一个使用Spring Data + Hibernate + JPA + Quartz的Web应用程序。在我的一个Quartz作业中,我需要刷新一个实体,因为用户可能已经通过用户界面更改了实体。基本上,实体包含Quartz作业的配置,如果实体在作业外部更改,则实体中的数据是陈旧的,因此我想在保留实体之前刷新,以便它不会覆盖更新的信息。

由于Spring Data确实在存储库上提供了刷新方法,因此我为Spring Data中的所有存储库创建了一个自定义实现。

以下是我设置自定义实现的方法:

CustomRepository.java(接口)

@NoRepositoryBean
public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {

    public void refresh(T entity);
}

CustomRepositoryImpl.java(实施)

@NoRepositoryBean
public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomRepository<T, ID> {

    private EntityManager entityManager;

    public CustomRepositoryImpl(Class<T> domainClass, EntityManager entityManager){
        super(domainClass, entityManager);

        this.entityManager = entityManager;
    }

    public void refresh(T entity) {
        this.entityManager.refresh(entity);

    }
}

CustomRepositoryFactoryBean.java(Spring Bean for Spring)

public class CustomRepositoryFactoryBean<T extends JpaRepository<S,ID>,S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {

    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager){
        return new CustomRepositoryFactory(entityManager);
    }

    private static class CustomRepositoryFactory<T, ID extends Serializable> extends JpaRepositoryFactory{

        private EntityManager entityManager;

        public CustomRepositoryFactory(EntityManager entityManager) {
            super(entityManager);
            this.entityManager = entityManager;
        }

        protected Object getTargetRepository(RepositoryMetadata metadata){
            return new CustomRepositoryImpl<T, ID>((Class<T>) metadata.getDomainType(), entityManager);
        }

        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata){
            return CustomRepository.class;
        }
    }
}

弹簧-config.xml中

<jpa:repositories base-package="com.network.socially.data.repositories" 
  factory-class="com.network.socially.data.repositories.custom.CustomRepositoryFactoryBean">  
</jpa:repositories>

当应用程序通过Tomcat初始化时,自定义实现的设置似乎有效,但是当我尝试调用refresh方法时,我收到异常。

以下是调用refresh方法的代码:

public void execute(JobExecutionContext context) throws JobExecutionException {
    super.logExecution(context);
    super.initialize(context);

    this.extractObjects();

    MyJob myJob = this.myJobRepository.findOne(super.applicationJob.getJobId());
    this.myJobRepository.refresh(myJob);
        this.myJobRepository.save(myJob);
}

抛出异常:

Caused by: java.lang.IllegalArgumentException: Entity not managed
    at org.hibernate.ejb.AbstractEntityManagerImpl.refresh(AbstractEntityManagerImpl.java:914)
    at org.hibernate.ejb.AbstractEntityManagerImpl.refresh(AbstractEntityManagerImpl.java:895)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
    at $Proxy25.refresh(Unknown Source)
    at com.network.socially.data.repositories.custom.CustomRepositoryImpl.refresh(CustomRepositoryImpl.java:22)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:333)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    ... 10 more

我不明白为什么不管理实体,因为从数据库中检索实体导致它在持久化上下文中被管理。

有谁可以指出我哪里出错了?我是否需要使用JTA而不是RESOURCE-LOCAL?当我通过JPA检索实体时,为什么不管理实体?

2 个答案:

答案 0 :(得分:2)

问题是您在调用refresh()时需要一个事务。 Spring Data JPA中的所有存储库方法都会自动为您自动执行此操作。最简单的方法是使用Spring的@Transactional,假设你enabled Spring transaction management。例如:

@Transactional
public void execute(JobExecutionContext context) throws JobExecutionException {
  super.logExecution(context);
  super.initialize(context);

  this.extractObjects();

  MyJob myJob = this.myJobRepository.findOne(super.applicationJob.getJobId());
  this.myJobRepository.refresh(myJob);
  this.myJobRepository.save(myJob);
}

以上假设定义此方法的对象实例是Spring管理的 - 即Spring bean。事务的边界扩展到整个方法。上述方法的缺点是,如果您在多个位置调用refresh(),则需要确保在每个位置的事务内调用它。

答案 1 :(得分:0)

尝试在合并前使用合并。

library(gpuR)

A <- seq.int(from=0, to=999)
B <- seq.int(from=1000, to=1)
gpuA <- gpuVector(A)
gpuB <- gpuVector(B)

C <- A + B
gpuC <- gpuA + gpuB

all.equal(C, gpuC)
#> [1] "Modes: numeric, S4"                             
#> [2] "Attributes: < target is NULL, current is list >"
#> [3] "target is numeric, current is igpuVector"
all.equal(C, gpuC[])
#> [1] TRUE