全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

详解基于Spring Boot与Spring Data JPA的多数据源配置

由于项目需要,最近研究了一下基于spring Boot与Spring Data JPA的多数据源配置问题。以下是传统的单数据源配置代码。这里使用的是Spring的Annotation在代码内部直接配置的方式,没有使用任何XML文件。

@Configuration 
@EnableJpaRepositories(basePackages = "org.lyndon.repository") 
@EnableTransactionManagement 
@PropertySource("classpath:application.properties") 
public class JpaConfig { 
   
  private static final String DATABASE_DRIVER = "db.driver"; 
  private static final String DATABASE_URL = "db.url"; 
  private static final String DATABASE_USER = "db.user"; 
  private static final String DATABASE_PASSWORD = "db.password"; 
  private static final String PACKAGES_TO_SCAN = "packages.to.scan"; 
  private static final String HIBERNATE_DIALECT = "hibernate.dialect"; 
  private static final String HIBERNATE_SHOW_SQL = "hibernate.show.sql"; 
   
  @Resource 
  private Environment env; 
   
  @Bean 
  public DataSource dataSource() { 
    DruidDataSource source = new DruidDataSource(); 
    source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER)); 
    source.setUrl(env.getRequiredProperty(DATABASE_URL)); 
    source.setUsername(env.getRequiredProperty(DATABASE_USER)); 
    source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD)); 
    return source; 
  } 
   
  @Bean 
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); 
    factory.setDataSource(dataSource()); 
    factory.setPersistenceProviderClass(HibernatePersistenceProvider.class); 
    factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN)); 
    factory.setJpaProperties(hibernateProperties()); 
    factory.afterPropertiesSet(); 
    return factory; 
  } 
   
  @Bean 
  public PlatformTransactionManager transactionManager() { 
    JpaTransactionManager manager = new JpaTransactionManager(); 
    manager.setEntityManagerFactory(entityManagerFactory().getObject()); 
    return manager; 
  } 
   
  @Bean 
  public HibernateExceptionTranslator hibernateExceptionTranslator() { 
    return new HibernateExceptionTranslator(); 
  } 
   
  private Properties hibernateProperties() { 
    Properties properties = new Properties(); 
    properties.put(HIBERNATE_DIALECT, env.getRequiredProperty(HIBERNATE_DIALECT)); 
    properties.put(HIBERNATE_SHOW_SQL, env.getRequiredProperty(HIBERNATE_SHOW_SQL)); 
    return properties; 
  } 
   
} 

但是这一配置是不能简单地扩展到多数据源配置的,因为Spring Boot默认会为开发人员做很多工作,而这些工作与多数据源的配置相冲突,因此需要修改原来的配置内容。网上有很多讲解多数据源配置的文章,但是这些文章大多使用的是XML配置的方式,而且没有使用Spring Boot等比较新的Spring框架技术(比如很多人使用实现AbstractRoutingDataSource这一Spring提供的抽象类的方式,还需要切面的支持,无疑是相当繁琐的),已经不适用于在最新的工程项目中使用了,因为最新的Spring框架可以为我们完成很多事情,我们只需要去适应新的方法即可。为此,我通过研究Spring的官方文档和不断调试,实现了新的多数据源配置的方法,在此贴出,仅供参考。

首先,Spring的JPA是直接支持多数据源配置的,因此我们可以在配置文件或者代码中直接配置多个数据源。由于多数据源配置可能会共享一些配置信息,因此使用继承体系实现这种配置是最合适的。在例子中,我的ORM框架使用的是hibernate,而与Hibernate相关的配置信息我都放在了配置基类BaseJpaConfg中,代码如下。

@Configuration 
@EnableTransactionManagement 
@PropertySource("classpath:application.properties") 
public class BaseJpaConfig { 
 
  private static final String HIBERNATE_DIALECT = "hibernate.dialect"; 
  private static final String HIBERNATE_SHOW_SQL = "hibernate.show.sql"; 
 
  @Resource 
  protected Environment env; 
 
  @Bean 
  public HibernateExceptionTranslator hibernateExceptionTranslator() { 
    return new HibernateExceptionTranslator(); 
  } 
 
  protected Properties hibernateProperties() { 
    Properties properties = new Properties(); 
    properties.put(HIBERNATE_DIALECT, env.getRequiredProperty(HIBERNATE_DIALECT)); 
    properties.put(HIBERNATE_SHOW_SQL, env.getRequiredProperty(HIBERNATE_SHOW_SQL)); 
    return properties; 
  } 
 
} 

