将 JpaRepository 与 Spring 数据和 Hibernate 一起使用

Posted

技术标签:

【中文标题】将 JpaRepository 与 Spring 数据和 Hibernate 一起使用【英文标题】:Use of JpaRepository with Spring data and Hibernate 【发布时间】:2015-12-26 23:34:07 【问题描述】:

我一直在使用 Spring 数据和 hibernate,我想知道什么是避免代码浪费的最好的类组织。 这是我的实际结构:

    public interface FleetRepository extends JpaRepository<Fleet, Integer> 

那我就用这个接口

public interface FleetServices 

     //Create one row into Fleet table, if id already exists this method executes an update
     public Fleet create(Fleet fleet);
     //Check if a fleet with given id already exists
     public boolean exists(int id);

因此我实现了它

@Service
public class FleetServicesImpl implements FleetServices

    @Resource
    private FleetRepository fleetRepository;

    @Override
    @Transactional
    public Fleet create(Fleet fleet) 
         return fleetRepository.save(fleet);
    

    @Override
    @Transactional
    public boolean exists(int id)
        return fleetRepository.exists(id);
    

鉴于我有几个使用相同方法的类(例如保存、创建...),我想创建一个通用类来用于所有这些方法,就像这样

public interface GeneralRepository<T, Id extends Serializable> extends JpaRepository<T, Id> 
    

然后

public interface GeneralServices<T,Id> 
    //Create one row into T table, if id already exists this method executes an update
    public T create(T object);
    //Check if a row with given id already exists
    public boolean exists(Id id);
    //Find a row into T table by Id
    public T findById(Id id);

终于

public class GeneralServicesImpl<T, Id extends Serializable > implements GeneralServices<T, Id> 

    @Resource
    private GeneralRepository<T,Id> generalRepository;

    @Override
    @Transactional
    public T create(T object) 
        return generalRepository.save(object);
    

    @Override
    @Transactional
    public boolean exists(Id id) 
        return generalRepository.exists(id);
    

    @Override
    @Transactional
    public T findById(Id id) 
        return generalRepository.getOne(id);
    


然后我在我的 FleetServicesImpl 中使用这个类

@Service
public class FleetServicesImpl extends GeneralServicesImpl<Fleet, Integer> implements FleetServices   

所以在databaseServicesImpl中

@Service

公共类 DatabaseServicesImpl 实现 DatabaseServices

@Autowired
private FleetServices fleetServices;
@Autowired
private EcuServicesImpl ecuServices;

public DatabaseServicesImpl() 


@Override
public void archiveAcquisition() 
    ecuServices.create(new Ecu("MM"));
    Ecu ecuId=ecuServices.findById("MM");
    Fleet fleet=new Fleet(ecuId,"334","2.9",170,"5+","Full","4x2","MT");
    System.out.println(ecuId.getIdEcu());
    fleetServices.create(fleet);

但我得到了这个例外

16:41:43.465 错误 o.s.web.context.ContextLoader - 上下文初始化失败 org.springframework.beans.factory.BeanCreationException:创建名为“databaseServicesImpl”的bean时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:私有 com.mkyong.services.EcuServicesImpl com.mkyong.services.DatabaseServicesImpl.ecuServices;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为“ecuServicesImpl”的 bean 时出错:资源依赖项注入失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为“generalRepository”的 bean 时出错:调用 init 方法失败;嵌套异常是 java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:834) ~[spring-context-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537) ~[spring-context-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:446) ~[spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:328) ~[spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107) [spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4727) [catalina.jar:8.0.26] 在 org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5167) [catalina.jar:8.0.26] 在 org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:8.0.26] 在 org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408) [catalina.jar:8.0.26] 在 org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398) [catalina.jar:8.0.26] 在 java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_60] 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60] 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60] 在 java.lang.Thread.run(Thread.java:745) [na:1.8.0_60] 原因:org.springframework.beans.factory.BeanCreationException:无法自动装配字段:private com.mkyong.services.EcuServicesImpl com.mkyong.services.DatabaseServicesImpl.ecuServices;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为“ecuServicesImpl”的 bean 时出错:资源依赖项注入失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为“generalRepository”的 bean 时出错:调用 init 方法失败;嵌套异常是 java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:571) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] ...省略了22个常用框架 原因:org.springframework.beans.factory.BeanCreationException:创建名为“ecuServicesImpl”的bean时出错:资源依赖注入失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为“generalRepository”的 bean 时出错:调用 init 方法失败;嵌套异常是 java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object 在 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:311) ~[spring-context-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1145) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1069) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:967) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:543) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] ...省略了24个常用框架 原因:org.springframework.beans.factory.BeanCreationException:创建名为“generalRepository”的bean时出错:调用init方法失败;嵌套异常是 java.lang.IllegalArgumentException: Not an manageset 29, 2015 4:41:43 PM org.apache.catalina.core.StandardContext listenerStart

【问题讨论】:

如果你的服务只是一个传递服务,为什么还要写一个呢。恕我直言,唯一有效的实现是DatabaseService,它应该是@Transactional。其他人将它们扔进垃圾箱并使用DatabaseService 中的存储库。 我更新了上面的代码。我认为存储库的类型必须在引导时知道, 【参考方案1】:

Quoting Oliver Gierke(Spring Data 项目负责人):

您得到的最后一个异常实际上表明您的 JPA 设置存在问题。 “不是托管 bean”意味着不是 JPA 提供者知道的类型。如果您正在设置基于 Spring 的 JPA 应用程序,我建议您在已配置到包含 JPA 实体的包的 LocalContainerEntityManagerFactory 上配置“packagesToScan”属性。或者,您可以在 persistence.xml 中列出所有实体类,但这通常比较麻烦。

确保您的 Spring 配置设置正确,似乎并非所有类都被 Spring 识别。

此外,heres an answer by Oliver 关于 Spring JPA 中的通用存储库,因为您似乎正在使用它。

【讨论】:

以上是关于将 JpaRepository 与 Spring 数据和 Hibernate 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data JPA - JpaRepository 中的自定义排序

如何在 Spring 中将 OrderBy 与 JPARepository 一起使用

Spring JpaRepository - 分离和附加实体

如何将对象从一个 JpaRepository 转换为另一个 JpaRepository

将 @EmbeddedId 与 JpaRepository 一起使用

Spring JpaRepository 中的 %Like% 查询