本文目录导读:

- 数据库直连方案(最简单)
- MyBatis 多数据源方案(推荐)
- 使用MySQL的Federated引擎(数据库层跨库)
- 使用Apache Calcite(高级方案)
- 实用案例:Spring Boot + MyBatis多数据源
- 性能优化建议
- 推荐方案
在Java中实现跨库查询,主要有以下几种常见方案,具体选择取决于你的业务场景和数据源类型:
数据库直连方案(最简单)
使用 JDBC 多数据源
public class CrossDatabaseQuery {
// 查询数据库A
public List<User> queryFromDB1() {
String sql = "SELECT * FROM user WHERE id = ?";
try (Connection conn = DataSource1.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
// 执行查询
}
}
// 查询数据库B
public List<Order> queryFromDB2() {
String sql = "SELECT * FROM order WHERE user_id = ?";
try (Connection conn = DataSource2.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
// 执行查询
}
}
// 在Java中组合结果
public UserDTO getCombinedData(Long userId) {
User user = queryFromDB1(userId);
List<Order> orders = queryFromDB2(userId);
UserDTO dto = new UserDTO();
dto.setUser(user);
dto.setOrders(orders);
return dto;
}
}
MyBatis 多数据源方案(推荐)
配置多数据源
# application.yml
spring:
datasource:
# 数据源1
db1:
url: jdbc:mysql://localhost:3306/db1
username: root
password: 123456
# 数据源2
db2:
url: jdbc:mysql://localhost:3306/db2
username: root
password: 123456
配置类
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource1") DataSource ds) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(ds);
// 指定mapper路径
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/db1/*.xml"));
return bean.getObject();
}
@Bean
public SqlSessionFactory sqlSessionFactory2(@Qualifier("dataSource2") DataSource ds) {
// 类似配置
}
}
使用MySQL的Federated引擎(数据库层跨库)
MySQL配置
-- 创建FEDERATED表
CREATE TABLE federated_user (
id INT NOT NULL,
name VARCHAR(50),
PRIMARY KEY (id)
) ENGINE=FEDERATED
CONNECTION='mysql://user:password@host:port/db1/user';
Java调用
// 直接查询联合表
@Service
public class CrossDatabaseService {
@Autowired
private JdbcTemplate jdbcTemplate;
public List<Map<String, Object>> crossQuery() {
String sql = "SELECT u.*, o.order_no " +
"FROM local_user u " +
"JOIN federated_order o ON u.id = o.user_id";
return jdbcTemplate.queryForList(sql);
}
}
使用Apache Calcite(高级方案)
Maven依赖
<dependency>
<groupId>org.apache.calcite</groupId>
<artifactId>calcite-core</artifactId>
<version>1.32.0</version>
</dependency>
实现代码
public class CalciteCrossQuery {
public ResultSet executeCrossQuery() throws Exception {
// 创建连接
Properties info = new Properties();
info.setProperty("lex", "JAVA");
Connection connection = DriverManager.getConnection("jdbc:calcite:", info);
// 创建Schema
SchemaPlus rootSchema =
connection.unwrap(CalciteConnection.class).getRootSchema();
// 添加数据源1
SchemaPlus db1Schema = rootSchema.add("DB1",
new JdbcSchema(dataSource1));
// 添加数据源2
SchemaPlus db2Schema = rootSchema.add("DB2",
new JdbcSchema(dataSource2));
// 执行跨库查询
String sql = "SELECT u.name, o.order_no " +
"FROM DB1.USER u " +
"JOIN DB2.ORDER o ON u.id = o.user_id";
Statement stmt = connection.createStatement();
return stmt.executeQuery(sql);
}
}
实用案例:Spring Boot + MyBatis多数据源
完整示例
@Service
public class CrossDatabaseServiceImpl implements CrossDatabaseService {
@Resource(name = "db1SqlSessionTemplate")
private SqlSessionTemplate db1SqlSessionTemplate;
@Resource(name = "db2SqlSessionTemplate")
private SqlSessionTemplate db2SqlSessionTemplate;
@Override
@Transactional(rollbackFor = Exception.class)
public List<Map<String, Object>> crossQueryWithTransaction() {
// 使用动态数据源切换
DatabaseContextHolder.setDatabaseType("DB1");
List<User> users = userMapper.selectAll();
DatabaseContextHolder.setDatabaseType("DB2");
List<Order> orders = orderMapper.selectByUserIds(
users.stream().map(User::getId).collect(Collectors.toList())
);
// Java层面组合数据
return combineData(users, orders);
}
}
性能优化建议
// 批量查询优化
public List<Map<String, Object>> optimizedCrossQuery(List<Long> userIds) {
// 1. 分批查询
int batchSize = 100;
List<Map<String, Object>> result = new ArrayList<>();
for (int i = 0; i < userIds.size(); i += batchSize) {
List<Long> batch = userIds.subList(i,
Math.min(i + batchSize, userIds.size()));
// 2. 并行查询不同数据库
CompletableFuture<List<User>> usersFuture =
CompletableFuture.supplyAsync(() -> queryUsers(batch));
CompletableFuture<List<Order>> ordersFuture =
CompletableFuture.supplyAsync(() -> queryOrders(batch));
// 3. 等待两个查询完成
CompletableFuture<Void> combinedFuture =
usersFuture.thenCombine(ordersFuture, (users, orders) -> {
// 合并结果
return combine(users, orders);
});
result.addAll(combinedFuture.join());
}
return result;
}
推荐方案
- 简单场景:使用JDBC多数据源或MyBatis多数据源
- 数据量大:使用数据库本身的跨库查询功能(如MySQL Federated)
- 复杂查询:使用Apache Calcite
- 微服务架构:考虑使用分布式查询中间件(如ShardingSphere)
选择方案时需要考虑数据一致性、性能和维护成本的平衡。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播