spring 引导的多个数据库的通用配置
common configuration for multiple databases with spring boot
我的项目有多个数据库,其中有一个主数据库和 35 个其他数据库(具有相同的模式和相同的配置)
目前我们正在使用 c3p0 连接池并使用 jdbc 从池中获取连接。
我曾尝试过不同的方法将现有的实现转移到 hibernate/JPA 中,但它会导致大量的样板代码,我需要在其中为每个数据库模式声明数据源和 dao。 (https://o7planning.org/en/11653/using-multiple-datasources-with-spring-boot-and-jpa)
我想以这样的方式设计数据库流,当请求连接时,我的数据库配置 class 应该能够 return JPA 连接,我可以做相应的我服务的功能 class
如果我能让我的查询易于理解或我的方法有任何缺陷,请告诉我
我通过使用 Spring 启动 AbstractRoutingDatasource
.
找到了 mulit tenancy
解决方案
我定义了一个国家数据库(也是默认数据库)和两个州数据库。
1) 我已经在下面 class.
中定义了所有数据库数据源
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
class
@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
class
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;
}
}
这是设置多租户应用程序所需的所有配置
最后,我们定义控制器、服务和实体class
@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");
}*/
}
}
最后,实体Class
@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
}
可以通过将数据库配置放在属性文件中来优化代码。
希望答案对您有所帮助
参考文献:
https://www.baeldung.com/spring-abstract-routing-data-source
https://javadeveloperzone.com/spring-boot/spring-boot-jpa-multi-tenancy-example/
我的项目有多个数据库,其中有一个主数据库和 35 个其他数据库(具有相同的模式和相同的配置)
目前我们正在使用 c3p0 连接池并使用 jdbc 从池中获取连接。
我曾尝试过不同的方法将现有的实现转移到 hibernate/JPA 中,但它会导致大量的样板代码,我需要在其中为每个数据库模式声明数据源和 dao。 (https://o7planning.org/en/11653/using-multiple-datasources-with-spring-boot-and-jpa)
我想以这样的方式设计数据库流,当请求连接时,我的数据库配置 class 应该能够 return JPA 连接,我可以做相应的我服务的功能 class
如果我能让我的查询易于理解或我的方法有任何缺陷,请告诉我
我通过使用 Spring 启动 AbstractRoutingDatasource
.
mulit tenancy
解决方案
我定义了一个国家数据库(也是默认数据库)和两个州数据库。
1) 我已经在下面 class.
中定义了所有数据库数据源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
class
@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
class
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;
}
}
这是设置多租户应用程序所需的所有配置
最后,我们定义控制器、服务和实体class
@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");
}*/
}
}
最后,实体Class
@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
}
可以通过将数据库配置放在属性文件中来优化代码。
希望答案对您有所帮助
参考文献:
https://www.baeldung.com/spring-abstract-routing-data-source
https://javadeveloperzone.com/spring-boot/spring-boot-jpa-multi-tenancy-example/