第 04 章编辑数据
这一章是整个工具里最需要小心的部分。核心是两句话: 数据网格是只读的,所有编辑都在右侧字段栏里做; 你在界面上做的任何修改都不会立刻写进数据库。 改动先进暂存区,你确认后再一次性提交。
为什么要有暂存区
如果每改一个字段就发一条 UPDATE,那你没有任何反悔的机会——
手滑改了生产库的一列数据,唯一的补救办法是去翻备份。
另一条同样重要的规矩:数据网格只读。网格只用来浏览和选择,改值一律在右侧的字段栏里做。 这样「看」和「改」是两件分开的事,拖选、滚动、双击都不会误改到数据。
把改动先攒起来,能带来三件好处:
- 可以预览。提交前能看到将要执行的确切 SQL,确认是改这 7 行而不是那 7 行。
- 可以整体放弃。一键回到服务器上的真实数据,什么都不用管。
- 要么全成要么全不成。所有改动打包在一个事务里,中间的语句失败就整体回滚,不会留下改了一半的状态。
工具栏「提交修改」按钮右边始终显示待提交的改动条数。它是 0 的时候整个按钮组是灰的, 所以「现在有没有没提交的东西」这个问题,扫一眼工具栏就知道。
什么时候能编辑
一张表要能编辑,必须先能被可靠地定位到某一行。不满足条件的表会被明确地置为只读。
| 表的条件 | 能不能编辑 | 状态栏会说什么 |
|---|---|---|
| 有主键 | 可以 | — |
| 有唯一索引,且索引列都不可为 NULL | 可以 | — |
| 唯一索引的列可以为 NULL | 不能 | 唯一索引的列可以为 NULL,无法可靠定位行 |
| 没有主键也没有唯一索引 | 不能 | 该表没有主键或唯一键,无法安全定位行 |
| 是视图 | 不能 | 视图不可编辑 |
| 连接处于只读模式 | 不能 | 该连接处于只读模式 |
- 「插入行」按钮直接隐藏,不是变灰
- 「删除行」禁用
- 右侧字段栏仍然显示这一行的字段和值,但所有编辑器禁用,栏顶写明原因
- 双击单元格改成打开快速查看(内容还是能看全的)
- 状态栏把原因写清楚,而不是留一堆灰按钮让你猜
在右侧字段栏里改字段
数据网格是只读的:不能在格子里改值,也没有「双击进入编辑」这回事。 所有字段值的修改都在右侧的字段栏里做——它是表数据视图里唯一的编辑入口。
字段栏长什么样
选中一行后,右侧的字段栏把这一行的所有列按表定义的顺序纵向列出来,一行一个字段。
| # | 元素 | 含义 |
|---|---|---|
| 1 | 工具栏最右的 ▤ | 显示 / 隐藏右侧字段栏。默认显示,没有快捷键;也可以走菜单「视图 → 显示 / 隐藏右侧字段栏」。 |
| 2 | 只读的数据网格 | 网格只负责浏览和选择:不能在格子里改值,也不能把多行文本铺开成二维表格粘进来。在网格里双击一个单元格,会自动跳到字段栏里对应的字段并聚焦;表不可编辑时则改为打开快速查看。 |
| 3 | 搜索字段 | 按列名过滤字段。右侧显示命中的数量,例如 显示 3 / 18;没有过滤时显示字段总数。 |
| 4 | 列名 + 类型 | 字段按表定义的顺序排列,不受网格的列显隐与列顺序影响。主键列的列名前带 🔑 并且加粗。类型是完整类型名(varchar(255)、int unsigned、decimal(10,2)),只读,不做类型转换。 |
| 5 | 值编辑器 | 点进去就能改这个字段。编辑器按列类型自动选,不用你挑(见下面两张图)。 |
| 6 | ∅ 按钮 | 点一下把这个字段设为 NULL,再点一下恢复原来的值。值本来就是 NULL 时按钮呈按下状态。 |
| 7 | 拖拽把手 | 拖它调整字段栏的宽度,范围 260–560pt(默认 320pt),按表记住。 |
- 字段栏里显示的是完整值:超过 4 KB 的列在选中行后会自动去服务器取一次。 如果这一行的大字段加起来超过 8 MB,就先不取,字段旁出现「加载完整内容…」,点一下才取。
- 没有选中行时显示
选中一行以查看和编辑它的字段;选中多行时显示已选中 12 行 · 请只选一行,不列字段。 - 在网格里双击一个单元格,字段栏会跳到它所在的行、并把对应的字段聚焦好,你直接就能改。
- 只有表数据标签里才有字段栏。查询结果、表结构、对象定义这些标签不显示。
编辑器按列类型自动选
点字段里的值就进入编辑,编辑器由这一列的类型决定。
| # | 列类型 | 用什么改 |
|---|---|---|
| 8 | 普通文本 | 单行输入框。 |
| 9 | 长文本 / JSON | 多行输入框,可以换行。按 ⇧↩ 换行不会提交,⌘↩ 才提交。 |
| 10 | 「展开」 | 把多行编辑器放大成一个独立的大窗口,同样带行号与查找,长内容在这里改更舒服。 |
| 11 | 数字 | 单行输入框,右对齐。只接受合法数字(含负号和小数点)。 |
| 12 | 日期 / 时间 | 日期选择器 + 手输。时间部分也可以直接打进去;时间戳这类值一律按文本解析,避免时区看错。 |
| # | 列类型 | 用什么改 |
|---|---|---|
| 13 | ENUM | 下拉选择。取值来自列定义,不需要手输,也不会拼错。 |
| 14 | SET | 多选。勾中的值用逗号拼在一起写入;值必须来自列定义。 |
| 15 | 布尔(tinyint(1)) |
偏好里打开「把 tinyint(1) 显示为复选框」之后,这一列就是一个复选框;没打开时按普通数字手输。 |
| 16 | 查看 | 打开快速查看。大字段还没取完整值时,点它才去服务器取。 |
| 17 | 从文件导入… | 把文件内容作为这个字段的新值(二进制原样读入)。 |
| 18 | 设为 NULL | BLOB 的 ∅。二进制不能当文本改,只能整个设为 NULL;再点一次恢复原值。 |
提交这次编辑
| 按键 / 动作 | 结果 |
|---|---|
| 失去焦点,或 ↩ | 把这个值写进暂存区(不会立刻落库) |
| Tab / ⇧Tab | 提交并移到下一个 / 上一个字段 |
| Esc | 放弃这次编辑,恢复原值 |
| ⇧↩ | 多行编辑器里换行,不提交 |
| ⌘↩ | 多行编辑器里提交 |
| ⌘V | 把剪贴板里的纯文本贴成这一个字段的值(见下面「粘贴」) |
把字段设为 NULL
NULL,再点一下恢复原来的值。| # | 元素 | 含义 |
|---|---|---|
| 19 | ∅(设为 NULL) | 点一下把这个字段的值设成 NULL。这一步同样只进暂存区,提交时才落库。 |
| 20 | ∅(再点一次) | 恢复到刚才那个值;没有记录时恢复成空文本。从 NULL 恢复不需要重新去服务器取值。 |
| 21 | NULL 与空字符串 | NULL 显示成灰色的 NULL,空字符串显示成一格空白。它们是两个不同的值,别当成一回事。 |
校验
- 数字列只接受合法数字(含负号和小数点)。
- 日期 / 时间列校验格式,解析不出来就报错。
SET的值必须来自列定义。- 校验不通过时输入框抖动并给出提示,保持编辑状态不退出,值也不会写进暂存区——你可以直接改到对。
外观反馈:改完之后会看到什么
- 字段栏里改过的字段变成橙色底色,左上角出现小三角标记。
- 网格里对应的单元格也变橙色,修改过的行在行号列出现标记。
- 这些标记一直保留到提交或放弃。
- 同一行里改了多个字段,提交时会合并成一条
UPDATE,不会一行发一次。
改回原值
把某个字段改回原来的值,这个字段的修改标记会自动消失; 如果一行里所有改动都被改回去了,这一行就重新变成「干净」的。
插入、复制、删除行
插入行
- 点状态栏的
+ 行,或者按 ⌘I。 - 网格底部出现一条绿色虚线行,同时右侧字段栏切到「新增行」模式:字段全部为空,光标停在第一个可编辑字段上。
- 按 Tab 往下依次填。只填需要填的列,留空的列交给数据库默认值。
- 自增主键留空即可,提交后由数据库生成。
- 没提交之前按 Esc 可以取消这一行。
复制行
- 选中若干行,按 ⌘D,或右键 →
复制行。 - 复制出来的行作为新增行插进来,自增主键会被清空,其余列保留原值。
- 复制出的行立刻进入暂存状态,字段栏切到这一行,可以直接接着改。
删除行
- 选中行按 ⌫,或右键 →
删除行。 - 行立刻变淡加删除线,但还没真正删除。
- 删除前会显示将要执行的条件,例如
WHERE id = 42,让你确认删的是哪一行。 - 已标记删除的行不能在字段栏里编辑:字段全部变灰、只读,栏顶显示
这一行已标记删除与「撤销删除」。想改要先撤销删除。
| # | 情况 | 字段栏里是什么样 |
|---|---|---|
| 22 | 新增行 | 栏顶标注「新增行」,字段全部为空,光标在第一个可编辑字段上。留空的列交给数据库默认值,自增主键留空即可。 |
| 23 | 已标记删除 | 栏顶显示 这一行已标记删除 和「撤销删除」按钮;字段全部变灰、只读。想改要先撤销删除。 |
| 24 | 不可编辑 | 栏顶写明原因(比如 该表没有主键或唯一键,无法安全定位行);字段和值照常显示,但所有编辑器禁用。双击单元格改为打开快速查看。 |
粘贴
字段栏里也支持粘贴,但只贴一个字段:把光标放进某个字段的编辑器,按 ⌘V, 剪贴板里的纯文本就成为这一个字段的值,然后走和手工输入一样的校验。
网格上不再支持把带制表符 / 换行的多行文本铺开成二维表格——网格是只读的。
需要批量改数据时,去 SQL 编辑器里写 UPDATE。
二维铺开粘贴要求网格可编辑,而我们把网格整个设成了只读:这样拖选、滚动、双击都不会误改数据。 批量改动走 SQL 编辑器更可控,也能在提交前看清语句。这是刻意的简化,不是漏掉的。
暂存区的规则
暂存区属于当前标签。每个表数据标签各有一个,互不影响。切到别的标签不会丢内容。 在同一个标签里,同一行最多只会有一条待提交的改动。
| 已有 | 新操作 | 结果 |
|---|---|---|
| 无 | 改某列 | 记为「修改」 |
| 已改 A 列 | 再改 B 列 | 合并成一次「修改」 |
| 已改 A 列 | 把 A 列改回原值 | 这一行的改动消失 |
| 无 | 新增行 | 记为「新增」 |
| 新增行 | 继续改这一行 | 合并进「新增」 |
| 新增行 | 又删除这一行 | 两者都消失,不产生任何操作 |
| 无 | 删除行 | 记为「删除」 |
| 已改某行 | 又删除该行 | 「修改」被「删除」取代 |
| 已删除某行 | 试图编辑该行 | 拒绝,提示先撤销删除 |
右键某一行 → 撤销该行的修改,可以只回退这一行,别的改动不受影响。
预览
按 ⇧⌘P 或点工具栏「预览」,看看将要执行什么。
面板里显示的语句就是实际会下发的语句,不存在「预览是一套、执行是另一套」的情况。 这一点是刻意设计的:所有写入都直接生成 SQL 文本,不经过参数化改写。
把鼠标移到预览里的某一条语句上,网格里对应的那一行会高亮,方便你确认。
- 复制全部:把这几条语句拷到剪贴板。
- 在新查询标签中打开:把这些语句放进一个查询标签,你可以手动调整后再执行。 注意从这里走出去以后就不再走暂存区了,改完直接执行会真的生效。
提交
按 ⌘S 或点工具栏「提交」。提交过程是这样的:
- 界面锁定编辑,状态栏显示
正在提交 3/7… - 所有改动在一个事务里依次执行
- 全部成功 → 清空暂存区,重新加载当前页,状态栏短暂显示
已提交 7 处修改,耗时 128 ms - 任何一条失败 → 整个事务回滚,所有改动都没生效,弹出错误面板
提交失败时你的修改原样保留在暂存区,可以修正后再提交。 因为事务已经整体回滚,数据库里什么都没变,所以这时也不需要「回退」什么。
提交过程中的其他规矩
- 可以取消。取消会在两条语句之间停下来并回滚。
- 提交超时时会提示:
提交超时,事务状态未知,请在数据库中手动核对这几行的数据。 这是少数几个没法自动补救的情况,必须人工确认。 - 暂存区内容只由编辑操作生成,正常不会包含结构变更语句;提交前仍会做一次防御性检查, 若发现 INSERT / UPDATE / DELETE 以外的语句,会直接拒绝,并提示你改用 SQL 编辑器执行。
某条语句影响 0 行怎么办
如果某条 UPDATE / DELETE 影响 0 行(比如这一行已经被别处删掉了),
视为成功,不报错。Console Log 里会记一条「影响 0 行」,
提交完成后这一行会从刷新后的数据里消失。
这样做是有意的:如果你在改一条别人刚删掉的数据,弹一个错误出来只会打断你, 反正结果(那一行不存在)和你想的一样。
放弃
- ⇧⌘⌫ 或点工具栏「放弃」:清空整个暂存区并重新加载当前页。
- 改动超过 5 条,或者包含删除 / 新增时,会先弹窗确认。
- 只想回退一行:右键那一行 →
撤销该行的修改。 - 放弃后表格恢复成服务器上的真实数据。
有未提交改动时的保护
下面这些操作会先问你,避免手一滑把攒了半天的改动弄丢:
- 关闭这个标签
- 断开或切换连接
- 重载当前页(⌘R)
- 应用过滤器或改变排序
- 退出 App
一个必须知道的限制:不检测并发修改
TableLite 不检测「这一行在你打开页面之后是否被别人改过」。 提交时直接用你本地的值覆盖服务器上的当前值。
也就是说:如果你在 10:00 打开一行、10:05 才提交,而别人在 10:02 改过同一行, 那么别人的改动会被你覆盖掉,而且不会有任何提示。
这是刻意的取舍——要检测就得给每张表加版本列或者比对整行原值, 对一个自用工具来说不划算。用在多人同时在写的表上时请自己注意。