09 - 多数据源与事务
9.1 数据源配置
DLZ-DB 支持动态数据源,通过代码方式添加和切换数据源。
添加数据源
// 添加从库数据源
DataSourceProperty slaveProperty = new DataSourceProperty();
slaveProperty.setName("slave");
slaveProperty.setUrl("jdbc:mysql://slave-host:3306/db_slave");
slaveProperty.setUsername("root");
slaveProperty.setPassword("slave123");
slaveProperty.setDriverClassName("com.mysql.cj.jdbc.Driver");
DBDynamic.addDataSource(slaveProperty);
// 添加报表库数据源
DataSourceProperty reportProperty = new DataSourceProperty();
reportProperty.setName("report");
reportProperty.setUrl("jdbc:mysql://report-host:3306/db_report");
reportProperty.setUsername("root");
reportProperty.setPassword("report123");
reportProperty.setDriverClassName("com.mysql.cj.jdbc.Driver");
DBDynamic.addDataSource(reportProperty);
删除数据源
DBDynamic.removeDataSource("slave");
9.2 切换与事务
切换数据源
// 使用默认数据源(master)
DB.Pojo.select(User.class).queryBeanList();
// 切换到从库查询
DB.Dynamic.use("slave", () -> DB.Pojo.select(User.class).queryBeanList());
// 切换到报表库
List<ResultMap> report = DB.Dynamic.use("report")
.jdbcSelect("SELECT * FROM daily_report")
.queryList();
链式切换
// 从库查询
List<User> users = DB.Dynamic.use("slave", () ->
DB.Pojo.select(User.class)
.eq(User::getStatus, 1)
.orderByDesc(User::getCreateTime)
.queryBeanList()
);
// 主库写入
DB.Dynamic.use("master", () -> DB.Pojo.insert(user));
事务控制
单数据源事务
Spring 的 @Transactional 只能管理 Spring 容器管理的默认数据源。在 DB.Dynamic.use() 内部调用 service 时,Spring 事务无法生效,因为 Spring 事务管理器无法感知动态切换的数据源。
@Service
public class UserService {
@Transactional
public void createUser(User user) {
// 同一事务内的操作(使用默认数据源)
DB.Pojo.insert(user);
DB.Pojo.insert(userLog);
}
}
动态数据源事务
在 DB.Dynamic.use() 手动管理事务:
DB.Dynamic.use("slave", true,() -> {
// 执行多个操作
DB.Pojo.insert(user);
DB.Pojo.insert(userLog);
});
跨数据源事务
DLZ-DB 不支持跨数据源事务。如需跨数据源事务,请使用分布式事务框架(如 Seata)。
读写分离建议
@Service
public class UserService {
// 写操作 → 主库
public void save(User user) {
DB.Dynamic.use("master", () -> DB.Pojo.insert(user));
}
// 读操作 → 从库
public User getById(Long id) {
return DB.Dynamic.use("slave", () ->
DB.Pojo.select(User.class)
.eq(User::getId, id)
.queryBean()
);
}
// 需要读取最新数据 → 主库
public User getByIdFromMaster(Long id) {
return DB.Dynamic.use("master", () ->
DB.Pojo.select(User.class)
.eq(User::getId, id)
.queryBean()
);
}
}