Spring使用EntityManager启动多个数据源

2024-04-12

我正在尝试使用 INFOQ 中的本教程设置一个具有多个数据源的 Springboot (v2.0.0.BUILD-SNAPSHOT) 项目

https://www.infoq.com/articles/Multiple-Databases-with-Spring-Boot https://www.infoq.com/articles/Multiple-Databases-with-Spring-Boot

但我需要使用多个 EntityManager,而不是 JdbcTemplate

这是我到目前为止所拥有的

应用程序属性

spring.primary.url=jdbc:sqlserver://localhost:2433;databaseName=TEST
spring.primary.username=root
spring.primary.password=root
spring.primary.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

spring.secondary.url=jdbc:oracle:thin:@//localhost:1521/DB
spring.secondary.username=oracle
spring.secondary.password=root
spring.secondary.driverClassName=oracle.jdbc.OracleDriver

应用程序.java

package com.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

应用程序配置.java

package com.test.config;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class ApplicationConfiguration {

    @Primary
    @Bean(name = "primaryDB")
    @ConfigurationProperties(prefix = "spring.primary")
    public DataSource postgresDataSource() {
        return  DataSourceBuilder.create().build();
    }

    @Bean(name = "primaryEM")
    public LocalContainerEntityManagerFactoryBean storingEntityManagerFactory(
        EntityManagerFactoryBuilder builder, @Qualifier("primaryDB") DataSource ds) {
        return builder
            .dataSource(ds)
            .packages("com.test.supplier1")
            .persistenceUnit("primaryPU")
            .build();
    }

    @Bean(name = "secondaryDB")
    @ConfigurationProperties(prefix = "spring.secondary")
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryEM")
    public LocalContainerEntityManagerFactoryBean storingEntityManagerFactory(
        EntityManagerFactoryBuilder builder, @Qualifier("secondaryDB") DataSource ds) {
    return builder
            .dataSource(ds)
            .packages("com.test.supplier2")
            .persistenceUnit("secondaryPU")
            .build();
    }

}

通用DAO.java

public abstract class GenericDAO<T extends Serializable> {

    private Class<T> clazz = null;

    @PersistenceContext
    protected EntityManager entityManager;

    public void setClazz(Class<T> clazzToSet) {
        this.clazz = clazzToSet;
    }

    public T findOne(Integer id) {          
        return this.entityManager.find(this.clazz, id);
    }

    public List<T> findAll() {
        return this.entityManager.createQuery("from " + this.clazz.getName()).getResultList();
    }

    @Transactional
    public void save(T entity) {
        this.entityManager.persist(setModifiedAt(entity));
    }
}

PersonDAO.java

@Repository
@PersistenceContext(name = "primaryEM")
public class PersonDAO extends GenericDAO<Person> {
    public PersonDAO() {
        this.setClazz(Person.class);
    }
}

产品DAO.java

@Repository
@PersistenceContext(name = "secondaryEM")
public class ProductDAO extends GenericDAO<Product> {
    public ProductDAO() {
        this.setClazz(Product.class);
    }
}

测试服务.java

@Service
public class TestService {

    @Autowired
    PersonDAO personDao;

    @Autowired
    ProductDAO productDao;

    // This should write to primary datasource
    public void savePerson(Person person) {
        personDao.save(person);
    }

    // This should write to secondary datasource
    public void saveProduct(Product product) {
        productDao.save(product);
    }

}

问题是它不起作用。当我尝试保留“产品”(辅助 ds)时,它也尝试保留到 @Primary 数据源。

我怎样才能做到这一点类似于文章中的 JdbcTemplate 示例?

我究竟做错了什么 ?

Thanks !

更新(尝试过@Deepak解决方案)

尝试下面的方法

@Repository
public class PersonDAO extends GenericDAO<Person> {
    @Autowired
    public PersonDAO(@Qualifier("primaryEM") EntityManager entityManager) {
        this.entityManager = entityManager;
        this.setClazz(Person.class);
    }
}

