跳到主要内容

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 条件,因此这不是“无业务条件一定拒绝”的强安全保证。

建议:

  1. 每次更新和删除都写出明确的业务条件;
  2. 检查返回的影响行数;
  3. 批量写入需要全有或全无时显式放入事务;
  4. 真正的全表操作使用可审核的固定 SQL,不依赖内部开关;
  5. 原生 SQL 的表名、列名和排序片段只能来自可信白名单。