该类提供Hibernate相关信息。它有两个子类,分别是SpringJpaConfig以及MysqlJpaConfig,分别配置了两个数据源,连接到两个不同的数据库Schema,代码如下。

@Configuration 
@EnableJpaRepositories(basePackages = {"org.lyndon.repository1"}, entityManagerFactoryRef = "springEntityManagerFactory", 
    transactionManagerRef = "springTransactionManager") 
public class SpringJpaConfig extends BaseJpaConfig { 
 
  private static final String DATABASE_DRIVER = "db.driver"; 
  private static final String DATABASE_URL = "db.url"; 
  private static final String DATABASE_USER = "db.user"; 
  private static final String DATABASE_PASSWORD = "db.password"; 
  private static final String PACKAGES_TO_SCAN = "packages.to.scan"; 
 
  @Bean 
  @ConfigurationProperties(prefix = "datasource.primary") 
  public DataSource dataSource() { 
    DruidDataSource source = new DruidDataSource(); 
    source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER)); 
    source.setUrl(env.getRequiredProperty(DATABASE_URL)); 
    source.setUsername(env.getRequiredProperty(DATABASE_USER)); 
    source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD)); 
    return source; 
  } 
 
  @Bean(name = "springEntityManagerFactory") 
  public LocalContainerEntityManagerFactoryBean springEntityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); 
    factory.setDataSource(dataSource()); 
    factory.setPersistenceProviderClass(HibernatePersistenceProvider.class); 
    factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN).split(",")); 
    factory.setJpaProperties(hibernateProperties()); 
    factory.afterPropertiesSet(); 
    return factory; 
  } 
 
  @Bean(name = "springTransactionManager") 
  @Primary 
  public PlatformTransactionManager transactionManager() { 
    JpaTransactionManager manager = new JpaTransactionManager(); 
    manager.setEntityManagerFactory(springEntityManagerFactory().getObject()); 
    return manager; 
  } 
 
} 
@Configuration 
@EnableJpaRepositories(basePackages = {"org.lyndon.repository2"}, entityManagerFactoryRef = "mysqlEntityManagerFactory", 
    transactionManagerRef = "mysqlTransactionManager") 
public class MysqlJpaConfig extends BaseJpaConfig { 
 
  private static final String DATABASE_DRIVER = "db.driver"; 
  private static final String DATABASE_URL = "db.url2"; 
  private static final String DATABASE_USER = "db.user"; 
  private static final String DATABASE_PASSWORD = "db.password"; 
  private static final String PACKAGES_TO_SCAN = "packages.to.scan2"; 
 
  @Bean 
  @ConfigurationProperties(prefix = "datasource.secondary") 
  public DataSource dataSource2() { 
    DruidDataSource source = new DruidDataSource(); 
    source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER)); 
    source.setUrl(env.getRequiredProperty(DATABASE_URL)); 
    source.setUsername(env.getRequiredProperty(DATABASE_USER)); 
    source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD)); 
    return source; 
  } 
 
  @Bean(name = "mysqlEntityManagerFactory") 
  public LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory() { 
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); 
    factory.setDataSource(dataSource2()); 
    factory.setPersistenceProviderClass(HibernatePersistenceProvider.class); 
    factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN).split(",")); 
    factory.setJpaProperties(hibernateProperties()); 
    factory.afterPropertiesSet(); 
    return factory; 
  } 
 
  @Bean(name = "mysqlTransactionManager") 
  public PlatformTransactionManager transactionManager() { 
    JpaTransactionManager manager = new JpaTransactionManager(); 
    manager.setEntityManagerFactory(mysqlEntityManagerFactory().getObject()); 
    return manager; 
  } 
 
} 

两份配置代码使用了各自的数据源、实体管理对象以及事务管理对象。这里要注意的有两点,首先是实体管理对象。Spring Boot框架为方便开发者,默认会寻找名为“entityManagerFactory”的Bean作为实体管理的实现,但是我们这里使用了两个实体管理对象,名称也并不是默认的“entityManagerFactory”,因此必须在各自的EnableJpaRepositories的Annotation中指明使用的实体管理对象。第二点,就是事务管理对象。Spring Boot会提供一个默认的事务管理对象的实现,但是我们在这里使用了两个不同的事务管理对象,因此我们也需要在各自的EnableJpaRepositories的Annotation中指明使用的事务管理对象。除此以外,我们还必须指定其中一个事务管理对象为主要对象(使用Primary这一Annotation),让Spring能有主次地使用相应的事务管理对象。