产品DAO

@Repository
public class ProductDAO extends GenericDAO<Product> {
    @Autowired
    public ProductDAO(@Qualifier("secondaryEM") EntityManager entityManager) {
        this.entityManager = entityManager;
        this.setClazz(Product.class);
    }
}

同时从 GenericDAO 中删除 @PersistenceContext 注释

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v2.0.0.BUILD-SNAPSHOT)

com.test.Application                     : Starting Application on...   
com.test.Application                     : No active profile set, falling back to default profiles: default 
ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@69b2283a: startup date [Thu Apr 20 15:28:59 BRT 2017]; root of context hierarchy  
.s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!   
.s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!   
f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring  
o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http) 
o.apache.catalina.core.StandardService   : Starting service Tomcat  
org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.12    
o.a.c.c.C.[Tomcat].[localhost].[/    : Initializing Spring embedded WebApplicationContext
o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 4001 ms  

o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]  
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]   
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]    
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]  
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]  

j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'primaryPU' 
o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [  name: primaryPU ...]    
org.hibernate.Version                    : HHH000412: Hibernate Core {5.2.9.Final}  
org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found    
o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final} 
org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.SQLServer2012Dialect 
j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'primaryPU'    

j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'secondaryPU'   
o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [  name: secondaryPU   ...]
org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.SQLServer2012Dialect 
j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'secondaryPU'

