Oracle 学习笔记

第一章:ORACLE 基础知识

一、基础软件的下载安装

这里是 Oracle 基础环境搭建,包括 Oracle 数据库的下载安装,以及 Oracle 客户端的下载安装。如果你使用的是云数据库,那么可以直接跳过这两个软件,直接安装 PL/SQL 即可。 以下是安装步骤及相关链接:

# 如果需要安装最新 Oracle,那么步骤如下


# 一、下载 Oracle 数据库
https://www.oracle.com/database/technologies/oracle19c-windows-downloads.html

# 二、下载 Oracle 数据库客户端
https://www.oracle.com/hk/database/technologies/instant-client/winx64-64-downloads.html

# 三、下载 PL/SQL 软件
https://www.allroundautomations.com/files/plsqldev1406x64.msi

# 四、安装 PL/SQL 软件
一直点击下一步即可 ==> 安装时建议更改安装目录,建议不要安装在 C 盘

# 五、PL/SQL 注册激活
product code  ==>  ke4tv8t5jtxz493kl8s2nn3t6xgngcmgf3
serial Number ==>  264452
password      ==>  xs374ca


# 注册码来源
https://www.luoxiao123.cn/plsql14.html

# 如果注册码不能使用,参考下面链接。如果链接失效,搜索关键字 ==> plsql14安装
https://blog.csdn.net/weixin_44903881/article/details/118680034

# Oracle 数据库安装参考链接【该部分已录制相应的视频,可供以后参考】
https://www.modb.pro/db/38320     # 该篇文章中的踩坑记录我都中了,也都根据教程解决了


# 注意
下载 Oracle 软件需要登录网站,账号是 guoshizhan.club@gmail.com,密码是【通用混合密码】

二、PL/SQL 的基本操作

-- 用户
在 oracle 中,用户才是管理表的基本单位。例如:test 用户下有 10 张表
在 MySQL 中,数据库才是管理表的基本单位。例如:test 数据库下有 10 张表


-- 表空间
具体参考文档,文档很详细 ==> http://guoshizhan.site:8888/documents/Oracle/

文档地址: http://guoshizhan.site:8888/documents/Oracle/

-- 创建表空间
-- 以下 SQL 表示创建了 game 表空间,存储到 d 盘的 game.dbf 文件,大小是 100M
-- autoextend 表示自动扩展,next 表示每次扩展 10M
create tablespace game 
datafile 'd:\game.dbf' 
size 100m
autoextend on 
next 10m;


-- 删除表空间
drop tablespace game;


-- 创建用户
create user Tom identified by root default tablespace game;


-- 给用户授权。给 Tom 授予 dba 角色
grant dba to Tom;

-- Oracle 数据库中常用角色如下:
connect   ==>  连接角色,基本角色
resource  ==>  开发者角色
dba       ==>  超级管理员角色

三、Oracle 的数据类型

数据类型描述
VARCHAR,VARCHAR2表示一个字符串
NUMBERNUMBER(n)表示一个整数,长度是n
NUMBER(m,n):表示一个小数,总长度是m,小数是n,整数是m-n
DATA表示日期类型
CLOB大对象,表示大文本数据类型,可存4G
BLOB大对象,表示二进制数据,可存4G

四、创建表结构

-- 创建一个 person 表
create table person(
    pid NUMBER(20),
    pname VARCHAR2(10)
);


-- 修改表结构
alter table person add gender number(1);  -- 添加一列
alter table person add (phone number(11), email varchar2(64));  -- 添加多列
alter table person modify gender char(1);  -- 修改列类型
alter table person rename column gender to sex;  -- 修改列名称
alter table person drop column sex;  -- 删除一列

五、增删改操作

-- 添加记录
insert into person(pid, pname) values (1, '小明');
commit;  -- 记得提交事务,否则会发生回滚。Oracle 默认需要手动提交数据


-- 查询记录
select * from person;


-- 更新记录
update person set pname = '小红' where pid = 1;
commit;


-- 三个删除
delete from person;         -- 删除表中全部记录
drop table person;          -- 删除表
truncate table person;      -- 先删除表,然后创建表。适用于数据量大的表,尤其是带索引的表

六、序列知识

