Spring Boot,带有多个数据源的Spring Data JPA

这是我正在尝试使用Spring Data JPA实现类似解决方案的代码。

CustomerDbConfig.java(第一个数据源连接)

@Configuration

@EnableJpaRepositories(

entityManagerFactoryRef = "orderEntityManager",

transactionManagerRef = "orderTransactionManager",

basePackages = {"com.mm.repository.customer"})

public class CustomerDbConfig {

@Bean(name = "customerEntityManager")

public LocalContainerEntityManagerFactoryBean entityManagerFactory(){

LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();

em.setDataSource(dataSource());

em.setPackagesToScan(new String[] {"com.mm.domain.customer"});

JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();

em.setJpaVendorAdapter(vendorAdapter);

em.setJpaProperties(additionalJpaProperties());

em.setPersistenceUnitName("customerPersistence");

em.setPackagesToScan("com.mm.domain.customer");

return em;

}

Properties additionalJpaProperties(){

Properties properties = new Properties();

properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");

properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");

properties.setProperty("hibernate.show_sql", "true");

return properties;

}

@Bean

public DataSource dataSource(){

return DataSourceBuilder.create()

.url("jdbc:h2:mem:customer:H2")

.driverClassName("org.h2.Driver")

.username("sa")

.password("")

.build();

}

@Bean(name = "customerTransactionManager")

public PlatformTransactionManager transactionManager(EntityManagerFactory emf){

JpaTransactionManager transactionManager = new JpaTransactionManager();

transactionManager.setEntityManagerFactory(emf);

return transactionManager;

}

}

CustomerDbConfig.java(第二个数据源)

@Configuration

@EnableJpaRepositories(

entityManagerFactoryRef = "orderEntityManager",

transactionManagerRef = "orderTransactionManager",

basePackages = {"com.mm.repository.customer"})

public class CustomerDbConfig {

@Bean(name = "customerEntityManager")

public LocalContainerEntityManagerFactoryBean entityManagerFactory(){

LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();

em.setDataSource(dataSource());

em.setPackagesToScan(new String[] {"com.mm.domain.customer"});

JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();

em.setJpaVendorAdapter(vendorAdapter);

em.setJpaProperties(additionalJpaProperties());

em.setPersistenceUnitName("customerPersistence");

em.setPackagesToScan("com.mm.domain.customer");

return em;

}

Properties additionalJpaProperties(){

Properties properties = new Properties();

properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");

properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");

properties.setProperty("hibernate.show_sql", "true");

return properties;

}

@Bean

public DataSource dataSource(){

return DataSourceBuilder.create()

.url("jdbc:h2:mem:customer:H2")

.driverClassName("org.h2.Driver")

.username("sa")

.password("")

.build();

}

@Bean(name = "customerTransactionManager")

public PlatformTransactionManager transactionManager(EntityManagerFactory emf){

JpaTransactionManager transactionManager = new JpaTransactionManager();

transactionManager.setEntityManagerFactory(emf);

return transactionManager;

}

}

...

Customer.java(模型)

...

@Entity

@Table(name = "customer")

@Data

@EqualsAndHashCode(exclude = {"id"})

public class Customer {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private Integer id;

@Column(name = "name", nullable = false)

private String name;

@Column(name = "age", nullable = false)

private Integer age;

....

Order.java(模型)

@Entity

@Table(name = "order")

@Data

@EqualsAndHashCode(exclude = {"id"})

public class Order {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private Integer id;

@Column(name = "code", nullable = false)

private Integer code;

@Column(name = "quality", nullable = false)

private Integer quality;

CustomerRepository.java

public interface CustomerRepository extends JpaRepository<Customer, Integer>{

}

OrderRepository.java

public interface OrderRepository extends JpaRepository<Order, Integer> {

}

最后,Application.java

@Configuration

@ComponentScan

@EnableAutoConfiguration

public class Application extends SpringApplication{

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

@Bean

public ServletRegistrationBean h2Console() {

ServletRegistrationBean reg = new ServletRegistrationBean(new WebServlet(), "/console/*");

reg.setLoadOnStartup(1);

return reg;

}

}

在启动过程中会引发以下异常:

-10-10 15:45:24.757 ERROR 1549 --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerTransactionManager' defined in class path resource [com/mm/boot/multidb/CustomerConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.persistence.EntityManagerFactory]: : No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager

at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)

at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1095)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:990)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)

at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)

at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)

at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)

at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)

at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)

at com.mm.boot.multidb.Application.main(Application.java:17)

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager

at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:974)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)

at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)

at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)

... 18 common frames omitted

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customerTransactionManager' defined in class path resource [com/mm/boot/multidb/CustomerConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.persistence.EntityManagerFactory]: : No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager

at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)

at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1095)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:990)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)

at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)

at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)

at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)

at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)

at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)

at com.mm.boot.multidb.Application.main(Application.java:17)

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: customerEntityManager,orderEntityManager

at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:974)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)

at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)

at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)

... 18 more

预先感谢你的帮助。

回答:

通过使用@EnableAutoConfiguration和application.properties,还有另一种具有多个数据源的方法。

基本上,将多个dataSource配置信息放在application.properties上,并通过@EnableAutoConfiguration自动为第一个dataSource生成默认设置(dataSource和EntityManagerFactory)。但是对于下一个dataSource,请通过属性文件中的信息手动创建dataSource,entityManagerFactory和transactionManager。

