适合人群:想最快用上 Oracle 的人。概念只讲”现在必须知道的”,全部命令可复制运行;原理深挖放到文末延伸。
一、30 秒认识 Oracle(可跳过)
Oracle 是老牌商用数据库,银行、电信、政务系统的常客。我们学习用官方 Free 免费版:限 2 核 CPU、2GB 内存、12GB 用户数据,个人学习绰绰有余,语法和企业版完全一致。
开跑前只记一件事:你连接的是实例(活着的进程 + 内存),数据存在数据库(磁盘上的文件),两者合起来才是常说的一套”Oracle Server”。这个区分现在不重要,以后排错时特别有用——连不上多是实例问题,数据丢了/变慢多是存储问题。
二、5 分钟:装好并连上
2.1 Docker 一条命令启动
1 | docker run -d --name oracle-free \ |
2.2 三种连接方式,选一个
| 方式 | 适合谁 |
|---|---|
| sqlplus 命令行(容器内,零配置) | 跟着本文走,用这个 |
| SQL Developer / DBeaver 图形客户端 | 日常写 SQL |
浏览器打开 Database Actions(http://localhost:8080) |
不想装任何软件 |
命令行直进:
1 | docker exec -it oracle-free sqlplus system/Test_1234@localhost/FREEPDB1 |
连接串拆开看:用户名/密码@主机/服务名。服务名是 FREEPDB1,别写成别的——Oracle 12c 之后分两层:CDB(底盘)和 PDB(插上去的业务库),我们全程在 PDB 里干活,现阶段记住这个名字就够了。
连上后跑两条验证:
1 | SELECT instance_name, status FROM v$instance; -- 状态应为 OPEN |
退出用 EXIT。图形工具的连接参数就四样:主机 localhost、端口 1521、服务名 FREEPDB1、用户 system / Test_1234。
三、2 分钟:建一个自己的用户
system 是管理员账号,别直接在上面建表。三条命令建一个属于自己的 frank:
1 | CREATE USER frank IDENTIFIED BY Pass_1234 |
换 frank 登录:
1 | docker exec -it oracle-free sqlplus frank/Pass_1234@localhost/FREEPDB1 |
这里藏着和 MySQL 最大的不同:Oracle 没有”库”和 USE 切库这回事,用户就是命名空间(schema)——frank 建的表全名都是 frank.xxx,要访问别人 scott 的表就写 scott.emp。
顺带一提 DEFAULT TABLESPACE users:表在逻辑上放进 USERS 表空间,物理上才落到 .dbf 数据文件里(中间还有段、区、块三层,入门阶段只需记住一条铁律:业务表放 USERS,永远别往 SYSTEM 放)。
四、10 分钟:跑通增删改查
以下全部用 frank 执行。
4.1 建两张表
1 | CREATE TABLE users ( |
类型三句话:字符串一律 VARCHAR2(n CHAR)——必须带 CHAR,按字符计数,存中文才不会截断;数字只有 NUMBER(p,s),整数小数通吃、金额精确;时间用 DATE,自带时分秒。自增主键不叫 AUTO_INCREMENT,叫 GENERATED BY DEFAULT AS IDENTITY。
4.2 增:INSERT
1 | INSERT INTO users (username, email) VALUES |
必须记住:Oracle 默认不自动提交。不敲 COMMIT,数据只在当前会话可见,断连就没了。
1 | COMMIT; -- 保存 |
4.3 查:SELECT
1 | -- 全表 |
4.4 改与删:UPDATE / DELETE
1 | UPDATE orders SET order_status = '已支付' WHERE order_id = 2; |
4.5 分页
1 | -- 推荐写法(12c+),对应 MySQL 的 LIMIT 10,10 |
但老项目里满地都是 ROWNUM 写法,看懂即可:
1 | SELECT * FROM ( |
ROWNUM 有个著名的坑:WHERE ROWNUM > 1 永远查不到数据——编号是行被取出那一刻才分配的,不满足条件的行被丢弃后,下一行又从 1 开始测试,全军覆没。所以必须”子查询先编号,外层再取区间”,口诀:上界在内,下界在外。
五、避坑速查:和 MySQL 不一样的地方
一张表全部带走:
| 场景 | MySQL | Oracle |
|---|---|---|
| 自增主键 | AUTO_INCREMENT |
GENERATED BY DEFAULT AS IDENTITY |
| 前 N 条 | LIMIT 10 |
FETCH FIRST 10 ROWS ONLY |
| 分页 | LIMIT 10, 10 |
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY |
| 切库 | USE mydb |
没有;用户即库,写 frank.users |
| 当前时间 | NOW() |
SYSDATE |
| 字符串拼接 | CONCAT(a, b) |
a || b |
| 判空替换 | IFNULL(x, y) |
NVL(x, y) |
| 时间格式化 | DATE_FORMAT(t, '%Y-%m-%d') |
TO_CHAR(t, 'YYYY-MM-DD') |
| 大文本 | TEXT |
CLOB |
| 反引号 | `col` |
什么都不加 |
| 自动提交 | 默认开 | 默认关,手动 COMMIT |
两个必踩的坑:
坑一,空字符串就是 NULL:
1 | UPDATE users SET email = '' WHERE user_id = 1; -- 实际效果 = SET email = NULL |
坑二,标识符统一按大写存储:数据字典里查到的是 USERS 不是 users;数据本身('alice' 和 'ALICE')照旧区分大小写。另外别用双引号建表——CREATE TABLE "my_table" 会强制保留小写,以后每次访问都得带引号,纯属自找麻烦。
思考与练习(10 分钟)
- 建一张
products表(商品名/价格/库存),插入 3 条数据并提交。 - 查价格大于 200 的商品,按价格倒序,只取前 2 条。
- 把一条订单的
amount改成 -1 会发生什么?(提示:CHECK 约束) - 故意
UPDATE后不提交,另开一个窗口查询,能看到改动吗?再试试ROLLBACK。
本章核心总结
- 连接四要素:主机
localhost、端口1521、服务名FREEPDB1、用户名/密码 - 用户就是库(schema):没有
USE,访问别人的表写全名scott.emp - 类型三板斧:
VARCHAR2(n CHAR)、NUMBER(p,s)、DATE;自增用IDENTITY - 手动 COMMIT,默认不自动提交
- 分页用
FETCH ... OFFSET,老代码认得 ROWNUM(上界在内,下界在外) - 两大坑:
''即NULL;标识符按大写存储、远离双引号
下一步
到这里你已经是”能用 Oracle 干活”的状态了。想继续深入,按需取用:权限体系(GRANT 细粒度授权)、事务与锁(和 MySQL 的 MVCC 差异)、实例与表空间的存储原理(回看图 1、图 2 就是入口)。