-- 创建序列 ==> 默认从 1 开始依次递增,主要用来给主键赋值
create sequence s_person;


-- 查看序列 ==> dual 是虚表,只是为了补全语法,没有任何意义
-- 在 Oracle 数据库中,查询语句必须要有 from 关键字,因而就有了虚表
select s_person.nextval from dual;
select s_person.currval from dual;


-- 使用序列插入数据
insert into person(pid, pname) values (s_person.nextval, '小明');
commit;

第二章:scott 用户基本使用

一、解锁 scott 用户

-- scott 用户,密码默认是 tiger
-- 安装完 Oracle 软件之后,默认是没有解锁 scott 用户,所以需要先解锁
-- 使用管理员账户进行 scott 账户解锁
alter user scott account unlock;


-- 解锁 scott 用户的密码【该语句也可以用来进行密码重置操作】
alter user scott identified by tiger;


-- 切换到 scott 用户
sesson ==> log off ==> all
log on ==> scott ==> tiger

二、单行函数

# 单行函数和多行函数


单行函数 ==> 作用于一行,返回一个值
多行函数 ==> 作用于多行,返回一个值

1、字符函数和数值函数

-- 此时是在操作 scott 用户下的表

-- 字符函数 ==> upper() 和 lower()
select upper('yes') from dual;        -- 将字符转换成大写
select lower('YES') from dual;        -- 将字符转换成小写


-- 数值函数 ==> round() 函数,用于四舍五入,后边的参数表示保留的位数
select round(12.34, 1) from dual;     -- 结果是:12.3
select round(12.34, 0) from dual;     -- 结果是:12
select round(12.34, -1) from dual;    -- 结果是:10
select round(12.34, -2) from dual;    -- 结果是:0


-- 数值函数 ==> trunc() 函数,用于直接截取指定位数,不四舍五入,后边的参数表示保留的位数
select trunc(12.34, 1) from dual;     -- 结果是:12.3
select trunc(12.34, 0) from dual;     -- 结果是:12
select trunc(12.34, -1) from dual;    -- 结果是:10


-- 数值函数 ==> mod() 函数,用于求余
select mod(10, 3) from dual;          -- 求 10%3 的余数

2、日期函数

-- 查询出 emp 表中所有员工入职距离现在几天 ==> sysdate-e.hiredate 的单位 ==> 天
select sysdate - e.hiredate from emp e;


-- 算出明天此刻
select sysdate + 1 from dual;         -- 结果是:2021/4/21 18:39:07


-- 查询出 emp 表中所有员工入职到现在距离多少个月
select months_between(sysdate, e.hiredate) from emp e;


-- 查询出 emp 表中所有员工入职到现在距离多少个年
select months_between(sysdate, e.hiredate) / 12 from emp e;


-- 查询出 emp 表中所有员工入职距离现在多少周
select (sysdate - e.hiredate) / 7 from emp e;

3、转换函数

-- 日期转字符串 ==> 将当前时间日期转换成指定格式
-- 加 fm 去除 0;加 24 是变成 24 小时制
select to_char(sysdate, 'yyyy-mm-dd hh:mi:ss') from dual;          -- 结果是:2021-04-20 06:47:02
select to_char(sysdate, 'fm yyyy-mm-dd hh:mi:ss') from dual;       -- 结果是:2021-4-20 6:47:9
select to_char(sysdate, 'fm yyyy-mm-dd hh24:mi:ss') from dual;     -- 结果是:2021-04-20 18:48:11


-- 字符串转日期 ==> 将字符串转化成指定格式的日期 ==> 以下 SQL 结果是:2021-04-20 18:48:11
select to_date('2021-4-20 6:47:9', 'yyyy-mm-dd hh24:mi:ss') from dual;


-- 通用函数 nvl() 函数 ==> 举例:算出 emp 表中所有员工的年薪
select e.sal * 12 from emp e;


-- 员工还有奖金,也是钱,也应该算上
select e.sal * 12 + e.comm from emp e;          -- 结果发现,有些员工的值为空,没钱了,这是为什么


-- 原因是 comm 字段中,有些人的这个字段为 null 值,所以结果出错
select e.sal * 12 + nvl(e.comm, 0) from emp e;  -- nvl 函数表示如果 comm 有值,就使用其值,没有就用 0 代替

