【问题标题】:common configuration for multiple databases with spring bootspring boot 多个数据库的通用配置
【发布时间】:2020-01-07 03:40:26
【问题描述】:

我的项目有多个数据库,其中一个主数据库和 35 个其他数据库(具有相同的架构和相同的配置)

现在我们正在使用 c3p0 连接池并使用 jdbc 从池中获取连接。

我尝试了不同的方法将现有实现迁移到 hibernate/JPA 中,但它导致了繁重的样板代码,我需要为每个 db 模式声明数据源和 dao。 (https://o7planning.org/en/11653/using-multiple-datasources-with-spring-boot-and-jpa)

我想以这样一种方式设计数据库流,当请求连接时,我的数据库配置类应该能够返回 JPA 连接,并且我可以在我的服务类上执行相应的功能

如果我可以让我的查询易于理解或我的方法有任何缺陷,请告诉我

【问题讨论】:

  • 您希望在您的应用程序中使用所有数据库吗?到目前为止,您是如何配置 c3p0 驱动程序的?我猜你在你的代码中使用 Sql 查询?为什么要使用 Hibernate 呢?您能描述一个使用许多 DAO 的用例吗?
  • 您是否正在实施多租户?如果是,请阅读 Hibernate 文档:docs.jboss.org/hibernate/orm/5.4/userguide/html_single/…

标签: hibernate spring-boot jpa multiple-databases


【解决方案1】:

我通过使用 Spring Boot AbstractRoutingDatasource 实现找到了mulit tenancy 解决方案。

我定义了一个国家数据库(也作为默认数据库)和两个州数据库。

1) 我已经在下面的类中定义了所有 db 数据源。

public class DatabaseLookupMap {

    public static Map<Object,Object> getDataSourceHashMap() {
        Map<Object,Object> dbMap = new HashMap<Object, Object>();

        DriverManagerDataSource dnational = new DriverManagerDataSource();
        dnational.setDriverClassName("org.postgresql.Driver");
        dnational.setUrl("jdbc:postgresql://127.0.0.1:5432/master");
        dnational.setUsername("postgres");
        dnational.setPassword("root");

        DriverManagerDataSource dstate1 = new DriverManagerDataSource();
        dstate1.setDriverClassName("org.postgresql.Driver");
        dstate1.setUrl("jdbc:postgresql://127.0.0.1:5432/b_22");
        dstate1.setUsername("postgres");
        dstate1.setPassword("root");

        DriverManagerDataSource dstate2 = new DriverManagerDataSource();
        dstate2.setDriverClassName("org.postgresql.Driver");
        dstate2.setUrl("jdbc:postgresql://127.0.0.1:5432/b_18");
        dstate2.setUsername("postgres");
        dstate2.setPassword("root");

        //dbnational will be marked as default state when application starts up
        dbMap.put(0, dnational);
        dbMap.put(22, dstate1);
        dbMap.put(18, dstate2);

        return dbMap;
    }
}

2) 然后,在定义数据源 bean 时,我将这些数据源绑定到自定义 AbstractRoutingDatasource 类

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan(basePackages = "org.nic")
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "org.nic")
public class PrintcardjobApplication {

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

    //this is used to define entityManagerFactory to the application
    @Bean
    public DataSource dataSource() {
        ClientDataSourceRouter router = new ClientDataSourceRouter();

        router.setTargetDataSources(DatabaseLookupMap.getDataSourceHashMap());
        return  router;
    }
}

3) 那么,下面是我们自定义的AbstractRoutingDatasource类的定义

public class ClientDataSourceRouter extends AbstractRoutingDataSource{

    public static Integer currentState;


    @Override
    protected Object determineCurrentLookupKey() {

        //At application startup, current state is null
        if(currentState != null) {
            return currentState;
        }

        //in this scenario, nhps schema should be returned to application 
        return 0;
    }


}

这是设置多租户应用程序所需的所有配置

最后,我们定义了控制器、服务和实体类

@RequestMapping("/testjpa/{statecode}")
    public @ResponseBody String testJPAController(@PathVariable("statecode") String state) {
        System.out.println("statecode=>>>"+state);

        try {
            ClientDataSourceRouter.currentState = Integer.parseInt(state);

            testService.testjpa(state);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return "checking";
    }

Service Class(最初,我只使用 JpaRepository 来获取记录。后来,我发现我也可以使用 EntityManagerFactory 来执行 HQL 查询,而不是使用 JpaRepository。所以,无论他们找到什么,都取决于开发人员方便)

@Service
@Transactional
public class TestService {

    @Autowired
    private RecordMasterDao dao;

    @Autowired
    private EntityManagerFactory factory;

    public void testjpa(String statecode) throws Exception {

        EntityManager em = factory.createEntityManager();

        Query query = em.createQuery("select a from RecordMasterEntity a where a.nhaid = :pmrssmid");
        query.setParameter("pmrssmid", "PLSNZ26M");

        RecordMasterEntity result = (RecordMasterEntity) query.getSingleResult();

        System.out.println(result);

        em.close();
        /*Optional<RecordMasterEntity> entity = dao.findById("PLSNZ26M");

        if(entity.isPresent()) {
            System.out.println(entity.get());   
        }
        else {
            System.err.println("no record found");

        }*/


    }
}

最后是实体类

    @Entity
    @Table(name = "tablename")
    public class RecordMasterEntity {

        @Id
        private String myid;

        private String scode;

        private String sname;

        private String name_eng;

        private String yearofbirth;

        private String gender;

        private String photo;

        private String hhidtype;

        getters and setters

}

可以通过将 db 配置放在属性文件中来优化代码。

希望回答对你有帮助

参考资料:

https://www.baeldung.com/spring-abstract-routing-data-source

https://javadeveloperzone.com/spring-boot/spring-boot-jpa-multi-tenancy-example/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-21
    • 2017-08-10
    • 2019-02-03
    • 1970-01-01
    • 2016-05-15
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多