【问题标题】:Spring JPA Base RepositorySpring JPA 基础存储库
【发布时间】:2019-08-02 02:26:30
【问题描述】:

我创建了一个自定义存储库来覆盖持久性方法,并尝试按照spring docs 中的描述将其连接起来。我没有收到任何错误,所有实体和存储库都在启动时找到,当我调用 repo.saveAll(entities) 时,持久性正常工作。但是,我的自定义代码永远不会被调用。我在我的代码中添加了日志语句,甚至抛出了 RuntimeExceptions,只是为了查看它是否正在执行,但它肯定被忽略了。我错过了哪一步?

@Configuration
@Profile("test")
@EnableJpaRepositories(repositoryBaseClass = SetClientInfoRepositoryImpl.class,
        basePackages = {"gov.penndot.hwy.apras.common.repository" }, 
        entityManagerFactoryRef = "serviceEntityManagerFactory", 
        transactionManagerRef = "serviceTransactionManager")
public class TestDatabaseConfig {

    @Bean(name = "serviceDataSource")
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
        dataSource.setUsername("sa");
        dataSource.setPassword("sa");

        return dataSource;
    }

    @Bean
    public EntityManagerFactoryBuilder entityManagerFactoryBuilder() {
        return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), new HashMap<String, Object>(), null);
    }

    @Bean(name = "serviceEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean serviceEntityManagerFactory(EntityManagerFactoryBuilder builder,
            @Qualifier("serviceDataSource") DataSource dataSource) {

        return builder
                .dataSource(dataSource)
                .packages("stuff")
                .persistenceUnit("service")
                .build();
    }

    @Bean(name = "serviceTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("serviceEntityManagerFactory") EntityManagerFactory serviceEntityManagerFactory) {
        return new JpaTransactionManager(serviceEntityManagerFactory);
    }

存储库:

@NoRepositoryBean
    public class SetClientInfoRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> {
        private static final Logger log = LoggerFactory.getLogger(SetClientInfoRepositoryImpl.class);
        private final EntityManager em;

        public SetClientInfoRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
            super(entityInformation, entityManager);
            this.em = entityManager;
        }

        @Transactional
        @Override
        public <S extends T> S save(S entity) {
            setClientInfo();
            return super.save(entity);
        }

        @Transactional
        @Override
        public void deleteById(ID id) {
            setClientInfo();
            super.deleteById(id);
        }

        @Transactional
        @Override
        public void delete(T entity) {
            setClientInfo();
            super.delete(entity);
        }

        @Transactional
        @Override
        public void deleteAll(Iterable<? extends T> entities) {
            setClientInfo();
            super.deleteAll(entities);
        }

        @Transactional
        @Override
        public void deleteInBatch(Iterable<T> entities) {
            setClientInfo();
            super.deleteInBatch(entities);
        }

        @Transactional
        @Override
        public void deleteAll() {
            setClientInfo();
            super.deleteAll();
        }

        @Transactional
        @Override
        public void deleteAllInBatch() {
            setClientInfo();
            super.deleteAllInBatch();
        }

        @Transactional
        @Override
        public <S extends T> S saveAndFlush(S entity) {
            setClientInfo();
            return super.saveAndFlush(entity);
        }

        @Transactional
        @Override
        public <S extends T> List<S> saveAll(Iterable<S> entities) {
            setClientInfo();
            super.saveAll(entities);
            throw new RuntimeException("foo");
        }

        private void setClientInfo() {
            log.debug("Entering setClientInfo method");
            [stuff]
        }
    }

【问题讨论】:

  • 确认一下,您调用的是 SetClientInfoRepositoryImpl 中的 saveAll() 方法,而不是其他类?这里要做的典型事情是为 SetClientInfoRepository 创建一个接口,在需要的地方自动装配/注入该存储库,然后使用该接口调用 saveAll() 方法。 stackoverflow.com/questions/13036159/…
  • 你确定你的主配置类,你使用@EnableJpaRepositories的地方是用@Profile("!test")注解的吗?
  • @Derek - (感谢您的回复!)我在注释为存储库的不同接口上调用 saveAll() 方法。为什么我需要另一个接口,当方法相同,并且 spring 文档不要求一个时?当需要自定义方法时,我使用了自定义接口
  • @Selindek - (感谢您的回复!)是的,配置文件不是问题。正确的数据库配置正在加载到 Spring 中,因为所有持久性都发生在配置类中定义的 h2 db 中
  • 好的,那么让我们确定原来的@EnableJpaRepositories 未被选中:将其注释掉并以这种方式运行测试。

标签: java spring spring-data-jpa jpa-2.0


【解决方案1】:

好的,这是一个非常绝望的想法,但值得一试......

创建自定义仓库接口:

public interface SetClientInfoRepository<T, ID> extends JpaRepository<T, ID> {
}

通过您的自定义基础存储库实现此存储库接口:

public class SetClientInfoRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements SetClientInfoRepository<T, ID> {
}

... 最后通过您的存储库接口而不是JpaRepository 扩展此接口

以这种方式,Spring 必须从您的实现中创建存储库代理,因为它没有其他类可以使用。此外,如果它由于任何原因无法创建存储库,您将在启动期间获得更多信息的异常。

使用自定义存储库接口本身并不是一件坏事,因为您总是很有可能希望稍后将一些常用的自定义方法添加到存储库中,然后它就会派上用场。

【讨论】:

  • 感谢您的帮助!你的回答确实有效。我创建了一个新的简单项目并让原始的 baseRepositoryClass 注释正常工作,所以我确定我一定在某个地方搞砸了
  • 我相信 Spring Data JPA(和 Spring Data Rest)是(之一)最复杂的 Spring 包。如果这个问题是由于其中的错误而发生的,我不会感到惊讶。
猜你喜欢
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-26
  • 2020-07-15
相关资源
最近更新 更多