3.1 基础 CRUD
本页集中说明查询、插入、更新和删除。批量写入、复杂条件、分页与结果映射分别见对应专题。
Pojo 查询(推荐)
查询单条记录
// 方式1:返回 Bean
User user = DB.pojo.selectWrapper(User.class)
.eq(User::getId, 1)
.queryBean();
// 方式2:返回 ResultMap
ResultMap result = DB.pojo.selectWrapper(User.class)
.eq(User::getId, 1)
.queryOne();
查询列表
// 查询全部
List<User> all = DB.pojo.selectWrapper(User.class).queryBeanList();
// 条件查询
List<User> users = DB.pojo.selectWrapper(User.class)
.eq(User::getStatus, 1)
.gt(User::getAge, 18)
.orderByDesc(User::getCreateTime)
.queryBeanList();
查询数量
long count = DB.pojo.selectWrapper(User.class)
.eq(User::getStatus, 1)
.count();
查询指定字段
List<User> users = DB.pojo.selectWrapper(User.class)
.select(User::getId, User::getName, User::getAge)
.eq(User::getStatus, 1)
.queryBeanList();
查询单个字段值
List<String> cities = DB.pojo.selectWrapper(User.class)
.select(User::getCity)
.queryStrList();
String city = DB.pojo.selectWrapper(User.class)
.select(User::getCity)
.eq(User::getId, 1)
.queryStr();
Table 查询(表名方式)
基础查询
// 查询单条
ResultMap result = DB.table.selectWrapper("user").eq("id", 1).queryOne();
User user = DB.table.selectWrapper("user").eq("id", 1).queryOne(User.class);
// 查询列表
List<ResultMap> list = DB.table.selectWrapper("user").eq("status", 1).queryList();
List<User> users = DB.table.selectWrapper("user").eq("status", 1).queryList(User.class);
动态表名
String tableName = "user_" + year;
List<ResultMap> list = DB.table.selectWrapper(tableName)
.eq("status", 1)
.queryList();
原生 SQL 查询
使用 ? 占位符
// 单条结果
ResultMap result = DB.jdbc.selectWrapper("SELECT * from user WHERE id = ?", 1).queryOne();
User user = DB.jdbc.selectWrapper("SELECT * from user WHERE id = ?", 1).queryOne(User.class);
// 列表结果
List<ResultMap> list = DB.jdbc.selectWrapper(
"SELECT * FROM user WHERE status = ? AND age > ?", 1, 18
).queryList();
// 单个值
String name = DB.jdbc.selectWrapper("SELECT name FROM user WHERE id = ?", 1).queryStr();
List<Long> ids = DB.jdbc.selectWrapper("SELECT id FROM user WHERE status = ?", 1).queryLongList();
复杂查询
String sql = "SELECT u.*, d.name AS dept_name "
+ "FROM user u "
+ "LEFT JOIN department d ON u.dept_id = d.id "
+ "WHERE u.status = ? AND d.type = ? "
+ "ORDER BY u.create_time DESC";
List<ResultMap> list = DB.jdbc.selectWrapper(sql, 1, "tech").queryList();
查询结果
返回值遵循一组固定规则:带 Bean 的方法返回当前 Pojo 类型,不带 Bean 的方法返回 ResultMap,带 Class 参数的方法映射为指定类型;queryOne* 严格限制单条,queryFirst* 只取第一条。
分页、完整返回类型表、Bean 映射和 ResultMap 深度取值见 3.3 分页排序与结果映射。
插入
实体插入
User user = new User();
user.setName("张三");
user.setAge(25);
DB.pojo.insert(user);
Long id = user.getId();
DB.pojo.insert(user) 会直接执行,并在主键策略支持时把生成值回填到实体。
按表名插入
JSONMap values = new JSONMap()
.set("name", "张三")
.set("age", 25);
int affected = DB.table.insert("user", values);
Long id = DB.table.insertWithAutoKey("user", values);
需要逐步构造字段时使用 Wrapper:
DB.table.insertWrapper("user")
.value("name", "张三")
.value("age", 25)
.execute();
插入或更新
DB.pojo.insertOrUpdateById(user);
DB.table.insertOrUpdate("user", values);
这两个方法根据主键是否为空选择 INSERT 或 UPDATE,不是数据库原子 Upsert,也不会先查询记录是否存在。
批量插入见 3.6 批量操作。
更新
按 ID 更新实体
int affected = DB.pojo.updateById(user);
默认更新非空字段。如需写入 null,应使用当前更新 API 支持的 UpdateOption.INCLUDE_NULL。
条件更新
int affected = DB.pojo.updateWrapper(User.class)
.set(User::getName, "李四")
.set(User::getUpdateTime, new Date())
.eq(User::getId, id)
.execute();
使用实体中已有值构建更新:
int affected = DB.pojo.updateWrapper(user)
.eq(User::getId, user.getId())
.execute();
按表名更新:
int affected = DB.table.updateWrapper("user")
.set("name", "李四")
.set("update_time", new Date())
.eq("id", id)
.execute();
Pojo Update 支持显式表达式:
DB.pojo.updateWrapper(User.class)
.setSql("login_count = login_count + 1")
.eq(User::getId, id)
.execute();
setSql 接收原生 SQL 片段,只应用于可信的固定表达式,不要拼接用户输入。
删除
按 ID 删除
int affected = DB.pojo.deleteById(User.class, id);
int tableAffected = DB.table.deleteById("user", id);
条件删除
int affected = DB.pojo.deleteWrapper(User.class)
.eq(User::getStatus, 0)
.lt(User::getCreateTime, cutoff)
.execute();
按表名删除:
DB.table.deleteWrapper("user")
.eq("id", id)
.execute();
存在逻辑删除字段时,删除默认改写为逻辑删除。物理删除、查询已删除数据等规则见 3.5 逻辑删除。
写操作安全边界
更新和删除 Wrapper 必须显式添加业务条件:
// 危险:启用逻辑删除时可能影响全部 deleted = 0 的记录
DB.pojo.updateWrapper(User.class)
.set(User::getStatus, 0)
.execute();
// 危险:可能逻辑删除全部未删除记录
DB.pojo.deleteWrapper(User.class).execute();
当最终 WHERE 完全为空时,当前构建器会生成 WHERE false。但逻辑删除插件注入的 deleted = 0 已经算作 WHERE 条件,因此这不是“无业务条件一定拒绝”的强安全保证。
建议:
- 每次更新和删除都写出明确的业务条件;
- 检查返回的影响行数;
- 批量写入需要全有或全无时显式放入事务;
- 真正的全表操作使用可审核的固定 SQL,不依赖内部开关;
- 原生 SQL 的表名、列名和排序片段只能来自可信白名单。