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

时间:2017-12-12 19:01:22

标签: spring hibernate jpa spring-data

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

旁边,我想使用JpaRepository,它只是将@Repository注释添加到扩​​展JpaRepository的某个接口,重点关注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);
    }
 }  

2 个答案:

答案 0 :(得分:0)

除非每个数据库基本上都是自包含的,否则不能。

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

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

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

每笔交易可能有多个EntityManager。它不能成为您的标准@Transactional,您必须配置JTATransactionalManager代替标准版本,但这不应该太难。请注意,每个事务中最多只能有一个非XA数据源。

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

答案 1 :(得分:0)

您需要提供一些其他配置选项才能完成此操作

@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的本机功能。