
在数字化转型的深水区,传统单机数据库面临高并发、海量数据、金融级高可用三大核心瓶颈。OceanBase作为原生分布式关系型数据库,凭借单机分布式一体化架构、金融级强一致、HTAP混合负载、高度兼容MySQL等核心能力,成为企业级数据库架构升级的核心选型。
本文基于OceanBase最新LTS版本V4.4.2编写,所有原理均来自官方权威文档,所有代码均经过JDK17环境编译验证,SQL脚本兼容MySQL 8.0与OceanBase MySQL模式,可直接执行。
OceanBase采用Shared-Nothing对等架构,集群内所有节点完全对等,无中心化设计,避免单点故障风险。核心架构分为接入层、SQL引擎层、事务引擎层、存储引擎层、复制协调层五大模块,同时通过多租户架构实现资源的物理隔离与弹性调度。

核心组件说明:
OceanBase存储引擎基于LSM-Tree(日志结构合并树) 架构设计,彻底解决了传统InnoDB B+树的随机写入痛点,同时通过自研优化实现了不输B+树的读取性能,是其支撑百万级TPS的核心基础。
LSM-Tree将数据分为内存增量数据与磁盘基线数据两部分,所有写入操作均为顺序写入,彻底避免随机IO:

特性 | OceanBase LSM-Tree | InnoDB B+树 |
|---|---|---|
写入模式 | 全顺序写入,无随机IO | 随机写入,更新操作产生随机IO |
存储成本 | 高压缩比,3-5倍空间节省 | 压缩比低,空间占用大 |
大并发写入 | 性能稳定,无抖动 | 高并发下随机IO激增,性能抖动 |
数据合并 | 异步合并,业务低峰期执行 | 同步页分裂,业务高峰期可能卡顿 |
海量数据存储 | 天然支持PB级数据,水平扩展 | 单机容量有限,分库分表复杂度高 |
OceanBase通过Multi-Paxos一致性协议实现多副本数据强一致,是其金融级高可用的核心保障,可实现RPO=0(数据零丢失)、RTO<30s(故障快速恢复) 的企业级容灾能力。
OceanBase通过全局时间戳服务GTS+优化两阶段提交2PC+MVCC多版本并发控制,实现了完整的分布式事务ACID保证,完全兼容MySQL的事务隔离级别,支持跨节点、跨分区的强一致事务。
OceanBase基于全局时间戳实现MVCC,读写互不阻塞,支持读未提交、读已提交、可重复读三种隔离级别,默认使用读已提交,完全兼容MySQL的隔离级别行为,业务迁移无需修改事务逻辑。
OceanBase MySQL模式高度兼容MySQL 5.7/8.0协议、语法、数据类型、函数与存储过程,业务从MySQL迁移至OceanBase,99%以上的代码无需修改,仅需更换JDBC连接串即可完成平滑迁移。
维度 | OceanBase | 单机MySQL |
|---|---|---|
架构 | 原生分布式,支持水平扩展 | 单机集中式,扩展能力有限 |
数据容量 | 天然支持PB级海量数据 | 单机容量上限,超千万行性能明显下降 |
高可用 | 原生多副本,RPO=0,RTO<30s | 主从复制,存在数据丢失风险,故障切换需人工干预 |
写入性能 | 全顺序写入,高并发下性能稳定 | 随机写入,高并发下IO瓶颈明显 |
混合负载 | 原生支持HTAP,交易+分析一套集群 | 仅适合OLTP,分析场景需搭配数仓 |
存储成本 | 高压缩比,存储成本降低70%+ | 压缩比低,存储成本高 |
本章节基于JDK17、SpringBoot 3.2.x、MyBatis-Plus 3.5.6、OceanBase V4.4.2实现完整的生产级项目,所有代码严格遵循《阿里巴巴Java开发手册(嵩山版)》规范,可直接编译运行。
执行以下命令,5分钟内即可搭建好OceanBase单机开发环境,默认端口2883,MySQL协议兼容,root用户默认密码为空。
docker run -d -p 2883:2883 --name oceanbase -e OB_ROOT_PASSWORD=root123 -e MODE=slim oceanbase/oceanbase-ce:4.4.2.0
部署完成后,使用MySQL客户端即可连接:
mysql -h127.0.0.1 -P2883 -uroot -proot123
执行以下SQL,创建业务数据库与专用用户,兼容MySQL 8.0语法:
-- 创建业务数据库
CREATE DATABASE IF NOT EXISTS ob_demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 创建业务用户
CREATE USER IF NOT EXISTS 'ob_user'@'%' IDENTIFIED BY 'ObUser@123456';
-- 授权
GRANT ALL PRIVILEGES ON ob_demo.* TO 'ob_user'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
-- 切换数据库
USE ob_demo;
以下为电商订单核心表结构,包含分区表示例,兼容MySQL 8.0,可直接在OceanBase中执行:
-- 订单表,采用Range分区,按订单创建时间按月份分区
CREATE TABLE IF NOT EXISTS t_order (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
order_no VARCHAR(64) NOT NULL COMMENT '订单编号',
user_id BIGINT NOT NULL COMMENT '用户ID',
total_amount DECIMAL(12,2) NOT NULL COMMENT '订单总金额',
pay_amount DECIMAL(12,2) NOT NULL COMMENT '实付金额',
order_status TINYINT NOT NULL DEFAULT 0 COMMENT '订单状态:0-待付款,1-已付款,2-已发货,3-已完成,4-已取消',
pay_time DATETIME COMMENT '支付时间',
delivery_time DATETIME COMMENT '发货时间',
receive_time DATETIME COMMENT '收货时间',
remark VARCHAR(512) COMMENT '订单备注',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除:0-未删除,1-已删除',
PRIMARY KEY (id, create_time),
UNIQUE KEY uk_order_no (order_no),
KEY idx_user_id (user_id),
KEY idx_create_time (create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表'
PARTITION BY RANGE (TO_DAYS(create_time)) (
PARTITION p202601 VALUES LESS THAN (TO_DAYS('2026-02-01')),
PARTITION p202602 VALUES LESS THAN (TO_DAYS('2026-03-01')),
PARTITION p202603 VALUES LESS THAN (TO_DAYS('2026-04-01')),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
-- 订单明细表
CREATE TABLE IF NOT EXISTS t_order_item (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
order_id BIGINT NOT NULL COMMENT '订单ID',
order_no VARCHAR(64) NOT NULL COMMENT '订单编号',
product_id BIGINT NOT NULL COMMENT '商品ID',
product_name VARCHAR(256) NOT NULL COMMENT '商品名称',
product_price DECIMAL(12,2) NOT NULL COMMENT '商品单价',
quantity INT NOT NULL COMMENT '购买数量',
total_price DECIMAL(12,2) NOT NULL COMMENT '商品总价',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除:0-未删除,1-已删除',
PRIMARY KEY (id),
KEY idx_order_id (order_id),
KEY idx_order_no (order_no),
KEY idx_product_id (product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';
-- 用户账户表
CREATE TABLE IF NOT EXISTS t_user_account (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
balance DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '账户余额',
freeze_amount DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '冻结金额',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户账户表';
-- 初始化测试账户数据
INSERT INTO t_user_account (user_id, balance) VALUES (10001, 10000.00);
INSERT INTO t_user_account (user_id, balance) VALUES (10002, 5000.00);
pom.xml完整依赖,所有组件均采用2026年2月最新稳定版本,适配JDK17:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<relativePath/>
</parent>
<groupId>com.jam</groupId>
<artifactId>oceanbase-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>oceanbase-demo</name>
<description>OceanBase Java实战项目</description>
<properties>
<java.version>17</java.version>
<mybatis-plus.version>3.5.6</mybatis-plus.version>
<oceanbase.version>2.4.14</oceanbase.version>
<fastjson2.version>2.0.52</fastjson2.version>
<guava.version>33.1.0-jre</guava.version>
<swagger.version>2.5.0</swagger.version>
</properties>
<dependencies>
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot 事务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- OceanBase JDBC驱动 -->
<dependency>
<groupId>com.oceanbase</groupId>
<artifactId>oceanbase-client</artifactId>
<version>${oceanbase.version}</version>
</dependency>
<!-- Druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.25</version>
</dependency>
<!-- MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- Swagger3(SpringDoc) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- FastJSON2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension-spring6</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<!-- Guava集合工具类 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml完整配置,适配OceanBase MySQL模式,生产级参数优化:
server:
port: 8080
spring:
application:
name: oceanbase-demo
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.oceanbase.jdbc.Driver
url: jdbc:oceanbase://127.0.0.1:2883/ob_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
username: ob_user
password: ObUser@123456
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
# MyBatis-Plus配置
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
type-aliases-package: com.jam.demo.entity
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: auto
logic-delete-field: isDeleted
logic-delete-value: 1
logic-not-delete-value: 0
# Swagger3配置
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
api-docs:
path: /v3/api-docs
packages-to-scan: com.jam.demo.controller
Order.java
package com.jam.demo.entity;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 订单实体类
* @author ken
* @date 2026-02-27
*/
@Data
@TableName("t_order")
@Schema(description = "订单实体")
public class Order {
@Schema(description = "主键ID")
@TableId(type = IdType.AUTO)
private Long id;
@Schema(description = "订单编号")
private String orderNo;
@Schema(description = "用户ID")
private Long userId;
@Schema(description = "订单总金额")
private BigDecimal totalAmount;
@Schema(description = "实付金额")
private BigDecimal payAmount;
@Schema(description = "订单状态:0-待付款,1-已付款,2-已发货,3-已完成,4-已取消")
private Integer orderStatus;
@Schema(description = "支付时间")
private LocalDateTime payTime;
@Schema(description = "发货时间")
private LocalDateTime deliveryTime;
@Schema(description = "收货时间")
private LocalDateTime receiveTime;
@Schema(description = "订单备注")
private String remark;
@Schema(description = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@Schema(description = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@Schema(description = "是否删除")
@TableLogic
private Integer isDeleted;
}
OrderItem.java
package com.jam.demo.entity;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 订单明细实体类
* @author ken
* @date 2026-02-27
*/
@Data
@TableName("t_order_item")
@Schema(description = "订单明细实体")
public class OrderItem {
@Schema(description = "主键ID")
@TableId(type = IdType.AUTO)
private Long id;
@Schema(description = "订单ID")
private Long orderId;
@Schema(description = "订单编号")
private String orderNo;
@Schema(description = "商品ID")
private Long productId;
@Schema(description = "商品名称")
private String productName;
@Schema(description = "商品单价")
private BigDecimal productPrice;
@Schema(description = "购买数量")
private Integer quantity;
@Schema(description = "商品总价")
private BigDecimal totalPrice;
@Schema(description = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@Schema(description = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@Schema(description = "是否删除")
@TableLogic
private Integer isDeleted;
}
UserAccount.java
package com.jam.demo.entity;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 用户账户实体类
* @author ken
* @date 2026-02-27
*/
@Data
@TableName("t_user_account")
@Schema(description = "用户账户实体")
public class UserAccount {
@Schema(description = "主键ID")
@TableId(type = IdType.AUTO)
private Long id;
@Schema(description = "用户ID")
private Long userId;
@Schema(description = "账户余额")
private BigDecimal balance;
@Schema(description = "冻结金额")
private BigDecimal freezeAmount;
@Schema(description = "乐观锁版本号")
@Version
private Integer version;
@Schema(description = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@Schema(description = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
OrderMapper.java
package com.jam.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jam.demo.entity.Order;
import org.apache.ibatis.annotations.Mapper;
/**
* 订单Mapper接口
* @author ken
* @date 2026-02-27
*/
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
OrderItemMapper.java
package com.jam.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jam.demo.entity.OrderItem;
import org.apache.ibatis.annotations.Mapper;
/**
* 订单明细Mapper接口
* @author ken
* @date 2026-02-27
*/
@Mapper
public interface OrderItemMapper extends BaseMapper<OrderItem> {
}
UserAccountMapper.java
package com.jam.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jam.demo.entity.UserAccount;
import org.apache.ibatis.annotations.Mapper;
/**
* 用户账户Mapper接口
* @author ken
* @date 2026-02-27
*/
@Mapper
public interface UserAccountMapper extends BaseMapper<UserAccount> {
}
OrderService.java 接口
package com.jam.demo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.jam.demo.entity.Order;
import com.jam.demo.request.OrderCreateRequest;
import com.jam.demo.vo.OrderDetailVO;
/**
* 订单服务接口
* @author ken
* @date 2026-02-27
*/
public interface OrderService extends IService<Order> {
/**
* 创建订单
* @param request 订单创建请求参数
* @return 订单编号
*/
String createOrder(OrderCreateRequest request);
/**
* 查询订单详情
* @param orderNo 订单编号
* @return 订单详情VO
*/
OrderDetailVO getOrderDetail(String orderNo);
/**
* 订单支付
* @param orderNo 订单编号
* @param userId 用户ID
* @return 支付结果
*/
Boolean payOrder(String orderNo, Long userId);
}
OrderServiceImpl.java 实现类
package com.jam.demo.service.impl;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.jam.demo.entity.Order;
import com.jam.demo.entity.OrderItem;
import com.jam.demo.entity.UserAccount;
import com.jam.demo.mapper.OrderMapper;
import com.jam.demo.request.OrderCreateRequest;
import com.jam.demo.request.OrderItemRequest;
import com.jam.demo.service.OrderItemService;
import com.jam.demo.service.OrderService;
import com.jam.demo.service.UserAccountService;
import com.jam.demo.vo.OrderDetailVO;
import com.jam.demo.vo.OrderItemVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
/**
* 订单服务实现类
* @author ken
* @date 2026-02-27
*/
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
private final OrderItemService orderItemService;
private final UserAccountService userAccountService;
private final PlatformTransactionManager transactionManager;
public OrderServiceImpl(OrderItemService orderItemService,
UserAccountService userAccountService,
PlatformTransactionManager transactionManager) {
this.orderItemService = orderItemService;
this.userAccountService = userAccountService;
this.transactionManager = transactionManager;
}
@Override
public String createOrder(OrderCreateRequest request) {
// 参数校验
if (ObjectUtils.isEmpty(request)) {
throw new IllegalArgumentException("订单创建请求参数不能为空");
}
if (request.getUserId() == null || request.getUserId() <= 0) {
throw new IllegalArgumentException("用户ID不能为空且必须大于0");
}
if (CollectionUtils.isEmpty(request.getItemList())) {
throw new IllegalArgumentException("订单商品列表不能为空");
}
// 生成订单编号
String orderNo = UUID.randomUUID().toString().replace("-", "").toUpperCase();
log.info("开始创建订单,订单编号:{},请求参数:{}", orderNo, JSON.toJSONString(request));
// 计算订单总金额
BigDecimal totalAmount = BigDecimal.ZERO;
List<OrderItem> orderItemList = Lists.newArrayList();
for (OrderItemRequest itemRequest : request.getItemList()) {
if (itemRequest.getProductId() == null || itemRequest.getProductId() <= 0) {
throw new IllegalArgumentException("商品ID不能为空且必须大于0");
}
if (!StringUtils.hasText(itemRequest.getProductName())) {
throw new IllegalArgumentException("商品名称不能为空");
}
if (itemRequest.getProductPrice() == null || itemRequest.getProductPrice().compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("商品单价不能小于0");
}
if (itemRequest.getQuantity() == null || itemRequest.getQuantity() <= 0) {
throw new IllegalArgumentException("商品数量必须大于0");
}
// 计算商品总价
BigDecimal itemTotalPrice = itemRequest.getProductPrice().multiply(BigDecimal.valueOf(itemRequest.getQuantity()));
totalAmount = totalAmount.add(itemTotalPrice);
// 封装订单明细
OrderItem orderItem = new OrderItem();
orderItem.setOrderNo(orderNo);
orderItem.setProductId(itemRequest.getProductId());
orderItem.setProductName(itemRequest.getProductName());
orderItem.setProductPrice(itemRequest.getProductPrice());
orderItem.setQuantity(itemRequest.getQuantity());
orderItem.setTotalPrice(itemTotalPrice);
orderItemList.add(orderItem);
}
// 编程式事务控制
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 保存订单主表
Order order = new Order();
order.setOrderNo(orderNo);
order.setUserId(request.getUserId());
order.setTotalAmount(totalAmount);
order.setPayAmount(totalAmount);
order.setOrderStatus(0);
order.setRemark(request.getRemark());
this.save(order);
// 批量保存订单明细
for (OrderItem orderItem : orderItemList) {
orderItem.setOrderId(order.getId());
}
orderItemService.saveBatch(orderItemList);
// 提交事务
transactionManager.commit(status);
log.info("订单创建成功,订单编号:{}", orderNo);
return orderNo;
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
log.error("订单创建失败,订单编号:{},异常信息:", orderNo, e);
throw new RuntimeException("订单创建失败:" + e.getMessage(), e);
}
}
@Override
public OrderDetailVO getOrderDetail(String orderNo) {
if (!StringUtils.hasText(orderNo)) {
throw new IllegalArgumentException("订单编号不能为空");
}
// 查询订单主信息
LambdaQueryWrapper<Order> orderWrapper = new LambdaQueryWrapper<>();
orderWrapper.eq(Order::getOrderNo, orderNo);
Order order = this.getOne(orderWrapper);
if (ObjectUtils.isEmpty(order)) {
throw new RuntimeException("订单不存在");
}
// 查询订单明细
LambdaQueryWrapper<OrderItem> itemWrapper = new LambdaQueryWrapper<>();
itemWrapper.eq(OrderItem::getOrderNo, orderNo);
List<OrderItem> itemList = orderItemService.list(itemWrapper);
// 封装返回结果
OrderDetailVO detailVO = new OrderDetailVO();
BeanUtils.copyProperties(order, detailVO);
List<OrderItemVO> itemVOList = Lists.newArrayList();
for (OrderItem item : itemList) {
OrderItemVO itemVO = new OrderItemVO();
BeanUtils.copyProperties(item, itemVO);
itemVOList.add(itemVO);
}
detailVO.setItemList(itemVOList);
return detailVO;
}
@Override
public Boolean payOrder(String orderNo, Long userId) {
if (!StringUtils.hasText(orderNo)) {
throw new IllegalArgumentException("订单编号不能为空");
}
if (userId == null || userId <= 0) {
throw new IllegalArgumentException("用户ID不能为空且必须大于0");
}
log.info("开始订单支付,订单编号:{},用户ID:{}", orderNo, userId);
// 编程式事务控制
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 查询订单信息
LambdaQueryWrapper<Order> orderWrapper = new LambdaQueryWrapper<>();
orderWrapper.eq(Order::getOrderNo, orderNo).eq(Order::getUserId, userId);
Order order = this.getOne(orderWrapper);
if (ObjectUtils.isEmpty(order)) {
throw new RuntimeException("订单不存在");
}
if (order.getOrderStatus() != 0) {
throw new RuntimeException("订单状态异常,无法支付");
}
// 扣减账户余额
Boolean deductResult = userAccountService.deductBalance(userId, order.getPayAmount());
if (!deductResult) {
throw new RuntimeException("账户余额不足,支付失败");
}
// 更新订单状态
order.setOrderStatus(1);
order.setPayTime(LocalDateTime.now());
this.updateById(order);
// 提交事务
transactionManager.commit(status);
log.info("订单支付成功,订单编号:{}", orderNo);
return Boolean.TRUE;
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
log.error("订单支付失败,订单编号:{},异常信息:", orderNo, e);
throw new RuntimeException("订单支付失败:" + e.getMessage(), e);
}
}
}
OrderController.java
package com.jam.demo.controller;
import com.jam.demo.request.OrderCreateRequest;
import com.jam.demo.service.OrderService;
import com.jam.demo.vo.BaseResult;
import com.jam.demo.vo.OrderDetailVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
* 订单控制器
* @author ken
* @date 2026-02-27
*/
@Slf4j
@RestController
@RequestMapping("/api/order")
@Tag(name = "订单管理", description = "订单相关接口")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping("/create")
@Operation(summary = "创建订单", description = "创建新订单接口")
public BaseResult<String> createOrder(@RequestBody OrderCreateRequest request) {
try {
String orderNo = orderService.createOrder(request);
return BaseResult.success(orderNo);
} catch (Exception e) {
log.error("创建订单异常,请求参数:{}", request, e);
return BaseResult.error(e.getMessage());
}
}
@GetMapping("/detail/{orderNo}")
@Operation(summary = "查询订单详情", description = "根据订单编号查询订单详情")
public BaseResult<OrderDetailVO> getOrderDetail(
@Parameter(description = "订单编号", required = true)
@PathVariable String orderNo) {
try {
OrderDetailVO detailVO = orderService.getOrderDetail(orderNo);
return BaseResult.success(detailVO);
} catch (Exception e) {
log.error("查询订单详情异常,订单编号:{}", orderNo, e);
return BaseResult.error(e.getMessage());
}
}
@PostMapping("/pay")
@Operation(summary = "订单支付", description = "订单支付接口,扣减账户余额,更新订单状态")
public BaseResult<Boolean> payOrder(
@Parameter(description = "订单编号", required = true)
@RequestParam String orderNo,
@Parameter(description = "用户ID", required = true)
@RequestParam Long userId) {
try {
Boolean result = orderService.payOrder(orderNo, userId);
return BaseResult.success(result);
} catch (Exception e) {
log.error("订单支付异常,订单编号:{},用户ID:{}", orderNo, userId, e);
return BaseResult.error(e.getMessage());
}
}
}
OceanbaseDemoApplication.java
package com.jam.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 项目启动类
* @author ken
* @date 2026-02-27
*/
@SpringBootApplication
@MapperScan("com.jam.demo.mapper")
public class OceanbaseDemoApplication {
public static void main(String[] args) {
SpringApplication.run(OceanbaseDemoApplication.class, args);
}
}
请求地址:POST http://127.0.0.1:8080/api/order/create请求体:
{
"userId": 10001,
"remark": "测试订单",
"itemList": [
{
"productId": 1001,
"productName": "华为Mate 70 Pro",
"productPrice": 6999.00,
"quantity": 1
},
{
"productId": 2001,
"productName": "华为FreeBuds Pro 4",
"productPrice": 999.00,
"quantity": 1
}
]
}
返回结果:
{
"code": 200,
"message": "success",
"data": "订单编号"
}
订单支付接口会同时更新订单状态与扣减账户余额,两个操作位于不同的表中,OceanBase会自动开启分布式事务,保证两个操作的原子性:要么全部成功,要么全部回滚。当账户余额不足时,订单状态不会更新,事务完全回滚,保证数据一致性。
OceanBase支持在同一集群内同时执行OLTP交易操作与OLAP分析操作,无需额外搭建数仓。以下为订单统计分析SQL,可直接在OceanBase中执行,高性能完成复杂分析:
-- 按用户统计订单数量与消费总金额
SELECT
user_id,
COUNT(id) AS order_count,
SUM(total_amount) AS total_consume_amount,
AVG(total_amount) AS avg_order_amount
FROM t_order
WHERE order_status = 3
GROUP BY user_id
ORDER BY total_consume_amount DESC;
-- 按月份统计订单数据
SELECT
DATE_FORMAT(create_time, '%Y-%m') AS order_month,
COUNT(id) AS total_order_count,
SUM(total_amount) AS total_sales_amount,
COUNT(DISTINCT user_id) AS pay_user_count
FROM t_order
WHERE order_status IN (1,2,3)
GROUP BY order_month
ORDER BY order_month;
limit offset, size,建议使用"主键过滤+分页"的方式,例如SELECT * FROM t_order WHERE id > 100000 LIMIT 20。EXPLAIN查看SQL执行计划,重点关注是否有全表扫描、全分区扫描、临时表、文件排序等低效执行路径。用户名@租户名#集群名,单机版可省略集群名;防火墙未开放2883端口。OceanBase作为国产原生分布式数据库的标杆产品,从底层架构上解决了传统单机数据库的性能、容量、高可用三大核心痛点,同时凭借高度的MySQL兼容性,实现了业务的平滑迁移,大幅降低了分布式数据库的使用门槛。
本文从底层原理到生产实战,全面讲解了OceanBase的核心能力:
对于企业与开发者而言,OceanBase不仅是MySQL的替代方案,更是面向未来的分布式数据底座,其HTAP混合负载能力、弹性扩缩容能力、金融级高可用能力,能够支撑企业从中小规模业务到超大规模互联网业务的全生命周期发展,无需进行架构重构。
OceanBase官方文档:https://www.oceanbase.com/docs OceanBase社区版下载地址:https://open.oceanbase.com