MyBatis-Flex DB Operations Hands-On Guide: Basics to Advanced
Hands-On Guide to MyBatis-Flex lightweight ORM framework, focusing on core classes Db, QueryWrapper, DbChain for flexible SQL control. Covers single-table CRUD, join queries, pagination, transactions, batch operations, with usage scenarios and best practices. Helps both beginners and experienced users master database operation skills efficiently.

MyBatis-Flex DB Operations Hands-On Guide: Basics to Advanced
As a lightweight ORM framework, MyBatis-Flex provides concise yet powerful database operation capabilities. This article systematically introduces the usage methods based on three core classes: Db, QueryWrapper, and DbChain, making it particularly suitable for developers who need flexible control over SQL. Whether you're new to MyBatis-Flex or an experienced user, this guide will help you perform database operations more efficiently.
Table of Contents
- 1. Basic Single-Table Operations (CRUD)
- 2. Single-Table Query Operations
- 3. Join Queries
- 4. Complex Queries
- 5. Pagination Queries
- 6. Transaction Operations
- 7. Batch Operations
- 8. Recommended Usage Scenarios Summary
- 9. Best Practice Recommendations
1. Basic Single-Table Operations (CRUD)
1.1 Simple Insert/Update/Delete - Recommended Using Db Class
The Db class provides concise static methods suitable for performing simple database operations.
Insert Operations
java
// Basic insert
Row user = new Row();
user.set("name", "张三");
user.set("age", 25);
user.set("email", "zhangsan@example.com");
int result = Db.insert("user", user); // Returns number of affected rows
// SQL-based insert - suitable for scenarios with few fields
int result = Db.insertBySql("INSERT INTO user(name, age) VALUES(?, ?)", "李四", 30);
// Batch insert - efficiently handles multiple records
List<Row> users = Arrays.asList(user1, user2, user3);
int[] results = Db.insertBatch("user", users); // Returns affected rows for each record
Update Operations
java
// Update by ID
Row updateData = new Row();
updateData.set("name", "李四");
updateData.set("age", 26);
int result = Db.updateById("user", updateData.setId("id", 1));
// SQL-based update - suitable for complex condition updates
int result = Db.updateBySql("UPDATE user SET status = ? WHERE age > ?", 1, 18);
// Update by condition
Map<String, Object> whereCondition = Map.of("status", 0);
int result = Db.updateByMap("user", updateData, whereCondition);
Delete Operations
java
// Delete by ID
int result = Db.deleteById("user", "id", 1);
// Delete by condition
Map<String, Object> condition = Map.of("status", 0);
int result = Db.deleteByMap("user", condition);
// SQL-based delete - suitable for complex condition deletions
int result = Db.deleteBySql("DELETE FROM user WHERE created_at < ?", lastMonth);
1.2 Chained Operations - Recommended Using DbChain
DbChain provides a fluent chained API that makes code more readable and maintainable.
Chained Insert
java
boolean success = DbChain.table("user")
.set("name", "王五")
.set("age", 30)
.set("email", "wangwu@example.com")
.save(); // Inserts and returns whether operation was successful
Chained Update
java
boolean updated = DbChain.table("user")
.set("status", 1)
.set("updated_at", new Date())
.where("id = ?", 1)
.update(); // Updates and returns whether operation was successful
Chained Delete
java
boolean deleted = DbChain.table("user")
.where("status = ? AND created_at < ?", 0, lastMonth)
.remove(); // Deletes and returns whether operation was successful
2. Single-Table Query Operations
2.1 Simple Queries - Recommended Using Db Class
The query methods of the Db class are suitable for quickly retrieving data and support multiple query methods.
Basic Queries
java
// Query single record by ID
Row user = Db.selectOneById("user", "id", 1);
// Query single record by condition
Map<String, Object> condition = Map.of("email", "test@example.com");
Row user = Db.selectOneByMap("user", condition);
// Query list satisfying conditions
List<Row> users = Db.selectListByMap("user", condition);
// Query all records in table
List<Row> allUsers = Db.selectAll("user");
SQL Queries
java
// Direct SQL query - suitable for complex condition queries
String sql = "SELECT * FROM user WHERE status = ? AND age >= ?";
List<Row> users = Db.selectListBySql(sql, 1, 18);
// Query single value - suitable for aggregate function queries
Object maxAge = Db.selectObject("SELECT MAX(age) FROM user WHERE status = ?", 1);
// Count query - quickly get record count
long count = Db.selectCount("SELECT COUNT(*) FROM user WHERE status = ?", 1);
2.2 Chained Queries - Recommended Using DbChain
The chained query API of DbChain makes building query conditions more intuitive and flexible.
Basic Chained Queries
java
// Single record query
Row user = DbChain.table("user")
.where("email = ?", "test@example.com")
.one(); // Get single record
// Optional query (avoids null pointer exceptions)
Optional<Row> userOpt = DbChain.table("user")
.where("id = ?", 1)
.oneOpt(); // Get Optional-wrapped record
// List query
List<Row> activeUsers = DbChain.table("user")
.where("status = ? AND age >= ?", 1, 18)
.orderBy("created_at DESC")
.limit(10) // Limit number of returned records
.list(); // Get record list
Statistics and Checks
java
// Count records
long count = DbChain.table("user")
.where("status = ?", 1)
.count();
// Check if record exists
boolean exists = DbChain.table("user")
.where("email = ?", "test@example.com")
.exists();
// Query single value
Object maxSalary = DbChain.table("user")
.select("MAX(salary)") // Specify query field
.where("dept_id = ?", 1)
.obj(); // Get single value
3. Join Queries
3.1 Simple Joins - Recommended Writing SQL Directly
For simple join queries, writing SQL directly is usually the most intuitive and efficient approach.
java
// Two-table join query
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);
// Multi-table join query
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 Dynamic Joins - Using QueryWrapper
When join conditions need to be dynamically constructed, QueryWrapper provides a flexible API for building queries.
java
// Build dynamic join query
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);
// Dynamically add conditions
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); // Execute query
3.3 Table Alias Settings - Using QueryWrapper
In complex queries, using table aliases appropriately can make SQL clearer and more readable. MyBatis-Flex provides multiple ways to set table aliases:
Setting Alias for Main Table
java
// Method 1: Use as() method to set alias for main table
QueryWrapper query = QueryWrapper.create()
.select("u.*")
.from("user")
.as("u") // Set alias u for user table
.where("u.status = ?", 1);
// Generated SQL: SELECT u.* FROM user u WHERE u.status = ?
// Method 2: Set alias directly in from() method
QueryWrapper query = QueryWrapper.create()
.select("u.*")
.from(new QueryTable("user").as("u"))
.where("u.status = ?", 1);
Setting Alias for Joined Tables
java
QueryWrapper query = QueryWrapper.create()
.select("u.*", "r.role_name")
.from("user u") // Set main table alias directly
.leftJoin("role r") // Set joined table alias directly
.on("u.role_id = r.id")
.where("u.status = ?", 1);
// Or using QueryTable object
QueryWrapper query = QueryWrapper.create()
.select("u.*", "r.role_name")
.from(new QueryTable("user").as("u")) // Main table alias
.leftJoin(new QueryTable("role").as("r")) // Joined table alias
.on("u.role_id = r.id");
Subquery Aliases
java
// Setting alias when using subquery as table
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"); // Subquery alias
4. Complex Queries
4.1 Subqueries
Subqueries are powerful tools for handling complex data relationships, and MyBatis-Flex supports various types of subqueries.
IN Subquery
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 Subquery
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 Window Function Queries
Window functions are advanced features provided by modern databases for complex data analysis.
java
// Ranking query
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);
// Cumulative statistics
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. Pagination Queries
MyBatis-Flex provides multiple pagination methods, allowing you to choose the appropriate solution based on query complexity.
5.1 Simple Pagination - Using Db.paginate
For single-table queries or simple join queries, the Db.paginate method can quickly implement pagination.
java
// Build query conditions
QueryWrapper query = QueryWrapper.create()
.select("*")
.from("user")
.where("status = ?", 1)
.orderBy("created_at DESC");
// Execute pagination query - parameters: table name, page number, page size, query conditions
Page<Row> page = Db.paginate("user", 1, 20, query);
// Access pagination results
System.out.println("Total records: " + page.getTotalRow());
System.out.println("Total pages: " + page.getTotalPage());
System.out.println("Current page data: " + page.getRecords());
5.2 Chained Pagination - Using DbChain
DbChain provides a more fluent pagination API, suitable for single-table pagination queries.
java
Page<Row> page = new Page<>(1, 20); // Create pagination object, set page number and page size
Page<Row> result = DbChain.table("user")
.where("status = ? AND age >= ?", 1, 18)
.orderBy("salary DESC", "created_at DESC")
.page(page); // Execute pagination query
// Pagination with known total (performance optimization)
Page<Row> pageWithTotal = new Page<>(2, 20, 1000L); // Specify total to avoid duplicate counting
Page<Row> result = DbChain.table("user")
.where("status = ?", 1)
.page(pageWithTotal);
5.3 Complex Join Pagination
For complex queries, manual pagination is recommended to fully control the SQL execution process.
java
// 1. First query total count
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. Then query paginated data
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. Manually build pagination object
Page<Row> page = new Page<>(pageNum, pageSize, total);
page.setRecords(data);
5.4 Pagination Method Selection Recommendations
| Pagination Method | Applicable Scenarios | Advantages | Disadvantages |
|---|---|---|---|
Db.paginate |
Single-table queries, simple join queries | Concise code, automatically handles counting and pagination | Limited support for complex queries |
DbChain.page |
Single-table chained queries | Fluent API, good code readability | Not suitable for complex join queries |
| Manual pagination | Complex join queries, subqueries, special SQL | Full control over SQL, highest flexibility | More code required |
Recommendation: Prefer Db.paginate or DbChain.page for simple pagination, and use manual pagination for complex query scenarios.
6. Transaction Operations
Transaction management is crucial for ensuring data consistency, and MyBatis-Flex provides a concise transaction API.
6.1 Simple Transactions
java
// Boolean return value transaction
boolean success = Db.tx(() -> {
// Insert user
Row user = new Row();
user.set("name", "张三");
user.set("email", "zhangsan@example.com");
Db.insert("user", user);
// Insert user-role relationship
Row userRole = new Row();
userRole.set("user_id", user.get("id"));
userRole.set("role_id", 1);
Db.insert("user_role", userRole);