MyBatis-Flex数据库操作实战指南:从基础到高级应用
MyBatis-Flex轻量级ORM框架实战指南,聚焦Db、QueryWrapper、DbChain核心类,助开发者灵活控制SQL。涵盖单表CRUD、连表查询、分页、事务、批量操作等,附使用场景与最佳实践。无论新手还是有经验用户,皆可高效掌握数据库操作技巧。

MyBatis-Flex 数据库操作实战指南:从基础到高级应用
作为一款轻量级的ORM框架,MyBatis-Flex提供了简洁而强大的数据库操作能力。本文将系统介绍基于Db
、QueryWrapper
和DbChain
三个核心类的使用方法,特别适合那些需要灵活控制SQL的开发者。无论你是MyBatis-Flex新手还是有经验的用户,这份指南都能帮助你更高效地进行数据库操作。
目录
1. 单表基础操作(CRUD)
1.1 简单插入/更新/删除 - 推荐使用 Db
类
Db
类提供了简洁的静态方法,适合执行简单的数据库操作。
插入操作
java
// 基本插入
Row user = new Row();
user.set("name", "张三");
user.set("age", 25);
user.set("email", "zhangsan@example.com");
int result = Db.insert("user", user); // 返回影响行数
// 使用SQL插入 - 适合字段较少的场景
int result = Db.insertBySql("INSERT INTO user(name, age) VALUES(?, ?)", "李四", 30);
// 批量插入 - 高效处理多条记录
List<Row> users = Arrays.asList(user1, user2, user3);
int[] results = Db.insertBatch("user", users); // 返回每条记录的影响行数
更新操作
java
// 根据ID更新
Row updateData = new Row();
updateData.set("name", "李四");
updateData.set("age", 26);
int result = Db.updateById("user", updateData.setId("id", 1));
// 使用SQL更新 - 适合复杂条件更新
int result = Db.updateBySql("UPDATE user SET status = ? WHERE age > ?", 1, 18);
// 根据条件更新
Map<String, Object> whereCondition = Map.of("status", 0);
int result = Db.updateByMap("user", updateData, whereCondition);
删除操作
java
// 根据ID删除
int result = Db.deleteById("user", "id", 1);
// 根据条件删除
Map<String, Object> condition = Map.of("status", 0);
int result = Db.deleteByMap("user", condition);
// 使用SQL删除 - 适合复杂条件删除
int result = Db.deleteBySql("DELETE FROM user WHERE created_at < ?", lastMonth);
1.2 链式操作 - 推荐使用 DbChain
DbChain
提供了流畅的链式API,使代码更具可读性和可维护性。
链式插入
java
boolean success = DbChain.table("user")
.set("name", "王五")
.set("age", 30)
.set("email", "wangwu@example.com")
.save(); // 插入并返回操作是否成功
链式更新
java
boolean updated = DbChain.table("user")
.set("status", 1)
.set("updated_at", new Date())
.where("id = ?", 1)
.update(); // 更新并返回操作是否成功
链式删除
java
boolean deleted = DbChain.table("user")
.where("status = ? AND created_at < ?", 0, lastMonth)
.remove(); // 删除并返回操作是否成功
2. 单表查询操作
2.1 简单查询 - 推荐使用 Db
类
Db
类的查询方法适合快速获取数据,支持多种查询方式。
基础查询
java
// 根据ID查询单条记录
Row user = Db.selectOneById("user", "id", 1);
// 根据条件查询单条记录
Map<String, Object> condition = Map.of("email", "test@example.com");
Row user = Db.selectOneByMap("user", condition);
// 查询满足条件的列表
List<Row> users = Db.selectListByMap("user", condition);
// 查询表中所有记录
List<Row> allUsers = Db.selectAll("user");
SQL查询
java
// 直接SQL查询 - 适合复杂条件查询
String sql = "SELECT * FROM user WHERE status = ? AND age >= ?";
List<Row> users = Db.selectListBySql(sql, 1, 18);
// 查询单个值 - 适合聚合函数查询
Object maxAge = Db.selectObject("SELECT MAX(age) FROM user WHERE status = ?", 1);
// 统计查询 - 快速获取记录数
long count = Db.selectCount("SELECT COUNT(*) FROM user WHERE status = ?", 1);
2.2 链式查询 - 推荐使用 DbChain
DbChain
的链式查询API使查询条件的构建更加直观和灵活。
基础链式查询
java
// 单条查询
Row user = DbChain.table("user")
.where("email = ?", "test@example.com")
.one(); // 获取单条记录
// 可选查询(避免空指针异常)
Optional<Row> userOpt = DbChain.table("user")
.where("id = ?", 1)
.oneOpt(); // 获取Optional包装的记录
// 列表查询
List<Row> activeUsers = DbChain.table("user")
.where("status = ? AND age >= ?", 1, 18)
.orderBy("created_at DESC")
.limit(10) // 限制返回记录数
.list(); // 获取记录列表
统计和检查
java
// 统计记录数
long count = DbChain.table("user")
.where("status = ?", 1)
.count();
// 检查记录是否存在
boolean exists = DbChain.table("user")
.where("email = ?", "test@example.com")
.exists();
// 查询单个值
Object maxSalary = DbChain.table("user")
.select("MAX(salary)") // 指定查询字段
.where("dept_id = ?", 1)
.obj(); // 获取单个值
3. 连表查询
3.1 简单连表 - 推荐直接写SQL
对于简单的连表查询,直接编写SQL通常是最直观和高效的方式。
java
// 两表连接查询
String sql = """
SELECT u.*, r.role_name
FROM user u
LEFT JOIN role r ON u.role_id = r.id
WHERE u.status = ? AND r.status = ?
""";
List<Row> result = Db.selectListBySql(sql, 1, 1);
// 多表连接查询
String complexSql = """
SELECT
u.name,
d.dept_name,
COUNT(p.id) as project_count
FROM user u
LEFT JOIN department d ON u.dept_id = d.id
LEFT JOIN user_project up ON u.id = up.user_id
LEFT JOIN project p ON up.project_id = p.id
WHERE u.status = ? AND d.status = ?
GROUP BY u.id, d.id
HAVING COUNT(p.id) > ?
ORDER BY project_count DESC
""";
List<Row> complexResult = Db.selectListBySql(complexSql, 1, 1, 0);
3.2 动态连表 - 使用 QueryWrapper
当连表条件需要动态构建时,QueryWrapper
提供了灵活的API来构建查询。
java
// 构建动态连表查询
QueryWrapper query = QueryWrapper.create()
.select("u.*", "r.role_name", "d.dept_name")
.from("user u")
.leftJoin("role r").on("u.role_id = r.id")
.leftJoin("department d").on("u.dept_id = d.id")
.where("u.status = ?", 1);
// 动态添加条件
if (roleId != null) {
query.and("u.role_id = ?", roleId);
}
if (deptId != null) {
query.and("u.dept_id = ?", deptId);
}
if (StringUtil.hasText(keyword)) {
query.and("u.name LIKE ?", "%" + keyword + "%");
}
query.orderBy("u.created_at DESC");
List<Row> users = Db.selectListByQuery(query); // 执行查询
3.3 表别名设置 - 使用 QueryWrapper
在复杂查询中,合理使用表别名可以使SQL更清晰易读。MyBatis-Flex提供了多种设置表别名的方式:
为主表设置别名
java
// 方法1:使用as()方法为主表设置别名
QueryWrapper query = QueryWrapper.create()
.select("u.*")
.from("user")
.as("u") // 为user表设置别名u
.where("u.status = ?", 1);
// 生成SQL: SELECT u.* FROM user u WHERE u.status = ?
// 方法2:在from()方法中直接设置别名
QueryWrapper query = QueryWrapper.create()
.select("u.*")
.from(new QueryTable("user").as("u"))
.where("u.status = ?", 1);
为连接表设置别名
java
QueryWrapper query = QueryWrapper.create()
.select("u.*", "r.role_name")
.from("user u") // 主表直接设置别名
.leftJoin("role r") // 连接表直接设置别名
.on("u.role_id = r.id")
.where("u.status = ?", 1);
// 或者使用QueryTable对象
QueryWrapper query = QueryWrapper.create()
.select("u.*", "r.role_name")
.from(new QueryTable("user").as("u")) // 主表别名
.leftJoin(new QueryTable("role").as("r")) // 连接表别名
.on("u.role_id = r.id");
子查询别名
java
// 子查询作为表使用时设置别名
QueryWrapper subQuery = QueryWrapper.create()
.select("dept_id", "COUNT(*) as user_count")
.from("user")
.where("status = ?", 1)
.groupBy("dept_id");
QueryWrapper mainQuery = QueryWrapper.create()
.select("d.dept_name", "uc.user_count")
.from("department d")
.leftJoin(subQuery).as("uc").on("d.id = uc.dept_id"); // 子查询别名
4. 复杂查询
4.1 子查询
子查询是处理复杂数据关系的强大工具,MyBatis-Flex支持各种类型的子查询。
IN子查询
java
String subQuerySql = """
SELECT u.* FROM user u
WHERE u.dept_id IN (
SELECT d.id FROM department d
WHERE d.region = ? AND d.status = ?
)
AND u.salary > (
SELECT AVG(salary) FROM user WHERE dept_id = u.dept_id
)
""";
List<Row> result = Db.selectListBySql(subQuerySql, "华东", 1);
EXISTS子查询
java
String existsSql = """
SELECT u.* FROM user u
WHERE EXISTS (
SELECT 1 FROM user_role ur
WHERE ur.user_id = u.id AND ur.role_id = ?
)
""";
List<Row> usersWithRole = Db.selectListBySql(existsSql, 1);
4.2 窗口函数查询
窗口函数是现代数据库提供的高级特性,可以进行复杂的数据分析。
java
// 排名查询
String rankSql = """
SELECT
name,
salary,
dept_id,
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) as rank_in_dept,
RANK() OVER (ORDER BY salary DESC) as overall_rank
FROM user
WHERE status = ?
""";
List<Row> rankedUsers = Db.selectListBySql(rankSql, 1);
// 累计统计
String cumulativeSql = """
SELECT
DATE(created_at) as date,
COUNT(*) as daily_count,
SUM(COUNT(*)) OVER (ORDER BY DATE(created_at)) as cumulative_count
FROM user
WHERE created_at >= ?
GROUP BY DATE(created_at)
ORDER BY date
""";
List<Row> stats = Db.selectListBySql(cumulativeSql, startDate);
5. 分页查询
MyBatis-Flex提供了多种分页方式,可根据查询复杂度选择合适的方案。
5.1 简单分页 - 使用 Db.paginate
对于单表查询或简单连表查询,Db.paginate
方法可以快速实现分页。
java
// 构建查询条件
QueryWrapper query = QueryWrapper.create()
.select("*")
.from("user")
.where("status = ?", 1)
.orderBy("created_at DESC");
// 执行分页查询 - 参数:表名、页码、每页大小、查询条件
Page<Row> page = Db.paginate("user", 1, 20, query);
// 访问分页结果
System.out.println("总记录数: " + page.getTotalRow());
System.out.println("总页数: " + page.getTotalPage());
System.out.println("当前页数据: " + page.getRecords());
5.2 链式分页 - 使用 DbChain
DbChain
提供了更流畅的分页API,适合单表分页查询。
java
Page<Row> page = new Page<>(1, 20); // 创建分页对象,设置页码和每页大小
Page<Row> result = DbChain.table("user")
.where("status = ? AND age >= ?", 1, 18)
.orderBy("salary DESC", "created_at DESC")
.page(page); // 执行分页查询
// 已知总数的分页(性能优化)
Page<Row> pageWithTotal = new Page<>(2, 20, 1000L); // 指定总数避免重复统计
Page<Row> result = DbChain.table("user")
.where("status = ?", 1)
.page(pageWithTotal);
5.3 复杂连表分页
对于复杂查询,推荐使用手动分页方式,完全控制SQL执行过程。
java
// 1. 先查询总数
String countSql = """
SELECT COUNT(*) FROM user u
LEFT JOIN department d ON u.dept_id = d.id
WHERE u.status = ? AND d.region = ?
""";
long total = Db.selectCount(countSql, 1, "华东");
// 2. 再查询分页数据
String dataSql = """
SELECT u.*, d.dept_name
FROM user u
LEFT JOIN department d ON u.dept_id = d.id
WHERE u.status = ? AND d.region = ?
ORDER BY u.salary DESC
LIMIT ? OFFSET ?
""";
int pageNum = 1, pageSize = 20;
int offset = (pageNum - 1) * pageSize;
List<Row> data = Db.selectListBySql(dataSql, 1, "华东", pageSize, offset);
// 3. 手动构建分页对象
Page<Row> page = new Page<>(pageNum, pageSize, total);
page.setRecords(data);
5.4 分页方式选择建议
分页方式 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
Db.paginate |
单表查询、简单连表查询 | 代码简洁,自动处理计数和分页 | 对复杂查询支持有限 |
DbChain.page |
单表链式查询 | API流畅,代码可读性好 | 不适合复杂连表查询 |
手动分页 | 复杂连表查询、子查询、特殊SQL | 完全控制SQL,灵活性最高 | 代码量较大 |
选择建议:优先使用Db.paginate
或DbChain.page
处理简单分页,对于复杂查询场景则采用手动分页方式。
6. 事务操作
事务管理是确保数据一致性的关键,MyBatis-Flex提供了简洁的事务API。
6.1 简单事务
java
// 布尔返回值事务
boolean success = Db.tx(() -> {
// 插入用户
Row user = new Row();
user.set("name", "张三");
user.set("email", "zhangsan@example.com");
Db.insert("user", user);
// 插入用户角色关系
Row userRole = new Row();
userRole.set("user_id", user.get("id"));
userRole.set("role_id", 1);
Db.insert("user_role",