三、条件表达式

/*
 * Oracle 和 MySQL 通用的条件表达式
 */
-- 给 emp 表中员工起中文名
select e.ename from emp e;
select e.ename,
    case e.ename
        when 'SMITH' then '曹操'
            when 'ALLEN' then '典韦'
                else '妲己'
                    end
from emp e;



-- 判断 emp 表中的员工工资,如果高于 3000 显示高收入
-- 如果高于 1500 低于 3000 显示中等收入,如果低于 1500 则显示低收入
select e.sal,
    case
        when e.sal > 3000 then '高收入'
            when e.sal > 1500 then '中等收入'
                else '低收入'
                    end
from emp e;
-- 注意:在 Oracle 中,除了起别名之外使用双引号(当然也可以不用),其他情况都使用单引号
-- Oralce 专用条件表达式
select e.ename,
    decode(e.ename ,
        'SMITH' , '曹操' ,
            'ALLEN' , '典韦' ,
                '妲己') 中文名
from emp e;

四、多行函数

-- 多行函数即聚合函数,作用于多行,返回一个值


select count(1) from emp;         -- 和 count(id) 或 count(*) 一样。1 代表第一个字段或 id 主键列
select count(empno) from emp;     -- count(empno),通过主键 id 查询记录总数

select sum(sal) from emp;         -- 工资总和
select min(sal) from emp;         -- 最低工资
select max(sal) from emp;         -- 最高工资
select avg(sal) from emp;         -- 平均工资

第三章:多表查询

一、分组查询

-- 分组查询:查询出每个部门的平均工资
-- 分组查询中,出现在 group by 后面的原始列,才能出现在 select 后面
-- 没有出现在 group by 后面的列,想在 select 后面, 必须加上聚合函数
-- 聚合函数有一个特性,可以把多行记录变成一个值
select e.deptno, avg(e.sal) from emp e group by e.deptno;


-- 查询出平均工资高于 2000 的部门信息
select e.deptno, avg(e.sal) from emp e group by e.deptno having avg(e.sal) > 2000;


-- 所有条件都不能使用别名来判断。例如下面 SQL 语句中的 esal 别名,执行该 SQL 会报错
select e.deptno, avg(e.sal) esal from emp e group by e.deptno having esal > 2000;
select ename, sal esal from emp where esal > 2000;


-- 查询出每个部门工资高于800的员工的平均工资
select e.deptno, avg(e.sal) esal from emp e where e.sal > 800 group by e.deptno;


-- where 和 having 的区别
-- where 是过滤分组前的数据,表现形式是 where 必须在 group by 之前
-- having 是过滤分组后的数据,表现形式是 having 必须在 group by 之后


-- 查询出每个部门工资高于 800 的员工的平均工资,然后再查询出平均工资高于 2000 的部门
select e.deptno, avg(e.sal) esal 
from emp e 
where e.sal > 800 group by e.deptno having avg(e.sal) > 2000;

二、多表查询相关概念

-- 笛卡尔积:两张表数据总数的乘积 ==> emp 表有 14 条记录,dept 表有 4 条记录
select * from emp e, dept d;   -- 结果有 56 条记录【包含了很多无用的数据】


-- 解决笛卡尔积的第一种方式 ==> 等值连接
select * from emp e, dept d where e.deptno=d.deptno;           -- 结果是 14 条记录


-- 解决笛卡儿积的第二种方式 ==> 内连接
select * from emp e inner join dept d on e.deptno=d.deptno;    -- 结果是 14 条记录


-- 查询出所有部门,以及部门下的员工信息【外连接】
select * from emp e right join dept d on e.deptno=d.deptno;    -- right 表示查询右表的所有信息


-- 查询出所有员工信息以及员工所属部门【外连接】
select * from emp e left join dept d  on e.deptno=d.deptno;    -- left 表示查询所有左表的信息


-- Oracle 中专用外连接,其表示形式是 ==> (+)
select * from emp e, dept d where e.deptno(+)=d.deptno;        -- 相当于上述的右外连接,结果是 15 条记录
select * from emp e, dept d where e.deptno=d.deptno(+);        -- 相当于上述的左外连接,结果是 14 条记录