s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@69b2283a: startup date [Thu Apr 20 15:28:59 BRT 2017]; root of context hierarchy  
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)    
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)  
o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/** onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/** onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup    
s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing    
o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http)   
io.test.Application                      : Started Application in 76.21 seconds (JVM running for 77.544)    

org.hibernate.SQL                        : select next value for SEQ_TDAI_ID    
o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 923, SQLState: 42000  
o.h.engine.jdbc.spi.SqlExceptionHelper   : ORA-00923: FROM keyword not found where expected 
--> ERROR

似乎它正在使用 @Primary 数据源方言构建两个实体(在本例中为“SQLServer2012方言").

辅助 EntityManager 应该是“Oracle12c方言".

更新(解决方案)

似乎连接没问题,唯一的问题是方言错误(似乎默认为 @Primary DataSource 方言),所以解决方案是将其强制在 EntityManagerFactory 上,这是我的快速修复:

1)添加正确的方言application.properties file

spring.primary.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.secondary.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect

2) 将 application.properties 方言值导入ApplicationConfiguration.java

@Value("${spring.primary.hibernate.dialect}")
private String dialect;

3)强制进入EntityManagerFactory

@Bean(name = "primaryEM")
public LocalContainerEntityManagerFactoryBean storingEntityManagerFactory(
    EntityManagerFactoryBuilder builder, @Qualifier("primaryDB") DataSource ds) {

    Properties properties = new Properties();
    properties.setProperty("hibernate.dialect", dialect);

    LocalContainerEntityManagerFactoryBean emf = builder
        .dataSource(ds)
        .packages("com.test.supplier1")
        .persistenceUnit("primaryPU")
        .build();

    emf.setJpaProperties(properties);

    return emf;
}

现在可以了。

有没有更优雅的方法来做到这一点?


尝试下面的方法

@Repository
public class PersonDAO extends GenericDAO<Person> {
    @Autowired
    public PersonDAO(@Qualifier("primaryEM") EntityManager entityManager) {
        this.entityManager = entityManager;
        this.setClazz(Person.class);
    }
}

产品DAO

@Repository
public class ProductDAO extends GenericDAO<Product> {
    @Autowired
    public ProductDAO(@Qualifier("secondaryEM") EntityManager entityManager) {
        this.entityManager = entityManager;
        this.setClazz(Product.class);
    }
}

同时从 GenericDAO 中删除 @PersistenceContext 注释

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring使用EntityManager启动多个数据源 的相关文章

  • 黄瓜与 Micronaut

    我正在尝试将 Cucumber 与 Micronaut 一起使用 但当我尝试将其与 Cucumber 一起使用时 MicronautTest 注释根本不起作用 未注入 theApple 请参阅下面的代码 如果我在没有黄瓜的情况下运行它就可以
  • GSON:自定义对象反序列化

    好吧 我编辑了这个问题 因为它不够清楚 Edit 2 更新了 JSON 文件 我在 Android 应用程序中使用 GSON 我需要解析来自服务器的 JSON 文件 而且有点太复杂了 我不想让我的对象结构太重 所以我想简化内容 所以我的对象
  • @NotNull.List 的目的

    当我查看标准时限制条件 http docs oracle com javaee 6 api javax validation constraints package summary html在 Bean Validation API JSR
  • Java 中的本机方法

    我花了一些时间学习什么是 Java Native 方法以及它们是在平台相关代码 主要是 C 中实现的 但是我在哪里可以找到这些 Java 的本机实现呢 例如 Thread 类的 sleep long millis 方法是本机的 但它的实现代
  • 无法启动组件 [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/LabWebServletHibernate]]

    当使用 eclipse neon 1 在 tomcat 8 上运行应用程序时 我收到此错误 它使用 spring 4 3 3 hibernate 5 2 4 和 maven 嚴重 A child container failed durin
  • 在 Java 5 及更高版本中迭代 java.util.Map 的所有键/值对的最简单方法是什么?

    在 Java 5 及更高版本中迭代 java util Map 的所有键 值对的最简单方法是什么 假设K是您的密钥类型 并且V是你的值类型 for Map Entry
  • ApplicationEventMulticaster 未初始化 - 在多播事件之前调用“刷新”

    我正在尝试实施ehcache对于我的应用程序 但是当尝试调用服务器时 出现以下错误 java lang IllegalStateException ApplicationEventMulticaster not initialized ca
  • 如何将 currentTimeMillis 转换为可读的日期格式? [复制]

    这个问题在这里已经有答案了 我想用currentTimeMillis两次 这样我就可以计算持续时间 但我也想以用户可读的格式显示时间和日期 我遇到了麻烦currentTimeMillis有利于计算 但我看不到内置函数可以转换为合适的时间或时
  • Spring @Value 添加验证小于

    我使用以下属性值注入 我如何向此操作添加小于验证 我的意思是我想设置一个验证user maxpassiveday可以说 财产价值不得低于 100 Value user maxpassiveday int maxpassiveday 使用Sp
  • 使用antlr4获取预处理器行并解析C代码

    我正在使用 Antlr4 来解析 C 代码 并使用以下语法来解析 链接到 C g4 https github com antlr grammars v4 blob master c C g4 上面的语法默认不提供任何解析规则来获取预处理器语
  • 迁移到 Hibernate 5.x

    我正在将我的应用程序从 Hibernate 3 迁移到 Hibernate 5 我们正在使用DatabaseMetadata类获得TableMetadata 因此使用TableMetadata对象获取数据库表列信息 如列大小 类型等 似乎在
  • JSP 作为电子邮件模板

    有没有办法发送 MIME 电子邮件 其中电子邮件正文源自 JSP 我需要使用 Javamail 发送一封电子邮件 其中包含一个表格 我认为如果我可以使用 JSP 来完成所有格式设置和布局 将会很方便 在这个线程中 Java 电子邮件模板的建
  • 如何获取队列中的第 n 个项目?

    我的应用程序中有许多队列和优先级队列 我想轻松访问这些队列中的第 n 个项目 但没有看到使用 API 实现此目的的简单方法 我想我可以创建一个Iterator并迭代到第 n 个元素或使用toArray index 但似乎应该有一个更简单的方
  • 在openjdk:7-jre-alpine docker上如何安装python 3.6

    直到大约一周前 我才在 java 图像上成功使用 python 3 6 脚本 如下所示 FROM openjdk 7 jre alpine RUN apk update apk upgrade apk add no cache bash a
  • EclipseLink 2.7.0 和 JPA API 2.2.0 - 签名不匹配

    当运行由maven构建的具有以下依赖项的项目时
  • 为什么jdk中没有ConcurrentLinkedHashMap类?

    这个问题直接接着问从我之前的问题来看 https stackoverflow com q 12299731 1527084 我想我的第二个问题的答案是否定的 所以我想了解为什么 java util concurrent 包中没有 Concu
  • Android - 保持用户登录状态

    我正在尝试使用 PHP 和 MySQLi for Android 进行登录 我不明白的是如何保持用户登录状态 我看到一个简单的教程 其中有人使用 SQLite 来保护信息 但我不知道这是否真的安全 如何保存用户信息以保持用户登录状态 谢谢
  • 如何使用 Spring Resource.groovy 正确注入 Grails 服务

    使用 Grails 2 2 1 我定义了以下 Grails 服务 package poc class TestService def helperService class HelperService 我已经用过TestService如下
  • 对 Java 协议缓冲区对象进行一些小更改

    我想在 Java 协议缓冲区对象树的深处进行一个小更改 我可以使用 getBuilder 方法来创建一个新对象 该新对象是旧对象的克隆并进行一些更改 当深入完成此操作时 代码会变得丑陋 Quux Builder quuxBuilder fo
  • 按字母顺序对对象的 ArrayList 进行排序

    我必须创建一个方法来排序数组列表根据电子邮件按字母顺序排列对象 然后打印排序后的数组 我在排序时遇到麻烦的部分 我已经研究过并尝试使用Collections sort vehiclearray 但这对我不起作用 我是因为我需要一个叫做比较器

随机推荐

  • 如何知道两个线程中哪个线程首先完成执行

    我有两个线程 A 和 B 如果 A 先完成 那么我必须执行 function1 否则如果 B 先完成 我需要执行 function 2 我如何知道两个线程中哪一个先完成执行 您可以使用以下内容 仅当先前的值为空时才会设置该内容 即使只有一个
  • 未收到 ACTION_MY_PACKAGE_REPLACED

    我正在使用 ACTION MY PACKAGE REPLACED 来接收我的应用程序更新或重新安装的信息 我的问题是该事件永远不会被触发 我尝试了 Eclipse 和真实设备 这就是我所做的 显现
  • Python:将原始字符串转换为字节字符串而不添加转义字符

    我有一个字符串 BZh91AY SYA xaf x82 r x00 x00 x01 x01 x80 x02 xc0 x02 x00 x00 x9ah3M x07 lt xc9 x14 xe1BA x06 xbe x084 而且我要 b BZ
  • Android EditText 具有固定的最大行数且无滚动

    我想创建一个文本输入 1 始终显示3行 2 不允许用户输入超过 3 行可用空间的文本 3 如果用户输入的文本超过 3 行 则不可滚动 从技术上讲 我允许用户输入最多 500 个字符以保存到数据库 但我并不期望输入的文本量接近这个数量 因此
  • 在Java 8中以静态方式获取类名[重复]

    这个问题在这里已经有答案了 这是后续更一般和类似的问题 答案 https stackoverflow com questions 1696551 how to get the name of the calling class in jav
  • java中的计算器[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 最近我在研究可以加 减 乘 除的简单计算器 public static void main String arr double num1
  • 如何在 Init 状态下访问提供者值

    如何从 init 函数或解决方法访问提供程序模型中的值 基本上 当我的应用程序加载时 我会在提供程序模型中保存一些值 一个值是一个搜索变量 然后我被重定向到加载页面 我需要该值来获取数据并呈现列表 我正在 init 方法中检索数据 我的主要
  • Ruby 中的安全整数解析

    我有一根绳子 比如说 123 我想将它转换为整数123 我知道你可以简单地做some string to i 但这会转换 lolipops to 0 这不是我想要的效果 当我试图用一种美好而痛苦的方式转换一些无效的东西时 我希望它在我脸上爆
  • 格式化 Fitnesse RowFixture 中的数据

    我有一个 Fitnesse RowFixture 它返回业务对象列表 该对象有一个浮点数字段 表示 0 到 1 之间的百分比 consumer业务对象的内容将是来自设计者的网页或报告 因此百分比的格式将由设计者而不是业务对象决定 如果页面能
  • 如何从 tomcat 提供静态内容

    我有一个目录 其中包含许多静态文件 png css 等 我认为 也许是错误的 只需在应用程序的 WEB INF 文件中创建一个目录就足够了 我只需按名称引用这些文件即可访问它们 Ex 我的目录结构如下 WEB INF static styl
  • 在 IntelliJ 中重新排序 Java 类方法的简单方法?

    在 IntelliJ 中 是否有比手动剪切和粘贴代码更简单的方法来重新排序类源文件中的方法 现在我在重构遗留代码时经常需要这个 例如将源代码中的相关方法移至彼此靠近的位置 在 Eclipse AFAIK 中 有一个类似于 IntelliJ
  • 获取gridview中选中记录的超链接字段值

    我的 Gridview 在其列上有一个超链接字段 每行都有复选框 我们可以通过选中复选框来选择任何记录 问题是 我无法获取超链接字段记录 执行此操作的代码是 for int i 0 i lt GridView1 Rows Count i C
  • 调用GAS中的sheet函数

    有没有办法在 google app script 中调用工作表函数 我想调用 MATCH IMPORTRANGE 和 INDEX 函数来计算函数定义中的返回值 如下所示 function abc foo bar a MATCH foo IM
  • 如何从 Azure 媒体服务获取视频的时长?

    我使用 Windows Azure Media Services NET SDK 3 来利用流媒体服务 我想检索视频的持续时间 如何使用 Windows Azure Media Services NET SDK 3 检索视频的持续时间 Az
  • 如何在实时服务器运行的情况下在 Visual Studio Code 中调试 JavaScript

    尝试在 Visual Studio Code 中调试简单的 HTML 和 JavaScript 项目 在 VS Code 终端窗口中 live server 用于启动 index html 在 VS Code 中 安装并配置了 Chrome
  • BitmapSource 转换为 Windows Phone 流

    我有一门课程需要一个流来旋转手机摄像头的图像 我遇到的问题是 当从独立存储加载图片时 即用户之前保存图片之后 它被加载到 BitmapSource 中 如果可能的话 我想将位图源 提取 回流中 有谁知道WP7是否使用silverlight
  • 是否可以使用实例化的 pojo 来插入 JDBC 模板?

    春天有BeanPropertyRowMapper从 SQL 中进行选择并映射到 POJO 对象 而无需创建自定义行映射器 我希望有同样的结果 但有一条插入语句 但我找不到同等的东西 public boolean addRenewalQuot
  • 在 JavaScript 解构中捕获嵌套级别 [重复]

    这个问题在这里已经有答案了 JavaScript 解构是否具有捕获对象及其内容的语法 换句话说 我可以在函数的参数列表中完全执行以下操作而不使用以下内容吗const line f a gt const b a console log I s
  • 使用 cmath 时禁用 math.h 废话[重复]

    这个问题在这里已经有答案了 我以前遇到过一个问题 因为函数在没有调用的情况下就被重载了std 而且诅咒仍然时不时地发生 因为我不使用using namespace std 删除 using namespace std 会导致程序得到垃圾结果
  • Spring使用EntityManager启动多个数据源

    我正在尝试使用 INFOQ 中的本教程设置一个具有多个数据源的 Springboot v2 0 0 BUILD SNAPSHOT 项目 https www infoq com articles Multiple Databases with