Oracle 里用户和模式一一对应:用户是「能登录的账号」, 模式是「这个账号拥有的对象集合」。建用户就等于建同名模式,不用单独建。 模式是平铺的命名空间,不能嵌套。 所以「换 schema」在 Oracle 里就等于「换用户」——这一点和 MySQL 差别很大, 是迁移时最常踩的坑。
前 11 章都在讲「数据怎么存、怎么查」。从这一章起讲「谁能碰」。 权限是数据库安全的第一道门,也是最容易被配错的一层。 这一章的组织顺序和实际操作顺序一致: 先建用户(12.1、12.2),再授权(12.3),权限多了用角色打包(12.4), 最后用 PROFILE 管住密码和资源(12.5)。
一、用户是什么:一个能登录的账号
CREATE USER scott IDENTIFIED BY tiger;
这一句做两件事:建一个能登录的账号、同时建一个同名模式。
所以「先建模式再建用户」这个顺序是不存在的——
模式不是独立对象,它是「用户拥有的东西」的集合名。
你把用户删了,模式也就没了。
建用户时必须想清楚三件事:
怎么认证(密码/外部/全局)、数据放哪个表空间、给多少配额。
第二三件事在 12.2 展开。
二、模式是什么:一个命名空间
模式(schema)是「对象的命名空间」。
你可以在 scott 模式里建一张 emp,在 hr 模式里也建一张 emp,两张互不干扰。
这就是模式的作用:给对象名字加一层隔离。
访问别人的对象要带前缀:SELECT * FROM hr.emp。
不带前缀时,数据库查的是「我自己模式里的同名对象」。
这一点和「同义词」正好配合——第 10 章讲的名字解析顺序,第一层就是「自己的对象」。
模式不能嵌套。
没有 scott.sub.emp 这种写法——Oracle 的模式是平铺的一层,SCOTT.EMP 已经是最深的层级。
三、和 MySQL 的错位:schema 到底是什么
MySQL 里 schema 和 database 是一回事,
一个实例下可以有多个 database,每个 database 里再放表。
Oracle 里 schema 和 user 是一回事,一个库就是一个「实例 + 一堆用户」,用户下面再放表。
所以「把 MySQL 的表迁到 Oracle」时,第一个问题就是:
原来的 database 对应到 Oracle 的什么?
答案通常是「一个用户」。这就意味着要建用户、给配额、授权——工作量比想象的大。
反过来,「Oracle 迁 MySQL」也一样:
原来靠 schema 隔离的权限,MySQL 里要靠 GRANT ... ON db.* 实现,粒度不一样,得重新设计。
四、删用户:对象跟着走,所以要小心
DROP USER scott;
如果 scott 模式里还有对象,这句会报 ORA-01922,删不掉。
要连对象一起删,得写 DROP USER scott CASCADE;。
CASCADE 这个字有多重:
它删的是「一个人 + 他名下所有表、视图、过程、序列」。
而且不问你一句。
所以生产上极少直接 DROP USER。
常见做法是先 ALTER USER ... ACCOUNT LOCK 锁账户,
观察一两个月(确认没有程序还在用它),再删。
这个习惯能救好几次事故——因为「已经不用的账号」往往是某个凌晨批处理还在悄悄连着的那个。
五、动手 Demo:两个「用户」两个库,同名表互不干扰
沙箱里没有 CREATE USER,但「用户 = 一个独立的对象空间」这件事可以直接用两个库文件复现。
每个库当成一个模式,同名的 emp 表在两边各有一份。
这个模型能说明两件事:
① 同名对象在模式之间互不干扰;② 不带前缀时查的是「自己那份」。
# 用户 = 模式:两个「用户」两个库,同名表互不干扰
import os, sqlite3
d = os.environ.get("TEMP", ".")
scott = sqlite3.connect(os.path.join(d, "scott.db"))
hr = sqlite3.connect(os.path.join(d, "hr.db"))
for db, who in ((scott, "SCOTT"), (hr, "HR")):
db.execute("create table if not exists emp (empno int, ename text)")
db.execute("delete from emp")
db.execute("insert into emp values (1, ?)", (who,))
db.commit()
def query(who, sql):
db = scott if who == "SCOTT" else hr
return db.execute(sql).fetchall()
print("SCOTT 看到的:", query("SCOTT", "select * from emp"))
print("HR 看到的:", query("HR", "select * from emp"))
print("有没有【建模式】这一步?没有——建用户就是建模式。")
scott.close()
hr.close()
实跑输出:
--------------------------------------------------------------------
第五十三课:用户与模式——一个人和一堆东西
--------------------------------------------------------------------
**Oracle 里「用户」和「模式」是两个概念,但一一对应。**
**用户是「能登录的账号」,模式是「这个账号拥有的对象集合」。**
**建一个用户,就自动有了一个同名模式**——不用单独建。
一、建用户,等于同时建了一个模式
--------------------------------------------------------------------
用户名 默认表空间 配额MB 账户状态
---------------------------------
SCOTT USERS 20 OPEN
HR USERS 50 OPEN
已选择 2 行
**注意这里没有「建模式」这一步。** **`CREATE USER scott` 之后,`scott` 这个模式就已经存在了**——
**它是一个空模式,等着你往里建表。**
二、同名表在两个模式下互不干扰
--------------------------------------------------------------------
所有者 对象名 对象类型 完整名
--------------------------------
hr emp TABLE hr.emp
scott emp TABLE scott.emp
已选择 2 行
**两张 `emp`,一张属于 `scott`、一张属于 `hr`,互不影响。**
**这就是模式的作用:给对象名字加了一层隔离。**
**所以你写 `SELECT * FROM emp` 时,数据库查的是「我自己模式里的 `emp`」**——
**要查别人的,得写 `hr.emp`。**
三、模式不是「目录」,是「命名空间」
--------------------------------------------------------------------
**一个常见的误解是「模式像文件夹,可以嵌套」。** **不能。**
**Oracle 的模式是平铺的:`SCOTT.EMP` 就是「SCOTT 模式下的 EMP」,没有更深的层级。**
**schema 名和用户名是同一个词**, **所以「换 schema」在 Oracle 里就等于「换用户」。**
**MySQL 里 schema 和 database 是一回事;Oracle 里 schema 和 user 是一回事。**
**这两个概念在两家产品里错位,是数据库迁移时最常踩的坑之一。**
四、删用户,对象跟着走
--------------------------------------------------------------------
**`DROP USER scott;` 不删对象,会报错**——
**因为模式里还有东西。要连着删,得写 `DROP USER scott CASCADE;`。**
**删之前 2 个对象,删之后 1 个——`scott.emp` 一起没了。**
所有者 对象名
-------------
hr emp
已选择 1 行
**注意「删用户」这个动作有多重:它删的是「一个人 + 他名下所有东西」。**
**所以生产上极少直接 `DROP USER`,一般是先锁账户(`LOCK`),观察一段时间再删。**
第一条输出:SCOTT 查自己那份,看到的是 SCOTT;HR 查自己那份,看到的是 HR。
两张表名字一样,内容不一样,谁也看不见谁。
这就是模式的隔离作用。
没有这层隔离,两个人就不能同时用 emp 这个名字——那所有公司都得先商量好表名怎么起。
最后一句是这一篇的结论:
「建用户就是建模式」,没有单独的「建模式」这一步。
所以「用户」这个词在 Oracle 里有双重含义:账号 + 命名空间。
30 秒实验
- 再建一个「用户」(第三个库文件),在它里面也建一张
emp,看三份互不干扰——这就是模式隔离。 - 用
ATTACH DATABASE把两个库挂到同一个连接上, 这样就能写scott.emp和hr.emp了——这就等价于 Oracle 里带前缀访问别人的表。 - 想一想:如果两个模式里都有
emp,你在scott里写SELECT * FROM emp, 数据库会不会去hr里找?不会。 这就是 10.3 讲的「名字解析顺序第一层」。
常见误区
- 「要先建模式,再建用户」。 Oracle 没有「建模式」这个语法。
CREATE USER同时建了模式和账号。 - 「模式可以嵌套,像文件夹」。 不能。模式是平铺的一层。
SCOTT.EMP已经到底了。 - 「
DROP USER只删账号,对象留着」。 有对象就删不掉,加CASCADE才会连对象一起删, 而且不提示。 - 「schema 就是 database」。 在 MySQL 里是,在 Oracle 里不是。 Oracle 的 schema 对应的是 user,这是迁移时最大的概念错位。
自测三问(点开对答案)
1. 建用户的时候,模式是怎么来的? —— **自动就有了。** `CREATE USER` 同时建账号和同名模式,**没有单独的「建模式」语法。** 2. 两个用户可以各有一张 `emp` 吗? —— **可以。** 模式是命名空间,同名对象在不同模式里互不干扰。**带前缀访问:`hr.emp`。** 3. `DROP USER` 和 `DROP USER ... CASCADE` 差在哪? —— **前者在用户有对象时会报 `ORA-01922` 删不掉;后者连对象一起删。** 4. Oracle 的 schema 和 MySQL 的 schema 有什么不同? —— **Oracle 的 schema 等于 user;MySQL 的 schema 等于 database。** **迁移时 database 一般映射成一个用户。**下一篇讲建用户的具体参数:认证方式、表空间、配额。 其中「配额」是最容易卡住新手的一项——有建表权限但没配额,照样建不了表。
- ☐ (本篇完,下一篇 12.2 创建与管理用户)
相关笔记
- 创建与管理用户
- 同义词对象
- 数据表概述
-
- 🐬 MySQL必知必会/00-索引
- 🏺 Oracle从入门到精通 · 索引