具有多个数据源和外部配置的 Spring Boot,Spring JPA
Posted
技术标签:
【中文标题】具有多个数据源和外部配置的 Spring Boot,Spring JPA【英文标题】:Spring Boot with multiple datasources and external configuration, Spring JPA 【发布时间】:2015-07-01 09:22:22 【问题描述】:我有一个带有 2 个外部 jar 的简单 Spring Boot 应用程序。每个 jar 都使用 Spring JPA 并完全配置为独立工作。
Jar1
JPA 存储库
@Repository
public interface QuarterRepository extends JpaRepository<Quarter, Long>
实体
@Entity
public class Quarter implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;...
配置
@Configuration
@Import(RepositoryConfig.class)
public class OnlineJpaAppConfig
@Bean(name = "onlinejpaAppConfigConfigurer")
public static PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer()
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocation(new ClassPathResource("/de/comp/onlinejpa/application.properties"));
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
@Configuration
@EnableJpaRepositories(basePackages = "de.comp.onlinejpa.repository",
entityManagerFactoryRef = "onlinejpaentityManagerFactory",
transactionManagerRef = "onlinejpaTransactionManager")
@EnableTransactionManagement
public class RepositoryConfig
@Value("$jdbc.driverClassName")
private String driverClassName;
@Value("$jdbc.url")
private String url;
@Value("$jdbc.username")
private String username;
@Value("$jdbc.password")
private String password;
@Value("$hibernate.dialect")
private String hibernateDialect;
@Value("$hibernate.show_sql")
private String hibernateShowSql;
@Value("$hibernate.hbm2ddl.auto")
private String hibernateHbm2ddlAuto;
private static final String QUALIFIER = "onlinejpa";
@Bean(name = "onlinejpaentityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[]"de.comp.onlinejpa.entity");
em.setPersistenceUnitName("onlinejpa");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
@Bean(name = "onlinejpaDataSource")
public DataSource dataSource()
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
@Bean(name = "onlinejpaTransactionManager")
public PlatformTransactionManager transactionManager(@Qualifier(value = "onlinejpaentityManagerFactory") EntityManagerFactory onlinejpaentityManagerFactory)
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(onlinejpaentityManagerFactory);
return transactionManager;
@Bean(name = "onlinejpaExceptionTranslation")
public PersistenceExceptionTranslationPostProcessor exceptionTranslation()
return new PersistenceExceptionTranslationPostProcessor();
Properties additionalProperties()
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", hibernateHbm2ddlAuto);
properties.setProperty("hibernate.dialect", hibernateDialect);
return properties;
第二个 jar 看起来和 Jar1 几乎一样,除了 bean 和包名
@EnableJpaRepositories(basePackages = "de.comp.aisjpa.repository",
entityManagerFactoryRef = "aisjpaentityManagerFactory",
transactionManagerRef = "aisjpatransactionManager")
@EnableTransactionManagement
public class RepositoryConfig
@Value("$jdbc.driverClassName")
private String driverClassName;
@Value("$jdbc.url")
private String url;
@Value("$jdbc.username")
private String username;
@Value("$jdbc.password")
private String password;
@Value("$hibernate.dialect")
private String hibernateDialect;
@Value("$hibernate.show_sql")
private String hibernateShowSql;
@Value("$hibernate.hbm2ddl.auto")
private String hibernateHbm2ddlAuto;
private static final String QUALIFIER = "aisjpa";
@Bean(name = "aisjpaentityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(aisdataSource());
em.setPackagesToScan(new String[]"de.comp.aisjpa.entity");
em.setPersistenceUnitName("ais");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
@Bean(name = "aisjpadatasource")
public DataSource aisdataSource()
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
@Bean(name = "aisjpatransactionManager")
public PlatformTransactionManager transactionManager(@Qualifier(value = "aisjpaentityManagerFactory") EntityManagerFactory aisjpaentityManagerFactory)
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(aisjpaentityManagerFactory);
return transactionManager;
@Bean(name = "aisjpaexceptionTranslation")
public PersistenceExceptionTranslationPostProcessor exceptionTranslation()
return new PersistenceExceptionTranslationPostProcessor();
Properties additionalProperties()
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", hibernateHbm2ddlAuto);
properties.setProperty("hibernate.dialect", hibernateDialect);
return properties;
在 Jar1 中运行这个 Main 类会得到预期的结果..(与 Jar2 相同)
public class App
public static void main(String[] args)
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(OnlineJpaAppConfig.class);
QuarterRepository quarterRepository = ctx.getBean("quarterRepository", QuarterRepository.class);
List<Quarter> quarters = quarterRepository.findAll();
for (Quarter quarter : quarters)
System.out.println(quarter.getQuarter());
这是我的 Spring Boot 应用程序的启动类
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class )
@Import( KVLdapAppConfig.class, OnlineJpaAppConfig.class,AISAppConfig.class)
public class ServerApplication
public static void main(String[] args)
SpringApplication.run(ServerApplication.class, args);
服务器启动没有问题,但是在配置 jpa 的过程中出现了一些问题。持久性单元 ais 的配置应使用 Oracle 方言和驱动程序。似乎它采用了 Jar1 的配置。
Building JPA container EntityManagerFactory for persistence unit 'onlinejpa'
HCANN000001: Hibernate Commons Annotations 4.0.1.Final
HHH000412: Hibernate Core 4.2.0.Final
HHH000206: hibernate.properties not found
HHH000021: Bytecode provider name : javassist
HHH000204: Processing PersistenceUnitInfo [
HHH000130: Instantiating explicit connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
HHH000400: Using dialect: org.hibernate.dialect.mysql5Dialect
HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory
HHH000397: Using ASTQueryTranslatorFactory
Loaded JDBC driver: com.mysql.jdbc.Driver
Building JPA container EntityManagerFactory for persistence unit 'ais'
HHH000204: Processing PersistenceUnitInfo [
HHH000130: Instantiating explicit connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
HHH000400: Using dialect: **org.hibernate.dialect.MySQL5Dialect**
HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory
HHH000397: Using ASTQueryTranslatorFactory
Loaded JDBC driver: com.mysql.jdbc.Driver
下一个问题是数据库访问。 Spring 不知道它应该使用哪个事务管理器
: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: aisjpatransactionManager,onlinejpaTransactionManager
将一个 tx 管理器设置为 @Primary 解决了上述问题,但以在另一个库中找不到表结束,这是错误配置的 tx 管理器/持久性单元的原因。
也许我的问题是为每个单独的 jar 创建 LocalContainerEntityManagerFactoryBean 。相反,我应该使用以下代码来设置我的数据库连接,但这会破坏我的个人库。
public LocalContainerEntityManagerFactoryBean internalEntityManagerFactory(
EntityManagerFactoryBuilder builder)
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", "create");
return builder
.dataSource(internalDataSource())
.packages("package here")
.persistenceUnit("onlinjpa")
.properties(properties)
.build();
如何让每个单独的 jar 在 Spring Boot 应用程序中工作。
这是一个使用 Sping Boot 设置多个数据源的链接,但我不想在 Spring Boot 应用程序中配置我的 libs 数据源。
Multiple data source and schema creation in Spring Boot
【问题讨论】:
【参考方案1】:问题是注入了错误的属性值,这可能是由每个 jar 中的 PropertyPlaceholderConfigurer
的静态调用引起的。
随便用
@PropertySource("classpath:/de/comp/aisjpa/application.properties")
public class RepositoryConfig
@Autowired
private Environment env;
dataSource.setUrl(env.getRequiredProperty("jdbc.url"));
....
或者将静态调用留给PropertyPlaceholderConfigurer
,但在您的application.properties 中为属性添加前缀,这样每个属性值在您的整个应用程序中都是唯一的
来自
jdbc.driverClassName=oracle.jdbc.OracleDriver
到
jar1.jdbc.driverClassName=oracle.jdbc.OracleDriver
【讨论】:
以上是关于具有多个数据源和外部配置的 Spring Boot,Spring JPA的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring Boot 自动装配具有 jpa 和非 jpa 特征的多个数据源
spring boot框架学习学前掌握之重要注解-通过注解方式读取外部资源配置文件2
spring boot项目application.properties多环境配置文件jar包外部配置文件