三、自连接概念

-- 查询出员工姓名,员工领导姓名【自连接:e1 是员工表,e2 是领导表】
select e1.ename, e2.ename from emp e1, emp e2 where e1.mgr=e2.empno;


-- 查询出员工姓名,员工部门名称,员工领导姓名,员工领导部门名称
select e1.ename, d1.dname, d2.dname, e2.ename 
from emp e1, emp e2, dept d1, dept d2
where e1.mgr=e2.empno and e1.deptno=d1.deptno and e2.deptno=d2.deptno;

四、子查询

-- 子查询返回一个值 ==> 举例:查询出工资和 SCOTT 用户一样的员工信息
select * from emp
where sal in 
(select sal from emp where ename='SCOTT');



-- 子查询返回一个集合 ==> 举例:查询出工资和 10 号部门任意员工一样的员工信息
select * from emp
where sal in 
(select sal from emp where deptno=10);



-- 子查询返回一张表。举例:查询出工资和 SCOTT 用户一样的员工信息
-- 查询出每个部门最低工资,和最低员工姓名,和该员工所在部门名称
-- 1、先查出每个部门的最低工资
select deptno,min(sal) msal 
from emp 
group by deptno;

-- 2、三表联合查询
select t.deptno, t.msal, e.ename, d.dname 
from (select deptno, min(sal) msal 
      from emp 
      group by deptno) t, emp e, dept d 
where t.deptno=e.deptno and t.msal=e.sal and e.deptno=d.deptno;

五、分页查询

-- Oracle 中的分页查询
-- rownum 行号:当进行一次查询操作时,每查询出一行记录,就会在该行上加上一个行号
-- 行号从 1 开始,一次递增,不能跳着走
-- emp 表根据工资倒序排列后,每页五条记录,查询第二页【排序操作会影响 rownum 的顺序】
select rownum, e.* from emp e order by e.sal desc;


-- 如果涉及到排序且需要使用到 rownum 的话,那么我们可以进行嵌套查询
select rownum, t.* from (select rownum, e.* from emp e order by e.sal desc) t;


-- emp 表根据工资倒序排列后,每页五条记录,查询第二页【最终 SQL 语句】
select * from (
    select rownum rn, tt.* from (
        select * from emp order by sal desc
    ) tt where rownum < 11
) where rn > 5;

-- 注意:分页查询的这个格式是固定的,记住就行了!(11 和 5 是外面传入的参数,不能写死)

第四章:Oracle 高级

一、视图的概念及使用

-- 视图的概念 ==> 视图就是提供一个查询的窗口,所有数据来自于原表
-- 创建视图【必须要有 dba 权限】


-- 1、跨用户复制一张表
create table emp as select * from scott.emp;

-- 2、创建 v_emp 视图
create view v_emp as select ename,job from emp;

-- 3、查询视图
select * from v_emp;

-- 4、修改视图,改的并不是视图,而是原表数据【不推荐对视图进行修改】
update v_emp set job='Java' where ename='ALLEN';
commit;

-- 5、创建只读视图
create view v_emp_read as select ename,job from emp with read only;


-- 视图的作用
-- 1、视图和屏蔽掉一些敏感的字段
-- 2、视图可以保证总部和分部的数据及时统一

二、索引的概念及使用

-- 索引的概念 ==> 索引就是在表的列上构建一个二叉树,达到提高查询效率的目的,但索引会影响增删改的效率

-- 单列索引 ==> 创建单列索引
create index idx_ename on emp(ename);

-- 单列索引触发规则:条件必须是索引列中的原始值,且单行函数和模糊查询都会影响索引的触发
select * from emp where ename='scott';

-- 复合索引 ==> 创建复合索引
create index idx_ename_job on emp(ename,job);

-- 复合索引中第一列为优先检索列,如果要触发复合索引,必须包含有优先检索列中的原始值
select * from emp where ename='scott' and job='Java';         -- 触发复合索引
select * from emp where ename='scott' or job='Java';          -- 不触发索引
select * from emp where ename='scott';                        -- 触发单列索引

三、Oracle 编程

1、变量定义

