如何使用 spring4+spring-data-jpa(hibernateJpaVendorAdapter)+multidatasource+one entityManager+jpaReposit

Posted

技术标签:

【中文标题】如何使用 spring4+spring-data-jpa(hibernateJpaVendorAdapter)+multidatasource+one entityManager+jpaRepository?【英文标题】:How to work with spring4+spring-data-jpa(hibernateJpaVendorAdapter)+multidatasource+one entityManager+jpaRepository? 【发布时间】:2017-12-12 19:01:22 【问题描述】:

我遇到一个项目,有两个数据库,但这些数据库中的数据结构不同,涉及多数据源中的事务管理。

另外,我想使用JpaRepository,它只是在一些扩展JpaRepository的接口上添加@Repository注解,重点关注sql语句。例如:

@Scope(value="prototype")
@Repository
public interface UserRepository extends JpaRepository<User, Integer>,
 JpaSpecificationExecutor<User> 
    @Query(value="select * from users",nativeQuery=true)
    public List<User>  getAll();

    @Query(value="select * from users where email=binary ?1 or   phone_number=?1",nativeQuery=true)
    public User findUserByEmailOrPhone(String name);

    public User save(User user);

    @Modifying
    @Query("Update User u set u.lastLoginTime=?2,u.mac=?3,u.lastIp=?4 where u.id=?1")
    public int updateLast_login(Integer id,Date last_loginTime,String mac,
          String last_ip);
  

关于事务管理,我想继续使用@Transctional注解,但这涉及到两个mysql数据库中sql语句的执行。

根据我对一个数据源的经验,我想只有一个entityManagerFactory来管理两个数据源中的不同实体类。

但是如何配置JpaRepository接口和数据源的映射,告诉entityManagerFactory数据源和实体类的映射呢?

这是我想要完成上述功能的示例。

// this entity data  is restored in A databse's Atab table
@Table
@Entity
public class A
   private String A_item1;
   private Integer A_item2;
   private Long A_item3;
   public A()
      super();
   

 // this entity data is restored in B databse's Btab table
 @Table
 @Entity
 public class B
     private String B_item1;
     private Integer B_item2;
     private Long B_item3;
     public B()
         super();
     
 

 @Repository
 public interface A_Repository extends JpaRepository<A, Integer>,
 JpaSpecificationExecutor<A>

      public A save(A a);

      @Modifying
      @Query(value="update Atab  set a_item1=?1 where a_item2=?2",nativeQuery=true)
      public A update(String a_item1,int a_item2 );

      public A update(A a);
 

 @Repository
 public interface B_Repository extends JpaRepository<B, Integer>,
 JpaSpecificationExecutor<B>

      public B save(B a);

      @Modifying
      @Query(value="update Btab  set b_item1=?1 where b_item2=?2",nativeQuery=true)
      public B update(String b_item1,int b_item2 );

      public B update(B b);
 

 @service
 public class A_B_Service

    @Autowired
    A_Repository a_Repos;

    @Autowired
    B_Repository b_Repos;

    @Transactional(rollbackFor=Exception.class)
    public void synchronous_save_AandB(A a,B b)
          a_Repos.save(a);
          b_Repos.save(b);

    

    @Transactional(rollbackFor=Exception.class)
    public void synchronous_update_AandB(A a,B b)
          a_Repos.update(a);
          b_Repos.update(b);
    

    @Transactional(rollbackFor=Exception.class)
    public void synchronous_update_AandB(String a_item1,int a_item2,String b_item1,int b_item2)
          a_Repos.update( a_item1,a_item2);
          b_Repos.update(b_item1,b_item2);
    
   

【问题讨论】:

【参考方案1】:

你不能,除非每个数据库基本上都是独立的。

每个实体都属于一个或多个JPARepository(是的,您可以根据需要为每个实体拥有多个存储库)。

每个JPARepository 属于一个EntityManager (如果使用Hibernate 和Spring,它基于您的扫描包)您可能有多个EntityManagers 扫描同一个包,但我认为您会有并发和如果这样做,数据覆盖问题。

每个EntityManager 只有一个数据源。 (我知道没有多数据源EntityManagers)

每个事务可能有多个EntityManagers。它不能是您的标准@Transactional,您必须配置一个JTATransactionalManager 来代替标准@,但这应该不会太难。请注意,每个事务中最多可以有 1 个非 XA 数据源。

另请注意,我所知道的任何EntityManager 都不支持跨数据源/EntityManagers 的 SQL 或 JPQL。

【讨论】:

,谢谢!根据您的评论,我已经搜索了一些关于JTATransactionalManager的问题,但它没有集成配置和使用。我的webservice机器是tomcat7,我需要找到一个新的webservice容器?我是JTATransactionalManager 的新手,你能找到一些关于我的情况的例子吗?【参考方案2】:

您需要提供一些额外的配置选项来完成此操作

@EnableJpaRepositories(
  basePackages =  "com.yourappliction.feature1.repositories" ,
  entityManagerFactoryRef = "entityManagerFeature1",
  transactionManagerRef = "transactionManagerFeature1"
)

@EnableJpaRepositories(
  basePackages =  "com.yourapplication.feature2.repositories" ,
  entityManagerFactoryRef = "entityManagerFactoryFeature2",
  transactionManagerRef = "transactionManagerFeature2"
)

这意味着您需要为EntityManagerFactoryTransactionManager 配置 2 个 bean。

feature1 中的 JpaRepository 接口将使用这些特定的 bean,而 feature2 将使用其他配置的 bean。

没有办法通过单个EntityManagerFactory 来完成此操作,因为工厂专门用于数据源。过去开发了一些自定义框架来支持这一点,但它不是 JPA 的原生特性。

【讨论】:

以上是关于如何使用 spring4+spring-data-jpa(hibernateJpaVendorAdapter)+multidatasource+one entityManager+jpaReposit的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring-data 中更改/定义 Mongodb 的默认数据库?

您如何保护 Spring Boot / Spring-Data Rest 以便用户只能访问他自己的实体

如何在 spring-data 2.0.x 中创建 RedisCacheManager

使用 Eclipse Scala IDE 中的 spring-data 注入测试 playframework 2.4

如何将 @Transactional 与 Spring Data 一起使用?

在 spring-data 项目中使用 @Version