# backend-orm **Repository Path**: MetaLite/backend-orm ## Basic Information - **Project Name**: backend-orm - **Description**: 【可选jar包依赖】元界MetaLite后端应用的轻量orm模块,功能、性能、开发体验均强于Mybatis、Mybatis-Plus等传统orm框架。 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2025-11-25 - **Last Updated**: 2026-05-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # backend-orm ## 简介 `backend-orm` 是 MetaLite 微服务框架的**ORM封装模块**,提供轻量级、类型安全的数据库访问能力,是所有后端服务的**可选jar包依赖**。 ### 定位与职责 | 定位 | 职责 | |------|------| | ORM封装 | 提供流式API数据库访问 | | 统一API | MySQL和ES使用相同的查询API | | 按需引入 | 业务服务需要MySQL/ES时引入 | | 类型安全 | 编译时检查字段名,避免运行时错误 | | 通用CRUD | 基础增删改查无需手写SQL | --- ## 设计思想 ### 统一API设计 `BaseEntityDao` 提供统一的数据访问接口,MySQL和Elasticsearch使用相同的查询API: ```java // MySQL和ES使用相同接口 public interface BaseEntityDao { // 查询 T findOneById(Serializable id); T findOneByCriteria(Criteria criteria); T findOneByQuery(Query query); List findListByCriteria(Criteria criteria); List findListByQuery(Query query); // 更新 int updateById(Serializable id, Update update); int updateByCriteria(Criteria criteria, Update update); // 删除 int deleteById(Serializable id); int deleteByCriteria(Criteria criteria); } ``` ### 流式查询构建 ```java // 传统MyBatis:手写SQL // MetaLite ORM:流式API,类型安全 List users = userDao.findListByCriteria( Criteria.where(User::getStatus, 1) .like(User::getName, "张%") ); ``` ### 分库分表接口封装 通过实现 `DbRouter` 和 `TableRouter` 接口灵活扩展分库分表逻辑: ```java // 分库路由 public interface DbRouter { String writeRoute(Collection writeDbNames); // 写库路由 String readRoute(Collection readDbNames); // 读库路由 } // 分表路由 public interface TableRouter { String insertRoute(String logicTable, Entity entity); // 插入路由 String queryRoute(String logicTable, Criteria criteria); // 查询路由 String updateRoute(String logicTable, Serializable id); // 更新路由 String deleteRoute(String logicTable, Serializable id); // 删除路由 } ``` ### 本地编程式事务 通过 `TransactionManager.doInTransaction()` 实现编程式事务,避免声明式事务注解到Service方法引起死锁问题: ```java // 编程式事务:仅将DAO操作封装在事务内部 transactionManager.doInTransaction(() -> { userDao.insert(user); orderDao.insert(order); return null; }); // 可配置隔离级别和超时 transactionManager.doInTransaction(callback, TransactionSettings.builder() .isolationLevel(IsolationLevelEnum.READ_COMMITTED) .timeout(30) .build()); ``` ### 分布式事务支持 框架集成 Seata AT 模式,支持跨服务、跨数据源的分布式事务: - **单数据源**:使用本地编程式事务 `TransactionManager.doInTransaction()` - **跨数据源**(单服务分库分表):使用 `@GlobalTransactional` - **跨服务**:使用 `@GlobalTransactional` 详见 [Seata 分布式事务](#seata-分布式事务) 章节。 --- ## 核心优势 | 优势 | 说明 | |------|------| | 统一API | MySQL和ES使用相同的Criteria/Query/Update | | 无XML配置 | 纯Java代码,编译时检查 | | 类型安全 | 方法引用字段名,IDE自动补全 | | 链式调用 | Criteria/Query/Update链式构建 | | 分页内置 | Pageable对象,自动计算offset | | 分库分表 | DbRouter/TableRouter接口,灵活扩展 | | 编程式事务 | doInTransaction封装,避免死锁 | | 分布式事务 | 集成Seata AT模式,开箱即用 | --- ## 核心能力 | 能力 | 类 | 说明 | |------|-----|------| | 条件构建 | Criteria | eq/ne/gt/gte/lt/lte/like/in/nin/isNull | | 查询构建 | Query | orderBy/includeField/excludeField/limit | | 更新构建 | Update | set/链式设置多字段 | | 分页对象 | Pageable | pageNo/pageSize,范围1-200/1-1000 | | 排序对象 | OrderBy | desc/asc | | 分组查询 | GroupBy | groupBy字段 | | 分库路由 | DbRouter | writeRoute/readRoute,自定义实现 | | 分表路由 | TableRouter | insertRoute/queryRoute/updateRoute/deleteRoute | | 编程式事务 | TransactionManager | doInTransaction,支持隔离级别和超时配置 | | 分布式事务 | @GlobalTransactional | Seata AT模式,跨服务跨数据源事务 | | 主键查询 | findOneById | 按主键查单条 | | 条件查询 | findListByCriteria | 按条件查列表 | | 分页查询 | findListByQuery | 分页+排序+条件 | | 按主键更新 | updateById | 按主键+Update对象 | | 按条件更新 | updateByCriteria | 按条件+Update对象 | | 按主键删除 | deleteById | 按主键删除 | | 按条件删除 | deleteByCriteria | 按条件删除 | | 判断存在 | existsByCriteria | 按条件判断 | | 计数 | countByCriteria | 按条件统计 | --- ## 模块结构 ``` backend-orm/ ├── backend-orm-common/ # ORM通用接口 │ ├── dao/ # BaseEntityDao统一接口 │ ├── query/ # Criteria/Query/OrderBy/Pageable │ ├── update/ # Update构建器 │ ├── route/ # DbRouter/TableRouter分库分表接口 │ └── annotation/ # @Dao/@Table/@Column │ ├── backend-orm-jdbc/ # MySQL实现 │ ├── dao/ # BaseEntityJdbcDao实现 │ ├── transaction/ # TransactionManager编程式事务 │ └── config/ # 数据源配置 │ └── backend-orm-seata/ # Seata分布式事务支持 ├── autoconfiguration/ # 自动配置类 ├── SeataXidFilter.java # XID传播过滤器 ├── SeataXidAspect.java # XID同步切面 └── SeataDataSourceProxyManager.java # 数据源代理管理器 ``` --- ## Seata 分布式事务 > Seata Server(TC)的安装部署请参考官方文档:https://seata.apache.org/zh-cn/docs/v2.1/user/quickstart ### 工作原理 框架集成 Seata AT 模式,支持跨服务、跨数据源的分布式事务: 1. **DataSource 代理**:当 `seata.enabled=true` 时,框架自动将所有 DataSource 包装为 `DataSourceProxy` 2. **SQL 拦截**:Seata 拦截 SQL 执行,记录前后镜像到 `undo_log` 表 3. **全局回滚**:事务失败时,根据 `undo_log` 自动生成反向 SQL 回滚数据 ### 配置步骤 #### 1. 添加依赖 ```xml com.metalite backend-orm-seata ``` #### 2. 应用配置 ```yaml seata: enabled: true # 启用 Seata 分布式事务 application-id: ${spring.application.name} # 应用标识,用于区分不同应用 tx-service-group: ${spring.application.name}-group # 事务分组名,需与 vgroup-mapping 配合 service: vgroup-mapping: ${spring.application.name}-group: default # 将事务分组映射到 Seata Server 集群名 registry: # 注册中心配置,用于发现 Seata Server type: nacos nacos: server-addr: ${nacos.server-addr:127.0.0.1:8848} # Nacos 服务地址 namespace: ${spring.profiles.active} # 命名空间,用于多环境隔离 group: SEATA_GROUP # Seata 服务注册分组 config: # 配置中心配置,用于读取 Seata 运行参数 type: nacos nacos: server-addr: ${nacos.server-addr:127.0.0.1:8848} # Nacos 服务地址 namespace: ${spring.profiles.active} # 命名空间,用于多环境隔离 group: SEATA_GROUP # Seata 配置分组 data-id: seataServer.properties # Seata 配置文件 Data ID ``` #### 3. Nacos 配置与 Seata Server 部署 Seata Server 安装部署、Nacos 配置创建等详细步骤,请参考官方文档: - **快速开始**:https://seata.apache.org/zh-cn/docs/v2.1/user/quickstart - **Nacos 配置中心**:https://seata.apache.org/zh-cn/docs/v2.1/user/configuration/nacos - **Nacos 注册中心**:https://seata.apache.org/zh-cn/docs/v2.1/user/registry/nacos > **注意**:ORM 框架内部创建的 DataSource 会被自动代理。当 `seata.enabled=true` 时,`SeataDataSourceProxyManager` 通过反射获取 `JdbcTemplateManager` 中所有已创建的 JdbcTemplate,将其中的 DruidDataSource 替换为 Seata DataSourceProxy,无需额外配置。 #### 4. 数据库准备 每个参与分布式事务的数据库都需要创建 `undo_log` 表: ```sql CREATE TABLE IF NOT EXISTS `undo_log` ( `branch_id` BIGINT NOT NULL COMMENT '分支事务ID', `xid` VARCHAR(128) NOT NULL COMMENT '全局事务ID', `context` VARCHAR(128) NOT NULL COMMENT '上下文', `rollback_info` LONGBLOB NOT NULL COMMENT '回滚信息', `log_status` INT NOT NULL COMMENT '日志状态', `log_created` DATETIME(6) NOT NULL COMMENT '创建时间', `log_modified` DATETIME(6) NOT NULL COMMENT '修改时间', UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`) ) ENGINE = InnoDB COMMENT = 'AT事务回滚日志表'; ``` ### 使用示例 #### 场景:电商下单(跨服务事务) **订单服务(事务发起方):** ```java import org.apache.seata.spring.annotation.GlobalTransactional; // Seata 全局事务注解 @Service public class OrderService { @Autowired private OrderDao orderDao; @Autowired private InternalServiceClient internalServiceClient; /** * 创建订单 - 分布式事务 */ @GlobalTransactional(name = "create-order", rollbackFor = Exception.class) public Resp createOrder(OrderDTO orderDTO) { // 1. 创建订单(本地数据库) Order order = new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(orderDTO.getUserId()); order.setProductId(orderDTO.getProductId()); order.setQuantity(orderDTO.getQuantity()); order.setAmount(orderDTO.getAmount()); order.setStatus(OrderStatus.CREATED); orderDao.insert(order); // 2. 扣减库存(库存服务,内部服务调用) DecreaseStockParam stockParam = new DecreaseStockParam(); stockParam.setProductId(orderDTO.getProductId()); stockParam.setQuantity(orderDTO.getQuantity()); Resp stockResp = internalServiceClient.callOneInstanceRtnData( RpcRequest.builder() .provider(InternalServiceEnum.INVENTORY.getCode()) .endpoint("/api/inventory/stock/decrease") .rpcMode(RpcModeEnum.HTTP_POST_JSON) .param(WebUtil.genInternalReq(new ExternalLoginBizParamReq<>(), stockParam)) .build(), Void.class); if (!stockResp.isOk()) { throw new BusinessException(stockResp.getMsg()); } // 3. 扣减余额(账户服务,内部服务调用) DecreaseBalanceParam balanceParam = new DecreaseBalanceParam(); balanceParam.setUserId(orderDTO.getUserId()); balanceParam.setAmount(orderDTO.getAmount()); Resp balanceResp = internalServiceClient.callOneInstanceRtnData( RpcRequest.builder() .provider(InternalServiceEnum.ACCOUNT.getCode()) .endpoint("/api/account/balance/decrease") .rpcMode(RpcModeEnum.HTTP_POST_JSON) .param(WebUtil.genInternalReq(new ExternalLoginBizParamReq<>(), balanceParam)) .build(), Void.class); if (!balanceResp.isOk()) { throw new BusinessException(balanceResp.getMsg()); } return Resp.ok(); } } ``` **库存服务(事务参与方):** ```java import org.springframework.transaction.annotation.Transactional; // Spring 本地事务注解 @Service public class InventoryService { @Autowired private InventoryDao inventoryDao; @Transactional(rollbackFor = Exception.class) public void decreaseStock(Long productId, Integer quantity) { Inventory inventory = inventoryDao.findOneById(productId); if (inventory.getStock() < quantity) { throw new BusinessException("库存不足"); } inventoryDao.updateByCriteria( Criteria.where(Inventory::getId, productId), Update.set(Inventory::getStock, inventory.getStock() - quantity) ); } } ``` **账户服务(事务参与方):** ```java import org.springframework.transaction.annotation.Transactional; // Spring 本地事务注解 @Service public class AccountService { @Autowired private AccountDao accountDao; @Transactional(rollbackFor = Exception.class) public void decreaseBalance(Long userId, BigDecimal amount) { Account account = accountDao.findOneById(userId); if (account.getBalance().compareTo(amount) < 0) { throw new BusinessException("余额不足"); } accountDao.updateByCriteria( Criteria.where(Account::getId, userId), Update.set(Account::getBalance, account.getBalance().subtract(amount)) ); } } ``` ### 注意事项 1. **DataSource 代理**:框架已自动代理所有 DataSource(主库、从库)。当 `seata.enabled=true` 时,`SeataDataSourceProxyManager` 通过反射代理 `JdbcTemplateManager` 创建的所有数据源 2. **事务传播**:`@GlobalTransactional` 会通过 Seata 的全局事务 XID 传播到下游服务,`InternalServiceClient` 会自动传递 XID Header 3. **内部服务调用**:使用 `InternalServiceClient` 进行跨服务调用,XID 会自动传播 4. **异常回滚**:确保远程调用返回异常时能正确回滚,建议使用 `rollbackFor = Exception.class` 5. **性能考量**:分布式事务会增加开销,仅在跨服务/跨数据源一致性场景使用 6. **本地事务优先**:单数据源场景优先使用 `TransactionManager.doInTransaction()` ### 本地事务 vs 分布式事务 | 特性 | 本地事务 | 分布式事务 | |------|----------|------------| | 注解 | 无需注解 | `@GlobalTransactional` | | 跨数据源 | ❌ 不支持 | ✅ 支持 | | 跨服务 | ❌ 不支持 | ✅ 支持 | | 性能开销 | 低 | 较高 | | 适用场景 | 单服务单库 | 微服务架构 | --- ## 许可证 MIT License