跳到主要内容

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()
);
}
}