-- PL/SQL 编程语言是对 SQL 语言的扩展,使得 SQL 语言具有过程化编程的特性
-- PL/SQL 编程语言比一般的过程化编程语言更加灵活
-- PL/SQL 编程语言主要用来编写存储过程和存储函数等


-- 声明方法 =====> := 表示赋值操作,into 也可以表示赋值操作
declare
    i number(2) := 10;
    s varchar2(10) := '小明';
    temp emp.ename%type;         -- 引用型变量,获取 emp 表 ename 变量的类型,然后赋值给 temp 变量
    emprow emp%rowtype;          -- 记录型变量,用于接受一行的值
begin
    dbms_output.put_line(i);
    dbms_output.put_line(s);
    select ename into temp from emp where empno=7788;
    dbms_output.put_line(temp);
    select * into emprow from emp where empno=7788;
    dbms_output.put_line(emprow.ename || '的工作是:' || emprow.job);
end;

2、if 判断

-- PL/SQL 中的 if 判断
-- 输入小于 18 的数字,输出未成年
-- 输入大于 18 小于 40 的数字,输出中年人
-- 输入大于 40 的数字,输出老年人


declare
  i number(3) := &ii;    -- 把 ii 的输入值赋值给 i,ii也可以被替换成 i 或者其他变量名
begin
  if i < 18 then
    dbms_output.put_line('未成年');
  elsif i < 40 then
    dbms_output.put_line('中成年');
  else
    dbms_output.put_line('老成年');
  end if;
end;

3、循环语句

-- PL/SQL 中的循环语句

-- while 循环
declare
  i number(2) := 1;
begin
  while i < 11 loop
    dbms_output.put_line(i);
    i := i + 1;
  end loop;
end;
-- 退出循环,用的比较多
declare
  i number(2) := 1;
begin
  loop
    exit when i > 10;
    dbms_output.put_line(i);
    i := i + 1;
  end loop;
end;
-- for 循环
declare
begin
  for i in 1..10 loop
    dbms_output.put_line(i);
  end loop;
end;

4、游标的使用

-- 游标:可以存放多个对象,多行记录
-- 输出 emp 表中所有员工的姓名
declare
  cursor c1 is select * from emp;          -- 定义游标 c1
  emprow emp%rowtype;
begin
  open c1;
    loop
      fetch c1 into emprow;
      exit when c1%notfound;
      dbms_output.put_line(emprow.ename);  -- 循环输出所有员工的姓名
    end loop;
  close c1;
end;
-- 给指定部门员工涨工资
select sal from emp where deptno=10;    -- 先查询一下员工工资

declare
  cursor c2(eno emp.deptno%type) is select empno from emp where deptno=eno;
  en emp.empno%type;
begin
  open c2(10);  -- 打开游标的时候进行赋值操作
    loop
      fetch c2 into en;
      exit when c2%notfound;
      update emp set sal = sal + 1000 where empno=en;  -- 涨 1000 工资
      commit;
    end loop;
  close c2;
end;

select sal from emp where deptno=10;    -- 再次查询一下员工工资

第五章:存储过程和存储函数

一、存储过程

-- 存储过程:存储过程就是提前编译好的一段 PL/SQL 代码,放置在数据库端
-- 这段代码可以直接被调用。注意:这段代码一般都是固定步骤的业务

-- 定义一个存储过程 p1,给指定员工涨 1000 元
create or replace procedure p1(eno emp.empno%type) is
begin
  update emp set sal = sal + 1000 where empno=eno;
  commit;
end;



-- 测试 p1 存储过程是否起作用
select sal from emp where empno=7788;
declare
begin
  p1(7788);  -- 调用存储过程
end;
select sal from emp where empno=7788;

二、存储函数

-- 通过存储函数实现计算指定员工的年薪
-- 存储过程和存储函数的参数都不能带长度
-- 存储函数的返回值类型不能带长度
create or replace function f_yearsal(eno emp.empno%type) return number 
is
  s number(10);
begin
  select sal * 12 + nvl(comm, 0) into s from emp where empno=eno;
  return s;
end;



-- 测试存储函数 f_yearsal
declare
  res number(10);
begin
  res := f_yearsal(7788);
  dbms_output.put_line(res);
end;

三、out 类型参数的使用

