Home > Blockchain >  spring-data - multiple DB: NoUniqueBeanDefinitionException No qualifying bean of type 'Transact
spring-data - multiple DB: NoUniqueBeanDefinitionException No qualifying bean of type 'Transact

Time:11-20

I have created a spring-data project (version = 2.5.5) with two datasources GitHub. It works fine, as long, as I am using the interface CrudRepository.java. But when I am trying to implement my own DAO based on SimpleJpaRepository.java I am getting the error

No qualifying bean of type 'org.springframework.transaction.TransactionManager' available: expected single matching bean but found 2: db1TransactionManager,db2TransactionManager

DB2Config.java (DB1Config.java is the same but instead of '2' the bean names has '1')

@Configuration
@PropertySource("classpath:db2-config.properties")
@EnableJpaRepositories(
        basePackages = "com.vscoding.jpa.db2.entity",
        entityManagerFactoryRef = "db2EntityManagerFactory",
        transactionManagerRef = "db2TransactionManager"
)
public class DB2Config {

  @Bean
  @ConfigurationProperties(prefix = "db2.datasource")
  public DataSource db2DataSource() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  public FactoryBean<EntityManagerFactory> db2EntityManagerFactory(@Qualifier("db2DataSource") DataSource db2DataSource, Environment env){
    var em = new LocalContainerEntityManagerFactoryBean();
    var va = new HibernateJpaVendorAdapter();
    var properties = new HashMap<String,Object>();

    properties.put("hibernate.hbm2ddl.auto","create");
    em.setDataSource(db2DataSource);
    em.setPackagesToScan("com.vscoding.jpa.db2.entity");
    em.setJpaVendorAdapter(va);
    em.setJpaPropertyMap(properties);

    return em;
  }

  @Bean
  public PlatformTransactionManager db2TransactionManager(@Qualifier("db2EntityManagerFactory") FactoryBean<EntityManagerFactory> db2EntityManagerFactory) throws Exception {
    var tm = new JpaTransactionManager();

    tm.setEntityManagerFactory(db2EntityManagerFactory.getObject());

    return tm;
  }

  @Bean
  @Profile("with-init")
  public DataSourceInitializer dataSourceInitializer2(@Qualifier("db2DataSource") DataSource datasource) {
    var populator = new ResourceDatabasePopulator();
    populator.addScript(new ClassPathResource("db2.sql"));

    DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
    dataSourceInitializer.setDataSource(datasource);
    dataSourceInitializer.setDatabasePopulator(populator);

    return dataSourceInitializer;
  }
}

ProductCustomRepository.java

@Repository
@Transactional(transactionManager = "db2TransactionManager")
public class ProductCustomRepository extends SimpleJpaRepository<ProductEntity2, Integer> {
  private final EntityManager entityManager;

  public ProductCustomRepository(@Qualifier("db2EntityManagerFactory") EntityManager entityManager) {
    super(ProductEntity2.class, entityManager);
    this.entityManager = entityManager;
  }

  public List<ProductEntity2> customQuery() {
    var query = entityManager.createQuery("SELECT p FROM ProductEntity2 p WHERE p.name='special'",ProductEntity2.class);

    return query.getResultList();
  }
}

I would expect, that @Transactional(transactionManager = "db2TransactionManager") would select the right transactionManager, but maybe I am missing something.

ProductCustomRepositoryTest.java (test to reproduce the error)

@SpringBootTest
class ProductCustomRepositoryTest {
  @Autowired
  private ProductCustomRepository sut;

  @Test
  void customQuery() {
    //Given
    var special = new ProductEntity2("special");
    sut.save(special);

    //When
    var result = sut.customQuery();

    //Then
    assertTrue(result.contains(special));
  }
}

Thanks in advance.

CodePudding user response:

As mentioned by Simon, I could solve the error, by following https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations

Changed my ProductCustomRepository.javato CustomRepositoryImpl.java and added Interface CustomRepository.java

@Repository
@Transactional(transactionManager = "db2TransactionManager")
public class CustomRepositoryImpl implements CustomRepository {
  // no changes here
}

Then extend my main Repository with the interface.

public interface ProductRepository2 extends CrudRepository<ProductEntity2,Integer>,CustomRepository {
}
  • Related