以上就是本文的主要内容。关于Service的配置等问题,由于和单数据源时是一样的,因此就不再赘述了。基于上述代码,我们就可以使用Spring Boot实现多数据源之间的无缝切换了,是不是很轻松?如果你不想使用代码配置的方式,也可以使用XML文件代替,配置的核心属性与上文相同,可以自己加以琢磨。希望对大家的学习有所帮助,也希望大家多多支持。


# springboot  # 多数据源  # spring  # boot  # data  # jpa  # SpringData JPA基本/高级/多数据源的使用详解  # SpringBoot+Spring Data JPA整合H2数据库的示例代码  # 解决Spring Data Jpa 实体类自动创建数据库表失败问题  # Springboot使用Spring Data JPA实现数据库操作  # Spring Data JPA进行数据分页与排序的方法  # springboot使用spring-data-jpa操作MySQL数据库  # Spring boot中使用Spring-data-jpa方便快捷的访问数据库(推荐)  # Spring Data JPA框架的核心概念与Repository接口详解  # 的是  # 这一  # 使用了  # 如果你  # 在这里  # 放在  # 多个  # 子类  # 在此  # 有很多  # 我都  # 很多人  # 只需  # 不是很  # 要去  # 要在  # 我们可以  # 要注意  # 能有  # 相关信息 


相关文章: 如何高效完成自助建站业务培训?  建站之星伪静态规则如何设置?  潍坊网站制作公司有哪些,潍坊哪家招聘网站好?  c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】  网站制作软件有哪些,制图软件有哪些?  娃派WAP自助建站:免费模板+移动优化,快速打造专业网站  红河网站制作公司,红河事业单位身份证如何上传?  深圳网站制作平台,深圳市做网站好的公司有哪些?  PHP正则匹配日期和时间(时间戳转换)的实例代码  昆明网站制作哪家好,昆明公租房申请网上登录入口?  c# Task.ConfigureAwait(true) 在什么场景下是必须的  如何快速辨别茅台真假?关键步骤解析  音响网站制作视频教程,隆霸音响官方网站?  阿里云网站制作公司,阿里云快速搭建网站好用吗?  广州美橙建站如何快速搭建多端合一网站?  如何通过西部数码建站助手快速创建专业网站?  建站主机类型有哪些?如何正确选型  如何通过虚拟主机空间快速建站?  建站之星价格显示格式升级,你的预算足够吗?  如何解决ASP生成WAP建站中文乱码问题?  如何在阿里云域名上完成建站全流程?  湖州网站制作公司有哪些,浙江中蓝新能源公司官网?  如何通过云梦建站系统实现SEO快速优化?  如何在Windows虚拟主机上快速搭建网站?  网站制作外包价格怎么算,招聘网站上写的“外包”是什么意思?  php条件判断怎么写_ifelse和switchcase的使用区别【对比】  相亲简历制作网站推荐大全,新相亲大会主持人小萍萍资料?  免费公司网站制作软件,如何申请免费主页空间做自己的网站?  如何通过万网虚拟主机快速搭建网站?  如何在腾讯云免费申请建站?  Python文件管理规范_工程实践说明【指导】  广州商城建站系统开发成本与周期如何控制?  IOS倒计时设置UIButton标题title的抖动问题  建站之家VIP精选网站模板与SEO优化教程整合指南  建站之星如何优化SEO以实现高效排名?  如何制作一个表白网站视频,关于勇敢表白的小标题?  深圳 网站制作,深圳招聘网站哪个比较好一点啊?  Python lxml的etree和ElementTree有什么区别  网站制作公司广州有几家,广州尚艺美发学校网站是多少?  已有域名和空间如何搭建网站?  浅谈Javascript中的Label语句  如何将凡科建站内容保存为本地文件?  建站之星如何防范黑客攻击与数据泄露?  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  制作销售网站教学视频,销售网站有哪些?  建站之星安装提示数据库无法连接如何解决?  简单实现Android文件上传  如何用IIS7快速搭建并优化网站站点?  如何在局域网内绑定自建网站域名?  北京建设网站制作公司,北京古代建筑博物馆预约官网? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。