-- out 类型参数使用案例 ==> 通过存储过程来计算年薪
create or replace procedure p_yearsal(eno emp.empno%type, yearsal out number) 
is 
  s number(10);         -- 存放年薪
  c emp.comm%type;      -- 存放奖金
begin
  select sal * 12, nvl(comm, 0) into s, c from emp where empno=eno;
  yearsal := s + c;
end;



-- 测试 p_yearsal 存储过程
declare
  yearsal number(10);
begin
  p_yearsal(7788, yearsal);    -- 调用存储过程
  dbms_output.put_line(yearsal);
end;



-- in 和 out 参数类型的区别是什么?
-- 凡是涉及到 into 查询语句赋值或者 := 赋值操作的参数,都必须使用 out 来修饰,其余的都用 in 来修饰或者不写

四、两者区别

-- 存储过程和存储函数的区别

-- 1、语法区别:关键字不一样。存储函数比存储过程多了两个 return
-- 2、本质区别:存储函数有返回值,而存储过程没有返回值
----- 如果存储过程想实现有返回值的业务,我们就必须使用 out 类型的参数
----- 即便是存储过程使用了 out 类型的参数,其本质也不是真正的有了返回值
----- 而是在存储过程内部给 out 类型参数赋值,在执行完毕后,我们直接拿到输出类型参数的值

-- 我们可以使用存储函数有返回值的特性来自定义函数,而存储过程不能用来自定义函数


-- 案例需求 ==> 查询出员工姓名、员工所在部门名称
-- 准备工作 ==> 把 scott 用户下的 dept 表复制到当前用户下
create table dept as select * from scott.dept;
select e.ename, d.dname from emp e,dept d where e.deptno=d.deptno;


-- 使用存储函数来实现提供一个部门编号,输出一个部门名称
create or replace function f_dname(dno dept.deptno%type) return dept.dname%type 
is
  dna dept.dname%type;
begin
  select dname into dna from dept where deptno=dno;
  return dna;
end;


-- 使用 f_dname 存储函数来实现上述的案例需求
select e.ename, f_dname(e.deptno) from emp e;

五、触发器

1、概念和分类

# 触发器概念
触发器就是制定一个规则,在我们做增删改时,只有满足该规则,就能够自动触发,无需调用


# 触发器分类
语句级触发器和行级触发器。包含 for each row 的就是行级触发器,不包含的就是语句级触发器
加 for each row 是为了使用 :old 或者 :new 对象或者一行记录
触发语句:old:new
Insert所有字段都是空(null)将要插入的数据
Update更新之前该行的值更新之后的数据
Delete删除之前该行的值所有字段都是空(null)

2、触发器案例

-- 语句级触发器案例 ==> 插入一条记录,输出一个新部门
create or replace trigger t1 
after 
insert 
on dept 
declare 

begin
  dbms_output.put_line('一个新部门成立');
end;


-- 插入一个部门
insert into dept values (50, 'DIY', 'MEXICO');   -- 此时可以在 Output 输出位看到输出信息
commit;
-- 行级触发器案例 ==> 不能给员工降薪
-- raise_application_error(只能在 -20999~-20001 之间, '错误提示信息!');
create or replace trigger t2 
before 
update 
on emp 
for each row 
declare 

begin
  if :old.sal > :new.sal then 
    raise_application_error(-20001, '不能给员工降薪!');  -- 第一个参数是有范围的:-20999~-20001
  end if;
end;


-- 执行一下两行语句会有弹窗特效
update emp set sal = sal - 100 where empno=7788;
commit;
-- 使用触发器实现主键自增【行级触发器】
-- 分析 ==> 在部门进行插入操作之前,拿到即将插入的数据,然后给该数据的主键列赋值
create or replace trigger t3 
before 
insert 
on person 
for each row 
declare 

begin
  -- s_person 来自于原先创建的序列
  select s_person.nextval into :new.pid from dual;
end;


-- 使用 t3 触发器实现主键自增
insert into person(pname) values ('Lion');
commit;

3、Java 调用存储过程

# 版本与 jar 包对应关系


oracle10g ==> ojdbc14.jar
oracle11g ==> ojdbc6.jar

第一步:创建 Maven 工程并导入 pom 依赖。依赖如下:

<dependencies>
    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc14</artifactId>
        <version>10.2.0.4.0</version>
        <!-- runtime 表示运行的时候才用,编译的时候不用 -->
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
    </dependency>
</dependencies>

第二步:编写测试类,测试能否正确连接到 Oracle 数据库。代码如下:

import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * @author: guoshizhan
 * @create: 2021-05-07 19:46
 * @description: 连接 Oracle 数据库测试
 */
public class OracleTest {

    @Test
    public void testOracle() throws Exception {
        // 1、加载数据库驱动
        Class.forName("oracle.jdbc.driver.OracleDriver");
        // 2、获取 Connection 连接
        Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
        // 3、得到预编译的对象
        PreparedStatement pstm = connection.prepareStatement("select * from emp where empno=?");
        // 4、给参数赋值
        pstm.setObject(1, 7788);
        // 5、执行数据库查询操作
        ResultSet rs = pstm.executeQuery();
        // 6、输出结果
        while (rs.next()) {
            System.out.println(rs.getString("ename"));
        }
        // 7、释放资源
        rs.close();
        pstm.close();
        connection.close();
    }

}

第三步:编写调用存储过程的方法。代码如下:

import oracle.jdbc.OracleTypes;
import org.junit.Test;

import java.sql.*;

/**
 * @author: guoshizhan
 * @create: 2021-05-07 19:46
 * @description: 连接 Oracle 数据库测试
 */
public class OracleTest {

    @Test
    public void testCallProcedure() throws Exception {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
        
        // 调用 p_yearsal 存储过程
        CallableStatement pstm = connection.prepareCall("{call p_yearsal(?,?)}");

        pstm.setObject(1, 7788);
        pstm.registerOutParameter(2, OracleTypes.NUMBER);
        pstm.execute();                         // 直接执行代码即可,不需要返回值
        System.out.println(pstm.getObject(2));  // 输出结果

        pstm.close();
        connection.close();
    }

}

第四步:编写调用存储函数的方法。代码如下:

import oracle.jdbc.OracleTypes;
import org.junit.Test;

import java.sql.*;

/**
 * @author: guoshizhan
 * @create: 2021-05-07 19:46
 * @description: 连接 Oracle 数据库测试
 */
public class OracleTest {

    @Test
    public void testCallFunction() throws Exception {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
        
        // 调用 p_yearsal 存储函数
        CallableStatement pstm = connection.prepareCall("{?= call f_yearsal(?)}");

        pstm.setObject(2, 7788);
        pstm.registerOutParameter(1, OracleTypes.NUMBER);
        pstm.execute();                         // 直接执行代码即可,不需要返回值
        System.out.println(pstm.getObject(1));  // 输出结果,注意:第一个参数才是结果,即第一个问号

        pstm.close();
        connection.close();
    }

}

第六章:Bug 问题解决

一、中文乱码问题

-- Oracle 查询时中文乱码问题解决方案


select userenv('language') from dual;          -- 查询当前使用编码
select * from V$NLS_PARAMETERS                 -- 查询系统所有编码


cmd ==> sysdm.cpl ==> 新建系统环境变量 ==> NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK 即可


最新的 PL/SQL14 也可以这样使用,需要在 客户端所在的操作系统进行配置,而不是服务端
说人话就是,在安装了 PL/SQL14 的操作系统上进行环境变量配置,配置好了重启 PL/SQL 即可解决中文乱码问题
注意 ==> 虽然在 PL/SQL14 中查不到 SIMPLIFIED CHINESE_CHINA.ZHS16GBK 这个编码,但是可以配置

二、PL/SQL 软件注册码

早期的 PL/SQL 软件注册码

Product Code4t46t6vydkvsxekkvf3fjnpzy5wbuhphqz
serial Number601769
passwordxs374ca

最新 PL/SQL14 的软件注册码

Product Codeke4tv8t5jtxz493kl8s2nn3t6xgngcmgf3
serial Number264452
passwordxs374ca
  • 文章作者:root
  • 创建时间:2021-04-20 14:28:00
  • 更新时间:2022-01-21 15:01:28
  • 版权声明:本文为博主原创文章,未经博主允许不得转载!
请 在 评 论 区 留 言 哦 ~~~
1024