下面是我设置两个数据源的示例。第一个数据源由@EnableAutoConfiguration设置,只能分配给一个配置,不能分配给多个。然后将通过DataSourceTransactionManager生成“ transactionManager” ,该外观看起来是由注释生成的默认transactionManager。但是,我已经看到,仅对于默认的DataSourceTransactionManager以及在有多个事务管理器的情况下,调度线程池中的线程上的事务才不会开始出现问题。所以我通过JpaTransactionManager手动创建transactionManager也为第一个dataSource分配了“ transactionManager” Bean名称和默认的entityManagerFactory。用于第一个数据源的JpaTransactionManager确实可以解决ScheduledThreadPool中线程上的奇怪事务问题。

Spring Boot 1.3.0.RELEASE的更新

我发现我以前使用@EnableAutoConfiguration的默认dataSource配置在使用Spring Boot 1.3版本查找entityManagerFactory时遇到问题。引入我自己的transactionManager之后,也许@EnableAutoConfiguration不会生成默认的entityManagerFactory。所以现在我自己创建了entityManagerFactory。因此,我不需要使用@EntityScan。因此,看起来我通过@EnableAutoConfiguration获得的安装越来越少。

第二个数据源是在没有@EnableAutoConfiguration的情况下设置的,并通过手动方式创建了“ anotherTransactionManager”。

由于从PlatformTransactionManager扩展了多个transactionManager,因此我们应在每个@Transactional注释上指定要使用的transactionManager

默认存储库配置

@Configuration

@EnableTransactionManagement

@EnableAutoConfiguration

@EnableJpaRepositories(

entityManagerFactoryRef = "entityManagerFactory",

transactionManagerRef = "transactionManager",

basePackages = {"com.mysource.repository"})

public class RepositoryConfig {

@Autowired

JpaVendorAdapter jpaVendorAdapter;

@Autowired

DataSource dataSource;

@Bean(name = "entityManager")

public EntityManager entityManager() {

return entityManagerFactory().createEntityManager();

}

@Primary

@Bean(name = "entityManagerFactory")

public EntityManagerFactory entityManagerFactory() {

LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();

emf.setDataSource(dataSource);

emf.setJpaVendorAdapter(jpaVendorAdapter);

emf.setPackagesToScan("com.mysource.model");

emf.setPersistenceUnitName("default"); // <- giving 'default' as name

emf.afterPropertiesSet();

return emf.getObject();

}

@Bean(name = "transactionManager")

public PlatformTransactionManager transactionManager() {

JpaTransactionManager tm = new JpaTransactionManager();

tm.setEntityManagerFactory(entityManagerFactory());

return tm;

}

}

另一个存储库配置

@Configuration

@EnableTransactionManagement

@EnableJpaRepositories(

entityManagerFactoryRef = "anotherEntityManagerFactory",

transactionManagerRef = "anotherTransactionManager",

basePackages = {"com.mysource.anothersource.repository"})

public class AnotherRepositoryConfig {

@Autowired

JpaVendorAdapter jpaVendorAdapter;

@Value("${another.datasource.url}")

private String databaseUrl;

@Value("${another.datasource.username}")

private String username;

@Value("${another.datasource.password}")

private String password;

@Value("${another.dataource.driverClassName}")

private String driverClassName;

@Value("${another.datasource.hibernate.dialect}")

private String dialect;

public DataSource dataSource() {

DriverManagerDataSource dataSource = new DriverManagerDataSource(databaseUrl, username, password);

dataSource.setDriverClassName(driverClassName);

return dataSource;

}

@Bean(name = "anotherEntityManager")

public EntityManager entityManager() {

return entityManagerFactory().createEntityManager();

}

@Bean(name = "anotherEntityManagerFactory")

public EntityManagerFactory entityManagerFactory() {

Properties properties = new Properties();

properties.setProperty("hibernate.dialect", dialect);

LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();

emf.setDataSource(dataSource());

emf.setJpaVendorAdapter(jpaVendorAdapter);

emf.setPackagesToScan("com.mysource.anothersource.model"); // <- package for entities

emf.setPersistenceUnitName("anotherPersistenceUnit");

emf.setJpaProperties(properties);

emf.afterPropertiesSet();

return emf.getObject();

}

@Bean(name = "anotherTransactionManager")

public PlatformTransactionManager transactionManager() {

return new JpaTransactionManager(entityManagerFactory());

}

}

application.properties

# database configuration

spring.datasource.url=jdbc:h2:file:~/main-source;AUTO_SERVER=TRUE

spring.datasource.username=sa

spring.datasource.password=

spring.datasource.driver-class-name=org.h2.Driver

spring.datasource.continueOnError=true

spring.datasource.initialize=false

# another database configuration

another.datasource.url=jdbc:sqlserver://localhost:1433;DatabaseName=another;

another.datasource.username=username

another.datasource.password=

another.datasource.hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect

another.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

为@Transactional注释选择适当的transactionManager

第一数据源服务

@Service("mainService")

@Transactional("transactionManager")

public class DefaultDataSourceServiceImpl implements DefaultDataSourceService

{

//

}

为另一个数据源提供服务

@Service("anotherService")

@Transactional("anotherTransactionManager")

public class AnotherDataSourceServiceImpl implements AnotherDataSourceService

{

//

}

以上是 Spring Boot,带有多个数据源的Spring Data JPA 的全部内容, 来源链接: utcz.com/qa/429779.html

回到顶部