ORACLE完整笔记及JAVA习题

更新时间:2024-01-21 08:38:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

29.

30.能从循环语句中跳出的是(ACD) A.return B.for C.break D.continue

31.下列那两个语句能够创建一个inputstream输入流并且打开文件file.txt准备读取(B) A.FileInputStream in = new FileReader(new File(”File.txt”)); B. FileInputStream in = new FileInputStream(new File(”File.txt”)); C. InputStream in = new FileReader(”File.txt”); D. InputStream in = new FileInputStream(”File.txt”);

E. InputStream in = new InputStreamFileReader(”File.txt”,”read”);

32.下列哪些方法可以定义新线程类(AB) A.继承thread类。 B.实现runnable接口。

C.在类中添加一个run()方法。 D.创建一个thread实例。 (线程部分创建的内容)

33.想要构造arraylist的一个实例,这个类继承了list接口,一下正确的是(C) A. List mylist = new List();

B. ArrayList mylist = new Object(); C. List mylist = new ArrayList();

D. ArrayList mylist = new ArrayList();

(D和C都是可以的,但是D一般不用,因为,用父类List可以方便代码复用,团队开发,和转化为组件)

34.下列关键字可以修饰构造函数的是(ABCD) A.protected B .public C. private D. default

(特征修饰符应该都不行:static,final,abstract,synchronize等) 35.关于集合描述错误的是(BCD)

A.Map是独立接口,没有继承collection接口,queue继承map接口。 B.没有collection这一个接口。

C.list,set,queue,map都继承自collection接口

D.list,set,queue,map都是独立接口,没有继承其他接口。 E.list,set,queue继承自collection接口。

ORACLE部分

开篇

MVC结构 进行下一步操作 用户 1(等待用户输入)

人机交互界面(浏览器)人机交互界面(浏览器)

2(根据用户输入 选择不同控制器)

6(根据返回结果选择不同的视图) Controller 5(返回数据给控制器) 控制器

3(将用户输入的数据 进行简单处理后 传递给模型层) Model 模型 4(进行业务逻辑判断

之后调用数 据存取方法)

ORACLE-SQL开发

DB 数据库 用户 View 视图 查询:单表查询;多表查询;单行函数与分组函数;

子查询;层次查询;集合运算。 数据操作:增删改 事务控制:

对象管理:表,约束,视图,引用,序列,同义词。

权限控制:用户,权限,角色

数据:能输入到计算机中并能被计算机处理的符号的总称。

数据处理的几个阶段:人工阶段,文件系统阶段,数据库系统阶段。 数据库特点:小数据冗余,独立于应用程序,可分享。 数据管理系统(DBMS):管理数据库的软件。

ORACLE数据库文件:数据文件,控制文件和重做日志文件。 数据模型的三个层次:概念模型(ER图),逻辑模型(层次模型,关系模型,网状模型),物理模型。

关系模型的组成:关系数据结构、关系操作集合、关系完整性约束。

(关系操作:连接,投影,选择,增加等)(约束:实体完整性约束,参照完整性约束,用户自定义完整性约束)

ORACLE一个数据库可以拥有多个用户,每一个用户有多个数据库对象。

Sys用户:权限最高,存放左右数据字典的表和视图。

Oracle用户System用户:普通dba权限,用户拥有次一级内部数据。 Scott用户:示范用户

Sys用户解锁Scott用户sql命令:alter user scott account unlock; 连接sql语句:connectScott/tiger;(用户名/密码)。 Conn sys/neuedu as sysdba;(sys用户登录) Sql语句 ==结构化查询语言。

第一章:编写简单的查询语句。

结构化查询语言sql(structural query language):是查询关系型数据库的标准语言。 DQL(SELECT)。 DML(insert,delete, update 修改行)。 结构化查询语言分为5类 TPL (commit,rollback 提交回滚)。 DCL (grant,revoke权限分配)。 DDL (create,drop,alter 对象操作)。

Select的语句涉及的关系包括:选择(行),投影(列),连接(表之间)。 调整sql-developer书写显示tools->preferance->edit->keywords,comment。 练习1:

1.用两种方式查询所有员工信息?2.同下 Select * from emp

Select emp ,empno,job,mgr,hiredate,sal,comm,deptno from emp.

算数运算符可以用在查询语句中。 练习2:

1. 员工转正之后月薪上调20%。查询转正之后的月薪。

Select ename,sal,sal+sal*0.2 from emp

2. 员工试用期6个月,转正之后月薪上调20%,查询所有员工第一年的所得 Select ename,sal*6+sal*1.2*6from emp

Sql中的空值(NULL)的处理,空值参与算术运算结果是空

列别名两种方式:列明列别名或者列名 as列别名,如果列别名中含有空格,必须用双引号引起来!并且加了双引号才可以改变大小写!例子“Annual Salary”就显示为 Annual Salary。 练习3:

员工试用期6个月,转正之后月薪上调20%,查询所有员工姓名,工资收入,奖金,总收入。 Select ename,sal*6+sal*1.2*6 工资收入,comm奖金,sal*6+sal*1.2*6+comm 总收入 from emp

(列别名可以有汉字)

连接运算符可以把两个列的值连接在一起 Select ename||job from emp 显示的是smithclerk的样式 Sql语句中的原义字符串就是原样显示的字句。 消除重复行用DISTINCT关键字。 员工试用期6个月,转正之后月薪上调20%,查询所有员工第一年总收入,要求显示的格式为:***的第一年总收入为***? SELECT ename || '的第一年的总收入是' || (sal*6+sal*1.2*6 )AS 员工总收入FROM emp 显示公司有哪几种岗位? Select distinct deptno from emp 课后作业:

4.在dept表中查询deptno和job两列,并加上distinct做实验? Select distinct deptno,job from emp

Distinct本身是消除重复行,当两列在一起的时候,会消除两个字段都重复的数据。

第二章:限制数据和排序数据。

Oracle的sql语句中等于是“=”,不等于是“<>”。

Sql语句中的字符型数据是区分大小写的,不区分大小写的是表明列名,关键字!如‘clerk‘和CLERK’

比较日期:中文系统默认的oracle日期格式为DD-MON-RR写成’01-1月-90’。 练习1

1. 查询职位为SALESMAN的员工编号,职位,入职日期

SELECT ename,job,hiredate FROM emp WHERE job='SALESMAN' 2.查询1985年12月31日之前入职的员工姓名及入职日期? SELECT ename,hiredate FROM emp WHERE hiredate < '31-12月-85' 2. 查询部门编号不在10部门的员工姓名,部门编号?

SELECT ename,deptno FROM emp WHERE deptno <> 10 特殊比较运算符:

BETWEEN…AND…(闭区间范围内部[1000,5000]!这个还可以用于日期型数据!) IN (是否与集合中任意一个相等)

LIKE (部分匹配,通配符:%代表多个字符,_代表一个字符) IS NULL (是否为空值,)

通配符的原义输出方法:

在“_”和“%”的前面加上一个’@’,然后后面用ESCAPE ‘@’就可以了。

例如:SELECT ename FROM emp WHERE ename LIKE'%@_W'ESCAPE ‘@’,名字里面含有_。

练习2

1. 查询入职日期在82到85年的员工姓名,入职日期?

SELECT ename,hiredate FROM emp WHERE hiredate BETWEEN '01-1月-82' AND '31-12月-85'

2. 查询月薪在3000到5000 的员工姓名,月薪

SELECT ename,sal FROM emp WHERE sal BETWEEN 3000AND5000

3. 查询部门号为10或者20 的员工姓名与部门编号? SELECT ename,deptno FROM emp WHERE deptno IN (10,20) 4.查询经理编号为7902,7566,7788的员工姓名,经理编号

SELECT ename ,mgr FROM emp WHERE mgr IN(7902,7788,7566) 5.查询员工姓名以W开头的员工姓名

SELECT ename FROM emp WHERE ename LIKE'W%' 6.查询员工姓名倒数第二个字符为T的员工姓名 SELECT ename FROM emp WHERE ename LIKE'%T_' 7.查询奖金为空的员工姓名和奖金。

SELECT ename,comm FROM emp WHERE comm ISNULL

逻辑运算符: AND逻辑与

OR逻辑或 NOT逻辑非 练习3,

1.查询工资超过2000并且职位是MANAGER,或者职位是SALSMAN的员工的姓名,职位,工资

SELECT ename ,job,sal FROM emp

WHERE sal>2000AND job ='MANAGER'OR job ='SALESMAN'

2.查询工资超过2000并且职位是MANAGER或SALESMAN的员工姓名,部门,工资 SELECT ename ,job,sal FROM emp

WHERE sal>2000AND(job ='MANAGER'OR job ='SALESMAN')

3.查询部门在10或20,并且工资在3000和5000之间的员工姓名,部门,工资 SELECT ename ,deptno,sal FROM emp

WHERE deptno IN(10,20)AND(sal BETWEEN3000AND5000)

4.查询入职日期在81年,并且职位不是SALES大头的员工姓名,入职日期,部门编号。 SELECT ename ,hiredate,job FROM emp

WHERE hiredate BETWEEN'01-1月-81'AND'12-12月-81'AND job NOTLIKE'SALES%' 5.查询职位为SALESMAN或者MANAGER,部门编号为10或20,姓名包括A的员工的姓名,职位,部门编号。

SELECT ename ,deptno,job FROM emp WHERE deptno IN(10,20)

AND(job IN('SALESMAN','MANAGER'))AND ename LIKE'%A%'

ORDER BY排序子句:必须写在SELECT语句的最后!可以按找列别名排序 ASC升序,DESC降序

注意空值(NULL)在升序中排在最后的,在降序中排在最前面。 练习4.

1.查询部门在20 或30 的员工姓名,部门编号,并按照工资升序排列 SELECT ename,deptno FROM emp ORDERBY sal ASC

2.查询工资在2000-3000之间,部门不再10号的员工姓名,部门编号,工资,并按照部门的升序排列。 SELECT ename,deptno,sal FROM emp WHERE sal BETWEEN2000AND3000AND deptno <>10ORDERBY

deptno ASC,sal DESC

3.查询入职日期在82年和83年之间,职位以SALES或者MAN开头的员工姓名,入职日期,职位,并按照入职日期的降序排列。

SELECT ename ,hiredate ,job FROM emp

WHERE hiredate BETWEEN'01-1月-81'AND'31-12月-82' AND(job LIKE'SALES%'OR job LIKE'MAN%') ORDERBY hiredate DESC 课后练习太简单,不再写

第四章单行函数

单行函数:作用于查询结果中的每一行。 多行函数:作用于查询结果中的一组。

单行函数可以写在SELECT ,WHERE,ORDER BY子句中

大小写转换:LOWER:转成小写(主要用于查询中方便查询,例子:select lower

(ename) from emp where ename like ‘A%’)

字符函数 UPPER:转成大写

INITCAP:首字母大写

字符处理: CONCAT:(与||类似,连接字符串,只能连接两个)

SUBSTR:(截取字符串,下标从1开始,substr中为负数,表示从后往前取)

LENGTH:(字符串长度) INSTR:(字符串,某个元素,开始位,第几次出现)的位数,没有返回0 LPAD:填充(被填充字符串,个数,填充字符串) RPAD:(与上面类似) REPLACE:(s1,s2,s3)s1中s2,替换成s3 TRIM:掐头去尾(‘H’ from‘HELLO’)或去空格(‘ HHHH ’)

应用实例:

CONCAT(‘spring’,’winter’)?springwinter

SUBSTR(‘spring’,1,3)?spr; SUBSTR(‘spring’,-1,3)?ing; LENGTH(‘spring’)?6 INSTR(‘spring’,’i’,1,1)?4

LPAD(‘spring’,10,’*’)?****spring RPAD(‘spring’,10,’*’)?spring**** REPLACE(‘spring’,s,d)?dpring

TRIM(‘ hh ’)?hh;TRIM(‘hh’ from ‘hhgghhgghh’)?gghhgg

练习1:

1,写一个查询,用首字母大写,其他字母小写显示雇员的ename,显示名字长度,并给每一列一个适当的标签,条件是满足所有雇员的姓名开头字母为J,A或M,并对查询结果安雇员的姓名升序排列。

SELECTINITCAP(ename)姓名,LENGTH(ename)姓名长度FROM emp WHERESUBSTR(ename,1,1)IN('J','A','M')ORDERBY姓名

2.查询员工姓名中含有大写或小写字母‘a’的员工姓名? SELECT ename FROM emp WHEREINSTR(LOWER(ename),'a')<>0

3.查询部门编号为10或者20,入职日期在81年5月1日之后,并且名字中含有大写字母A的员工姓名,以及姓名长度。

SELECT ename,LENGTH(ename)FROM emp

WHEREINSTR(ename,'A')<>0AND deptno IN(10,20)AND hiredate >'01-5月-81'

4.查询每个职工的编号,姓名,工资,要求将查询结果按照一定的格式合并成一个字符串:前10 位:编号,不足部分用*填充,左对齐;中间10位:姓名,不足部分用*填充,左对齐,后十位:工资,不足部分用*填充,右对齐。

SELECTLPAD('empno',10,'*')||LPAD(ename,10,'*')||RPAD(sal,10,'*')FROM emp

ROUND四舍五入:ROUND(46.927,0)?47,ROUND(46.927,-1)?50ROUND(46.927,2)?46.93

数值函数TRUNC截断:ROUND(46.927,0)?46,ROUND(46.927,-1)?40 ROUND(46.927,2)?46.92 MOD取余:MOD(1500,1400)?1500,MOD(1500,0)?1500

练习2.

1.查询100.456小数点后2,1,0位四舍五入的值?

SELECTROUND(100.456,2),ROUND(100.456,1),ROUND(100.456,0)FROM dual 2.查询100.456小数点后2,1,0位截断的值

SELECTTRUNC(100.456,2),TRUNC(100.456,1),TRUNC(100.456,0)FROM dual

日期函数

日期的默认格式“DD-MON-RR”

日期加减一个数表示在日期上加减相应的天数。 日期之间相减表示两个日期之间相差的天数。

如果要加其单位的时间需要进行进制转换。HH=DD*24;WEEK=DD/7; Sysdate:返回当前系统日期。

MONTHS_BETWEEN:返回两个日期的月间隔。 ADD_MONTHS:基础月份加上相应月数。

NEXT_DAY('01-2月-09’,’星期一’):返回某一个日期的下一天日期。 LAST_DAY:返回指定月份的最后一天。

ROUND(DATE,’fmt’):对日期四舍五入到天,或是按照格式四舍五入 TRUNC(DATE,’fmt’):对日期进行截断,或是按照格式进行截断。

EXTRACT:返回从日期中抽取的年、月、日。EXTRACT(month/year/day from hiredate) Fmt就是格式的意思,ORACLE中有相应的格式码,格式码如下:世纪CC,年YY,月MM,日DD,时HH24,分MI,秒SS

练习3

1. 查询每个员工从入职到现在一共多少天?

SELECT ename ,round(SYSDATE-hiredate)AS工作时间FROM emp 2. 查询服务器当前时间 SELECTSYSDATEfrom dual

3.查询部门10,20的员工截止到2000年1月1日,工作了多少个月,入职的月份,

SELECTEXTRACT(MONTHFROM hiredate)入职月份,months_between('01-1月-00',hiredate)工作月数FROM emp WHERE deptno IN(10,20)

4.如果员工试用期是6个月,查询职位不是MANAGER的员工姓名,入职日期,转正日期,入职日期后的第一个星期一。

SELECT ename,job,hiredate,add_months(hiredate,6)转正日期, next_day(hiredate,'星期一')入职后第一个周一, last_day(hiredate) FROM emp

WHERE job <>'MANAGER'

ORACLE中数据类型之间的转化

隐式转换:

数值型(比较)字符型?数值型 数值型(比较)日期型?日期型 ||?字符型

数值型(算术运算)非数值型?数值型 显示转换(注意括号中的是格式码)

TO_CHAR (YY,YEAR,MM,MONTH,DAY,DY,DAY “OF” MONTH)TO_CHAR(‘$99,99.99’)

DATE CHARACTER NUMBER TO_DATE(‘RR-MM-DD’)TO_NUMBER('9999.9999’) 转换函数是我的弱项 转换函数示例: Date to char

SELECT

to_char(hiredate,'yy')年份,

to_char(hiredate,'year')年份全称, to_char(hiredate,'mm')月份,

to_char(hiredate,'month')月份全称, to_char(hiredate,'dd')天, to_char(hiredate,'day')星期, to_char(hiredate,'dy')星期,

to_char(hiredate,'dd \),格式输出 to_char(hiredate,'HH24:MI:SS')时间 FROM emp

Number to char(位数不够显示#号)

SELECT sal,to_char(sal,'$9999.99')FROM emp Char to number(格式码必须与字符串对应)

SELECT to_number('1234.56','9999.99')FROM dual Char to date(格式码必须与字符串一致)

SELECT to_date('12-01-01','RR-MM-DD')FROM DUAL

通用函数

NVL(EXP1,EXP2):若EXP1不为空返回参数1,为空返回参数2;

NVL2(EXP1,EXP2,EXP3):第一个参数不为空返回第二个参数,为空返回第三个参数。 NULLIF(EXP1,EXP2):比较表达式,如果相等返回null,如果不相等,返回第一个表达式。 COALESCE:返回第一个不为空的表达式,参数个数是不受限制的

SELECT ename ,COALESCE(comm,0) comm1,nvl(comm,0) comm2 FROM emp

CASE …

WHEN … THEN … WHEN … THEN … ELSE … END

例子:

SELECT ename,deptno, (CASE deptno

WHEN10THEN'技术部' WHEN20THEN'服务部' WHEN30THEN'管理部' ELSE'无'END)AS部门 FROM emp

方法DECODE的实现方法: SELECT ename,deptno, DECODE(deptno, 10,'技术部', 20,'服务部', 30,'管理部', '无') department FROM emp

以下的一个例子表明,NVL函数中的两个函数类型必须是一致的,右边是char类型那么,左边就必须是char类型的。

SELECT ename,NVL(to_char(mgr),'no manager')FROM emp 课后作业:

1.计算2000年1月1日到现在有多少个月?有多少个周?

SELECTround(months_between(SYSDATE,TO_date('00-01-01','RR-MM-DD')))月数, ROUND((SYSDATE-TO_date('00-01-01','RR-MM-DD'))/7)周数FROM dual 3. 查询员工表中姓名第三个字母是‘a’的员工(用两个函数)

SELECT ename FROM emp WHERESUBSTR(ename,3,1)='A'(第3起长度1)

SELECT ename from emp WHEREINSTR(ename,'A',3,1)=3(第3起,第一次出现)

第五章多表连接

多表连接概述 等值连接 不等值连接 外部连接 内部链接

笛卡尔积:第一个表中的所有行与第二个表中的所有行均发生连接!

笛卡尔积在没有连接条件或者是连接条件无效的情况下发生,在where子句中设置连接条件,避免发生笛卡尔积。 练习1

1. 写一个查询,显示所有员工的姓名,部门编号,部门名称

SELECT e.ename,d.deptno FROM emp e,dept d WHERE e.deptno = d.deptno

2. 写一个查询,显示工作在芝加哥并且奖金不为空的员工的姓名,工作地点,奖金

SELECT e.ename,d.loc,NVL(e.comm,0)奖金FROM emp e,dept d WHERE e.deptno = d.deptno AND d.loc='CHICAGO'AND e.comm ISNOTNULL

3. 写一个查询,显示姓名中含有A的员工的姓名,工作地点?

SELECT e.ename,d.loc FROM emp e,dept d WHERE e.deptno = d.deptno ANDINSTR(lower(e.ename),'a')<>0或e.ename like ‘%A%’ Oracle中的不等值连接与多于两个表的连接内容比较少,直接写一个代表性的练习题就好了。 4.查询每个员工的的编号,姓名,工资,工资等级,所在工作城市,按照工资等级进行升序排列

SELECT e.empno,e.ename,s.grade,d.loc FROM emp e,dept d,salgrade s WHERE e.deptno = d.deptno

AND e.sal BETWEEN s.losal AND s.hisal ORDERBY s.grade ASC

ORACLE中的外链接与内连接及自身连接

内连接就是按照一定的连接条件,第一个表的每一条记录都能在另一个表找到相应的记录 ,同理外连接就是两个表中按照连接条件是找不到相应记录的,比如,某个员工没有部门,但是还是想把这个员工查出来,就需要用到外连接 外连接的语法规则就是在缺少信息匹配大那一边加上“(+)”,表示加上一个万能行 自身连接:查询员工姓名和直接领导姓名

例子的代码:SELECT e.ename 员工姓名,m.ename 经理姓名 FROM emp e,emp m

WHERE e.mgr = m.empno 练习2.

1.查询所有工作在纽约或(或就是IN,OR)芝加哥的员工姓名,员工编号及其经理姓名经理编号

SELECT e.ename,e.empno,m.ename,m.empno FROM emp e,emp m,dept d WHERE e.mgr = m.empno AND e.deptno = d.deptno

AND d.loc IN('NEW YORK','CHICAGO')

2.在第一题的基础上添加没有经理的King,并按照员工编号排序 SELECT e.ename,e.empno,m.ename,m.empno FROM emp e,emp m,dept d WHERE e.mgr = m.empno(+) AND e.deptno = d.deptno

AND d.loc IN('NEW YORK','CHICAGO') ORDERBY e.empno

Oracle语法规则SQL99的语法规则

SELECT e.ename,d.locSELECT e.ename,d.loc

FROM emp e,dept dFROM emp e CROSSJOIN dept d(交叉连接)

SELECT*SELECT*

FROM emp e,dept dFROM emp e NATURALJOIN dept d(自然连接)

WHERE e.deptno = d.deptnoSELECT*FROM emp JOIN dept(using方法) USING (deptno)相当于从多个相等字段中选一个deptno!

SQL99中用的最广的就是ON字句了,它的功能就是将检索条件和限制条件分开,限制条件放在where里面,而检索条件放在on里面,提高代码的可读性。

SELECT e.ename,d.deptnoSELECTename,deptno FROM emp e,dept dFROM emp JIONdept

WHERE e.deptno = d.deptnoON e.deptno = d.deptno(on子句放的条件更随意) ANDd.loc =‘NEW YORK’WHEREd.loc =‘NEW YORK’

SELECT*FROM EMP,DEPT SELECT*FROM EMPLEFTOUTERJOINDEPT

WHERE DEPT.DEPTNO = EMP.DEPTNO(+)ON EMP.DEPTNO = DEPT.DEPTNO

(无)SELECT*FROM EMPfullOUTERJOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO (全外连接)

练习3:

1.创建一个员工表和部门表的及交叉连接 SELECT*FROM emp CROSSJOIN dept

2.使用自然连接,显示入职日期在80年5月1日之后的员工,部门名称,入职日期

SELECT ename,deptno,hiredate FROM emp NATURALJOIN dept WHERE hiredate >'01-5月-80' 3.使用USING子句显示工作地点在CHICAGO的员工姓名,部门名称,工作地点

SELECT ename,dname,loc FROM emp JOIN dept USING(deptno)WHERE loc ='CHICAGO' 4.使用ON子句显示工作地点在CHICAGO的员工姓名,部门名称,工作地点,薪资等级 SELECT ename,dname,loc,grade

FROM emp JOIN dept ON emp.deptno = dept.deptno

JOIN salgrade ON emp.sal BETWEEN salgrade.losal AND salgrade.hisal WHERE loc ='CHICAGO'

5.使用左连接查询每个员工的姓名,经理姓名,没有经理的king也要显示出来 SELECT e.ename,m.ename FROM emp e LEFTOUTERJOIN emp m ON e.mgr = m.empno 6.使用右连接查询每个员工的姓名,经理姓名,没有经理的king也要显示出来 SELECT e.ename,m.ename FROM emp m RIGHTJOIN emp e ON e.mgr = m.empno 课后作业:

1.显示smith的姓名,部门名称,直接上级名称。

SELECT e.ename,d.dname,m.ename FROM emp e ,dept d,emp m WHERE e.deptno = d.deptno AND e.mgr = m.empno AND e.ename ='SMITH'

2.显示员工姓名,部门名称,工资,工资级别,要求大于4级。 SELECT e.ename,d.dname,e.sal,s.grade FROM emp e,dept d,salgrade s WHERE e.deptno = d.deptno

AND e.sal BETWEEN s.losal AND s.hisal AND s.grade >4

4.显示员工姓名,参加工作时间,经理名,参加工作时间,要求参加时间比经理早 SELECT e.ename,e.hiredate,m.ename,m.hiredate

FROM emp e ,emp m WHERE e.mgr = m.empno

AND e.hiredate < m.hiredate

第六章分组函数

分组函数:是对表中的一组记录进行操作,每一组能返回一个结果,首先就是要对数据进行分组。组函数只能嵌套两层

MIN:可以用于任何数据类型 MAX:可以用于任何数据类型 AVG:只能用于数值型 SUM:只能用于数值型

COUNT:count *可以计入空值,其他分组函数均是去掉空值计算的! Groupby 后面只能由两种语句:待分组的列和组函数。 相应的分组过滤字句必须是having里面的, 基础知识没有多少,直接做习题 练习1:

1.查询部门人数大于2的部门编号,部门名称,部门人数 SELECT e.deptno,d.dname,COUNT(e.empno) FROM emp e ,dept d

WHERE e.deptno = d.deptno GROUPBY e.deptno,d.dname HAVINGCOUNT(e.empno)>2 2.查询部门平均工资大于2000,且人数大于2的部门编号,部门名称,部门人数,部门平均工资,并按照部门人数升序排列

SELECT e.deptno,d.dname,COUNT(empno),AVG(sal) FROM emp e,dept d

WHERE e.deptno = d.deptno GROUPBY e.deptno,d.dname HAVINGAVG(sal)>2000 ORDERBYCOUNT(empno)

3.查询部门20 的员工,每个月的工资和及平局工资

SELECTSUM(sal)总工资,AVG(sal)平均工资FROM emp WHERE deptno ='20' 4.查询工作在CHICAGO的员工人数,最高工资及最低工资 SELECTCOUNT(e.empno),MIN(e.sal),MAX(e.sal) FROM emp e,dept d

WHERE e.deptno = d.deptno AND d.loc ='CHICAGO'

5.查询一共有集中岗位类型(去除重复记录并计数)

SELECTCOUNT(DISTINCT job)FROM emp

6.查询每个经理所管理的人数,经理编号,经理姓名,要求包括没有经理的人员信息 SELECT m.empno,m.ename,COUNT(e.empno) FROM emp e,emp m

WHERE e.mgr = m.empno(+) GROUPBY m.empno,m.ename

--1.部门平均工资在2500以上的部门名称及平均工资

SELECTAVG(e.sal),d.dname FROM emp e ,dept d WHERE e.deptno = d.deptno GROUPBY d.deptno,d.dname HAVINGAVG(sal)>2500

--2.查询岗位不以‘SA’开头,并且平均工资在2500以上的岗位及平均工资,按照工资降序

SELECT job,AVG(sal)FROM emp WHERE job <>'SA%' GROUPBY job ORDERBYAVG(sal)DESC

--3.查询部门人数在两个人以上的部门名称,最低工资,最高工资,并对工资进行四舍五入。

SELECT d.dname,round(MIN(e.sal)),round(max(e.sal)) FROM emp e,dept d WHERE e.deptno = d.deptno GROUPBY d.deptno,d.dname HAVINGCOUNT(empno)>2

--4.查询岗位不是salsesman的,工资和大于2500的每种岗位及其工资和

SELECT job,SUM(sal)FROM emp WHERE job <>'SALESMAN' GROUPBY job HAVINGSUM(sal)>2500

--5.显示经理号码,这个经理管理员工的最低工资,没有经理的king也要显示,不包括最底工资小于3000的,按最低工资由低到高排序

SELECT m.empno,min(e.sal) FROM emp e,emp m

WHERE e.mgr = m.empno(+) GROUPBY m.empno

HAVINGMIN(e.sal)>=3000 ORDERBYmin(e.sal)ASC

--6.查询每个部门的最低工资与最高工资的差额

SELECTMAX(sal)-MIN(sal)FROM emp GROUPBY deptno

第七章子查询

子查询先于主查询执行

主查询与子查询之间的运算符可以使用:= ,>,<,IN<=,>=,<>(单行子查询), ANY,ALL(多行子查询),单行子查询:子查询的返回结果为一行一列,

多行子查询:返回结果是多行一列(包括0行,也就是0行也算多行)

多列子查询:返回的查询结果为多行多列。

子查询可以用在where,having,from 子句中。 单行子查询例题:

--1.工资最高的员工的员工姓名,工资

SELECT ename ,sal FROM emp WHERE sal =(SELECTMAX(sal)FROM emp )

--2.查询和7369相同工作的,并且工资大于7369的员工的姓名,工作,工资

SELECT ename, job,sal

FROM emp WHERE job =(SELECT job FROM emp WHERE empno =7369) AND sal >(SELECT sal FROM emp WHERE empno =7369)

--3.查询部门最低工资比20号部门最低工资高的部门编号和最低工资

SELECT deptno,MIN(sal)FROM emp GROUPBY deptno

HAVINGMIN(sal)>(SELECTMIN(sal)FROM emp WHERE deptno =20) --4.查询什么部门的人数高于各个部门的平均人数 SELECT deptno FROM emp GROUPBY deptno

HAVINGCOUNT(empno)>(SELECTavg(COUNT(empno))FROM emp GROUPBY deptno) --5.查询入职日期最早的那个员工姓名

SELECT ename FROM emp WHERE hiredate =(SELECTMIN(hiredate)FROM emp)

--6.查询工资比smith高,并且工作地点在chicago的员工姓名,工资,部门名称

SELECT e.ename,e.sal,d.dname FROM emp e,dept d WHERE e.deptno = d.deptno AND d.loc ='CHICAGO'AND e.sal >

(SELECT sal FROM emp WHERE ename ='SMITH')

--7.查询入职日期比20部门入职日期最早的员工还要早的员工姓名,入职日期

SELECT ename,min(hiredate)FROM emp WHERE hiredate <(SELECTmin(hiredate)FROM emp WHERE deptno =20)

--8.查询部门人数大于各部门平均人数的部门名称,部门编号,部门人数 SELECT d.dname,e.deptno,COUNT(e.empno)FROM emp e,dept d WHERE e.deptno(+)= d.deptno GROUPBY d.dname,e.deptno HAVINGCOUNT(empno)>

(SELECTAVG(COUNT(empno))FROM emp GROUPBY deptno)

一下练习中演示了多行子查询中多行运算符(IN 、ANY、 ALL)的应用。 --1.查询是经理的员工姓名,工资

SELECT ename,sal FROM emp WHERE empno IN(SELECT mgr FROM emp)

--2.查询部门编号不为10,且工资比10 部门中任意一个员工工资高的员工编号,姓名,职位,工资

SELECT empno,ename,job,sal FROM emp

WHERE deptno <>10AND sal >ANY(SELECT sal FROM emp WHERE deptno =10)

--3.查询部门编号不为10,且工资比10 部门中任意一个员工工资低的员工编号,姓名,职位,工资

SELECT empno,ename,job,sal FROM emp

WHERE deptno <>10AND sal

--4.查询部门编号不为10,且工资比10 部门中所有员工工资低的员工编号,姓名,职位,工资

SELECT empno,ename,job,sal FROM emp

WHERE deptno <>10AND sal

--5.查询部门编号不为10,且工资比10 部门中所有员工工资高的员工编号,姓名,职位,工资

SELECT empno,ename,job,sal FROM emp

WHERE deptno <>10AND sal >ALL(SELECT sal FROM emp WHERE deptno =10)

多列子查询:通过一下的例子可以看出,多列子查询其实就是子查询中出现了多个列! --1.查询职位和部门与smith完全相同的人员姓名,

SELECT ename FROM emp WHERE(job,deptno)IN(SELECT job,deptno FROM emp WHERE ename ='SMITH')

AND ename <>'SMITH'

--2.查询和1981年入职的任意一个员工的部门和职位完全相同,员工姓名,部门,职位,入职日期,不包括1981年入职的员工

SELECT ename,deptno,job,hiredate FROM emp WHERE(deptno,job)

IN(SELECT deptno,job FROM emp WHEREEXTRACT(YEARFROM hiredate)=1981) ANDSUBSTR(hiredate,-2)<>81

或substr(hiredate,-2)=81或to_char(hiredate,'YYYY')='1981'

--3.查询和1981年入职的任意一个员工的部门或职位相同,员工姓名,部门,职位,入职日期,不包括1981年入职的员工

SELECT ename,deptno,job,hiredate FROM emp WHERE( deptno

IN(SELECT deptno FROM emp WHEREEXTRACT(YEARFROM hiredate)=1981)

OR job IN(SELECT job FROM emp WHEREEXTRACT(YEARFROM hiredate)=1981)) ANDEXTRACT(YEARFROM hiredate)<>1981

注意:最后一题不是多列子查询,说白了,多列子查询只能解决“列和”的问题,不能解决“列或”的问题。

子查询中的空值问题: 查询不是经理的员工姓名

SELECT ename FROM emp WHERE empno NOTIN(SELECT mgr FROM emp ) 翻译为:

SELECT ename FROM emp WHERE

(empno <>7839AND empno <>7782AND empno <>NULLAND empno <>7698AND empno <>7902AND empno <>7566)

例子中可以看出,子查询中有了一个空值,整个查询结果就是faulse,一个也查不出来 所以以上查询应该这样写:

SELECT ename FROM emp WHERE empno NOTIN(SELECT mgr FROM emp where mgr is not null)

From 子句中应用子查询:这一类查询中很明显“自己部门”既没有信息,又是模糊的, 自己部门+平均工资,可以构成一个表。

--1.查询比自己部门平均工资高的员工姓名,工资,部门编号,部门平均工资。 SELECT e.ename,e.sal,e.deptno,tavg.av

FROM emp e,(SELECT deptno,AVG(sal) av FROM emp GROUPBY deptno) tavg WHERE e.deptno = tavg.deptno AND e.sal > tavg.av

关于伪列ROWNUM:

1.ROWNUM是一个伪列,它与查询相对应,如果给每个查询都建立一个ROWNUM ,这些伪列之间互不影响。

2.select * from emp where rownum > 2查不出任何数据,因为rownum跟就记录生成而生成,roenum只能用<,<=用,不能用>!!!!

3.rownum和orderby连用的时候,rownum其实是排完序之后的!可见order by最后执行啊!!

--1.查询入职日期最早的前5名员工姓名,入职日期。

SELECTROWNUM,ename ,hiredate FROM(SELECT ename,hiredate FROM emp ORDERBY hiredate ASC)WHEREROWNUM<=5

--2.查询工作在CHICAGO并且入职日期最早的前两名员工姓名,入职日期

SELECTROWNUM,ename ,hiredate

FROM(SELECT ename,hiredate FROM emp e,dept d WHERE e.deptno = d.deptno ORDERBY hiredate ASC)WHEREROWNUM<=2

以上几个例子就非常明显的特征:排序之后再用伪列编号!只能这么写!:::

分页查询(重要)

分页查询可以分为未排序的和排序的两种 未排序的分页查询:(子查询全部查出,然后取5-10条,效率低) SELECTROWNUM,b.*FROM

(SELECTROWNUM rw,empno,ename FROM emp) b WHERE rw <=5*2AND rw >5*1

抽象成:WHERE rw <=页尺寸*当前页AND rw >页尺寸*(当前页-1) 未排序的分页查询:(子查询全查出前十条,然后在外面去除前5条,效率高) SELECTROWNUM,b.*FROM

(SELECTROWNUM rw,empno,ename FROM emp WHEREROWNUM<=5*2) b WHERE rw >5*1

以上可以看出,分页查询要查询的内容都在FROM中的子查询中! 指定排序条件的分页查询:

按照日期先后顺序进行分页查询,每页显示3条记录。 SELECT c.*FROM

(SELECTROWNUM rw, b.*FROM

(SELECTROWNUM,empno,ename,hiredate FROM emp ORDERBY hiredate) b WHEREROWNUM<=页尺寸*当前页) c WHERE rw>页尺寸*(当前页-1)

用的时候只需要换最内层的语句就好了。 章节课后题

--1.查询工资高于编号为7782的员工工资,并且和7369员工从事相同工作的员工编号,姓名,工资

SELECT empno,ename,sal FROM emp WHERE sal>(SELECT sal FROM emp WHERE empno =7782) AND job =(SELECT job FROM emp WHERE empno =7369) --2.查询工资最高的员工姓名,工资

SELECT ename,sal FROM emp WHERE sal =(SELECTMAX(sal)FROM emp )

--3.查询部门最低工资高于30号部门最低工资的部门的编号、名称及部门最低工资 SELECT e.deptno,d.dname,MIN(sal)FROM emp e, dept d WHERE e.deptno = d.deptno GROUPBY e.deptno,d.dname

HAVINGMIN(sal)>(SELECTMIN(sal)FROM emp WHERE deptno =30)

第八章集合运算

联合运算:去除重复行,自动按照第一列升序排列 完全联合运算:不去除重复行,不会排序, 联合运算的注意事项:,联合的列数与列属性必须一致,但是列名可以不一样;每个查询结

果不能含有自己的order by语句,只能联合完成之后,在最后使用orderby语句;可以联合多个select语句;查询结果级的名字以第一个select语句中的名字为准。 练习1:

--1.分别使用联合运算及完全联合运算完成,按照时间升序顺序,查询员工7839 的工作岗位列表。

SELECT job ,NULLFROM emp WHERE empno =7839 UNION

SELECT job, begindate FROM emp_jobhistory WHERE empno =7839 SELECT job ,NULLFROM emp WHERE empno =7839 UNIONALL

SELECT job, begindate FROM emp_jobhistory WHERE empno =7839

--2.使用多表连接,查询每个部门的部门名称,部门人数没有人数的部门显示零

SELECT d.dname,COUNT(e.empno) FROM emp e,dept d

WHERE e.deptno(+)= d.deptno GROUPBY d.deptno,d.dname

--3.使用联合运算,查询每个部门的部门名称,部门人数没有人数的部门显示零

SELECT d.dname,COUNT(e.empno) FROM emp e,dept d

WHERE e.deptno(+)= d.deptno GROUPBY d.deptno,d.dname UNION

SELECT dname,0 FROM dept d

WHERE deptno NOTIN(SELECT deptno FROM dept WHERE deptno ISNOTNULL) --4.联合运算,查询10,20号部门的员工

SELECT empno,ename FROM emp WHERE deptno IN(10,20) SELECT empno,ename FROM emp WHERE deptno =10 UNION

SELECT empno,ename FROM emp WHERE deptno =20 --5.利用集合运算打印出如图结果,(课件上) SELECT deptno,loc,NULL,NULLFROM dept UNION

SELECT deptno,null,ename,hiredate FROM emp

相交运算(intersect)共有部分 相减运算(minus)减去共有部分

第九章高级子查询

嵌套子查询单行,多行,多列 子查询

相关子查询(子查询中引用了父查询中的一个列)

第七章的子查询就是嵌套子查询,嵌套在where 、having、from子句中,嵌套子查询基本上是子查询先执行一次,然后用子查询的结果来确认取消父查询结果。 练习1.

--1.查询比自己所在职位平均工资高的员工姓名、职位 --相关子查询

SELECT ename,job FROM emp e WHERE sal >(SELECTAVG(sal)FROM emp WHERE job = e.job GROUPBY job) --嵌套子查询

SELECT ename,e.job FROM emp e,(SELECT job,AVG(sal) avgsal FROM emp GROUPBY job) b WHERE b.job = e.job AND e.sal > b.avgsal

--1.查询所有部门的名称和人数 --分组函数和多表连接

SELECT dname,COUNT(empno) FROM emp e,dept d

WHERE e.deptno = d.deptno GROUPBY dname --嵌套子查询

SELECT dname , ce 人数

FROM(SELECT deptno,COUNT(empno) ce FROM emp GROUPBY deptno) d,dept e WHERE e.deptno = d.deptno(+) --相关子查询

SELECT dname,(SELECTCOUNT(empno)FROM emp WHERE deptno = d.deptno) FROM dept d

--2.查询那些员工是经理 --嵌套子查询

SELECT*FROM emp WHERE empno IN(SELECTDISTINCT mgr FROM emp) --相关子查询

SELECT*FROM emp e WHERE(SELECTCOUNT(empno)FROM emp WHERE mgr = e.empno )>0 --3.查询至少调动过两次岗位的员工编号,姓名,岗位 SELECT*FROM emp e

WHERE(SELECTCOUNT(empno)FROM job_history WHERE e.empno = job_history.empno)>=2 --查询每个部门中工资最低的两个员工的编号,姓名,工资。 SELECT*FROM emp e

WHERE(SELECTCOUNT(empno)FROM emp WHERE deptno = e.deptno AND sal > e.sal)<=1 练习2:

--1,列出至少有一个雇员的所有部门名称 SELECT*FROM dept d

WHEREEXISTS(SELECT'1'FROM emp WHERE d.deptno = deptno) --2,列出一个雇员都没有所有部门名称 SELECT*FROM dept d

WHERENOTEXISTS(SELECT'1'FROM emp WHERE d.deptno = deptno)

第十章层次查询

层次查询:自然树结构,遍历树,修建分支,用level分等级, SELECTlevel,ename ||'report to'||--查询层次数和名字 PRIOR ename \--查询上一级名字

LPAD(ename,LENGTH(ename)+(LEVEL-1)*2,'*') --结构化输出层次报告 FROM emp

WHERE ename !='HIGGINS'--只删除higgins这一个节点,higgin子节点不删除 STARTWITH ename ='KING' --从KING开始

CONNECTBYPRIOR empno = mgr--按照从顶向下层次查询

AND ename !='HIGGINS'--从higgins这个节点开始,后面的全部去掉

第十一章数据操作和事务控制(DML && TPL)

数据查询语言:DQL--------select 数据操作语言:DML--insert,update,delete,merge操作行数据,相关子查询常用于 他们的Where子句中 5大语句事务处理语言:TPL---commit,rollback对DML操作的确认取消,保持数据一致性 数据定义语言:DDL--------create,alter,drop truncate 数据控制语言:DCL--------grant,revoke INSERTINTO dept(deptno,dname,loc)VALUES(50,'development','SY') 插入日期’01-1月-2018’-----默认日期格式 ‘to_date(‘2000-04-01’,’YYYY-MM-DD’)’ INSERTINTO tablename1 SELECT*FROM tablename2 WHERE conditions...插入多条数据相当于复制了 UPDATE emp SET sal = sal+100,deptno =10WHERE deptno =10 Set设置更改的列,where限定更改的行。

有一个比较有意思的例子在这里说一下, 这个可以叫嵌套更新

--修改工作地点在NEW YORK,CHICAGO的员工的工资,工资增加500

UPDATE emp SET sal = sal+500WHERE deptno =(SELECT deptno FROM emp WHERE loc IN('NEW YORK','CHICAGO')) 相关更新如下:

--修改员工表的dname列,填相应部门名称,该列与部门表中的数据对应

UPDATE emp e SET dname =(SELECT dname FROM dept WHERE deptno = e.deptno)

DELETEFROM emp WHERE job ='CLERK' 事务

什么是事务:

每一组相关的DML或select语句,加上TPL,DDL或DCL就算是一个完整的事务 事务的特性:原子性,一致性,隔离性,持久性。

事务自动开启:上一个事务结束后,遇到第一个DML语句

保存点:使事务回滚到指定点 语法:SAVEPOINT savepointname

ROLLBACK TO savepointname

保存点不结束事务,这与rollback完全不是一回事!!!!!!!!!!

锁及数据状态

锁:在多用户并发访问和操作数据库的时候,保持数据的一致性。 锁是oracle自动管理的,数据库会在执行DML操作时会在受DML影响的行记录上自动加锁,事务结束之后才会释放锁。

事务结束之前的数据状态:可以恢复,可以用select语句查看效果,当前记录上锁,别人无法查看当前的DML操作。

事务结束之后的数据状态:数据变化永久性了,所有回话和用户均可以看到操作后的结果,锁被释放,保存点被清除。

数据合并(merge)

根据指定条件执行插入操作或者是更新操作,如果满足条件执行更新操作,如果不满足则执行插入操作。

优点:避免独立的数据更新,提高效率使用方便,数据仓库中经常使用。 MERGEINTO emp a

USING employees b ON(a.employee_id = b.employee_id) WHENMATCHEDTHEN UPDATESET

a.email = b.email,

a.phone_number = b.phone_number, a.salary = b.salary,

a.manager_id = b.manager_id,

a.department_id = b.department_id WHENNOTMATCHEDTHEN INSERT

(employee_id,email,phone_number,salary,manager_id,department_id) VALUES(b.employee_id,b.email,b.phone_number, b.salary,b.manager_id,b.department_id)

第十二章数据库网络连接

网络连接方式:

Conn用户名/口令@服务命名[as sysdba/sysoper] 其中,服务命名 =主机名:端口号:数据库服务名 网络连接协议:

TCP: 网络传输控制协议

IPC:本地进程通信机制 网络连接的条件:

服务端:配置监听器服务

启动数据库主服务

客户端:配置网络服务名。

服务器端配置监听器服务:

工具:net configuration assistant工具?这个是讲过的。 Net manager 工具

第十三章创建和维护数据库对象(DDL)

数据定义语言包括了数据结构定义语言和数据库对象定义语言。

数据库对象:表,约束,序列,索引,视图,同义词,触发器,存储过程,函数,用户等。 所有对象中只有表能够存储数据的!

对象名命名规则:字母数字下划线$和#,同一用户内不可能有两个命名完全相同的对象,名字不能使oracle的保留字,名字大小写不敏感!

创建表(约束讲完之后统一建表示例)

Default关键字:用于定义表中字段的默认值,默认值的类型必须与定义的数据类型一致。 数据类型: 字符型:

Char:固定占用10个字节,用不了的空着。

Varchar2:长度可变,最小长度为1 ,最大是4000. Clob :可变长度:最大存储4G 数值型:

Number:既可以表示整数,也可以表示小数。 Number(n):整形

Number(m,n):总长度m,小数位n 日期型:

Date:年月日时分秒

Timestamp:精确到毫秒。 图片类型:

BLOB:最大4G的二进制的数据,存图片,声音,文件 子查询建表:

CREATETABLE manager ASSELECT*FROM emp WHERE job='MANAGER'从此两个表是没有任何关系了!

引用另一个用户的表 SELECT*FROM scott.emp 修改表(结构)

ALTER ..ADD添加列ALTERTABLE emp ADD gender CHAR(2)DEFAULT'男'

ALTER.. MODIFY 修改列列只能修改数据类型,长度及默认值。修改类型已有的行数据

必须先设置为空;修改列的长度,往大长度改没有限制,如果往小改已有的行数据必须为空。修改默认值只会影响新插入的值,以前的默认值是不变的。

ALTERTABLE emp MODIFY gender CHAR(4)或DEFAULT'女'或NUMBER

ALTER…DROP 删除列

删除列至少要留有一列,所有DDL不能回滚,删除时列中可以有数据也可以没有。被外键

引用的列不能被删除。

ALTERTABLE emp DROP(dname)注意括号

修改列的名字:

ALTERTABLE emp RENAMECOLUMN ename TONAME 删除表

DROPTABLE emp

注意:删除表之后所有的数据及结构都会被删除且无法回滚,所有的事务就会提交,所有的视图和同义词被保留但是无效,所有相关的约束索引都删除。 重命名表

RENAME emp TO empl 截断表

TRUNCATETABLE salavg 删除表数据但是保留表结构

截断表truncate和删除数据delete的区别:

Truncate:DDL;只能全部删除;释放表空间;无法回滚

Delete :DML;可以通过where子句限定条件;数据存入回滚段里面,可以回滚。

第十四章约束

约束:保证数据完整性

约束类型:主键,外键,唯一键,非空约束,检查性约束

外键:如果在某一列上建立了外键,那么该列取值的来源只能是引用的列

只有主键和唯一键所限定的列才能作为外键的引用列。 外键不默认产生非空。 创建表和约束

CREATETABLE department (

dno CHAR(4)CONSTRAINT department_dno_pk PRIMARYKEY, dname VARCHAR(20)CONSTRAINT department_dname_uk UNIQUE, dboss VARCHAR(20)CONSTRAINTNOTNULL,

dloc CHAR(8)CONSTRAINT department_dloc_ck CHECK(dloc IN('南湖校区','浑南校区')) )

CREATETABLECLASS (

cno NUMBER(4), cname VARCHAR(20), dno CHAR(4),

CONSTRAINT class_cno_pk PRIMARYKEY(cno), CONSTRAINT class_cname_uk UNIQUE(cname),

CONSTRAINT class_dno_fk FOREIGNKEY(dno)REFERENCES department (dno) )

外键中的删除

ONDELETECASCADE:父表删除,级联删除子表。

ONDELETESETNULL:父表删除,子表想依赖的行设为空值。

约束的启用与禁用

在大量数据迁移的时候需要禁用启用约束

ALTERTABLE emp DISABLECONSTRAINT emp_empno_pk ALTERTABLE emp ENABLECONSTRAINT emp_empno_pk 追加删除约束,添加非空约束

ALTERTABLE emp ADDCONSTRAINT emp_empno_pk PRIMARYKEY(empno) ALTERTABLE emp MODIFY ename NOTNULL

ALTERTABLE emp DROPUNIQUE(eno)|CONSTRAINT约束名 [CASCADE]CASCADE级联删除相关外键

第十五章视图

六种数表:用来存储用户数据的对象,由行和列组成,也就是字段和记录

据库对象约束:保证数据完整性的规则。约束设置在单个字段或是多个字段的组合上。 视图:虚表,是一个命名的查询,用于改变基表的数据显示,简化查询。 索引:构建于表的单字段或是字段组合,用于加速表中的数据查询。 序列:差生顺序的不重复的数字串,被作为主键约束的参照。 同义词:数据库对象的别名

创建视图语法:

CREATE [ORREPLACE] [FORCE|NOFORCE] VIEW viewname AS subquery

[WITHCHECKOPTION [CONSTRAINT constraintname]] [WITHREADONLY]

REPLACE:有这个视图责备替换

[FORCE|NOFORCE]: 如果基表不存在,强制建立视图 Subquery:子查询 [WITHCHECKOPTION [CONSTRAINT constraintname]]:首先视图是可以执行DML操作的,如果

执行的操作在视图中没有显示就会插入失败,如果视图中可以看到则会插入失败。 [WITHREADONLY]不执行DML语句

第一章:认识Java

毕向东Java基础视频复习笔记

线程

单例设计模式:(多线程与静态结合) 饿汉式:(实例提前加载) class SingleDemo1 {

Private static final SingleDemo1 s = new SingleDemo1(); Private SingleDemo1(){}

Public static SingleDemo1 getInstance()

{

Return s; } }

懒汉式:(实例的延迟加载) Class SingleDemo2 {

Private static SingleDemo2 s = null; Private SingleDemo(){}

Public staticsynchronizedSingleDemo2 getInstance() If(s==null) {

S = new SingleDemo2(); }

Return s; }

懒汉式在多线程创建对象的时候就会出现安全隐患。因此应该在懒汉式上加锁!但是加上同步函数之后,运行比较低效,因此采用同步代码块。修改如下: Class SingleDemo2 {

Private static SingleDemo2 s = null; Private SingleDemo(){}

Public static SingleDemo2 getInstance() {

If (s == null) {

Synchronized(Single.class)//在静态方法中,锁是该类所属的字节码文件。相比较,{步函数用的是this的锁 If(s==null)

S = new SingleDemo2(); } }

Return s; } }

死锁:

package com.neuedu.shuang.thread; class Test implements Runnable {

booleanflag = true;

Test(boolean flag)//用构造函数设置boolean值控制线程分别从if和else中进入。 {

this.flag = flag; }

publicvoid run()//死锁就是两个同步套用同步!所调用的锁正好相反 {

if(flag) {

synchronized(MyLock.lock1) {

System.out.println(\); synchronized(MyLock.lock2) {

System.out.println(\); } } } else {

synchronized(MyLock.lock2) {

System.out.println(\); synchronized(MyLock.lock1) {

System.out.println(\); } } } } }

class MyLock {

static Object lock1 = new Object();//静态方纯属便调用 static Object lock2 = new Object(); }

publicclass DeadLockTest {

publicstaticvoid main(String[] args) {

Thread t1 = new Thread(new Test(true)); Thread t2 = new Thread(new Test(false)); t1.start(); t2.start(); } }

线程间通信

COMMON SENSE:线程安全出现问题之后要加同步(synchronized),加上同步问题没有解决要看两个前提:第一,是不是两个或是两个以上线程;第二,用的是否是同一个锁。 线程间通信:其实就是多个线程操作同一个资源,但是操作的动作不一样。 package com.neuedu.shuang.thread; class Resource//定义一个共有资源 {

String name; String sex; }

class Input implements Runnable//输入方法实现Runnable接口 {

private Resource re;

Input(Resource re)//构造方法传值初始化,防止一个类new一个对象,那样资源就不共享了 {

this.re = re; }

publicvoid run() {

int x = 0;

while(true)//死循环多次输入 {

if(x == 0) {

re.name = \; re.sex = \; } else {

re.name = \王爽\; re.sex = \女\; }

x = (x+1)%2;//x在0和1之间互换,实现交替输出 } } }

class Output implements Runnable//输出方法同上 {

private Resource re; Output(Resource re) {

this.re = re; }

publicvoid run() {

while(true) {

System.out.println(re.name+\+re.sex); } } }

publicclass InputOutputDemo {

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub

Resource r = new Resource();//建立对象资源

Input in = new Input(r);//实例化实现了runnable接口的方法, Output out = new Output(r);

Thread t1 = new Thread(in);//建立两个线程 Thread t2 = new Thread(out);

t1.start();//线程开启 t2.start(); } }

这个线程间通信的小程序没有实现线程之间的同步!所以线程是不安全的!会输出如下结果:“王爽 male\\n John 女”等。

实现线程之间同步的代码如下,主要解决如下问题:将要加上锁的那一部分语句找出来,synchronized的位置要加对,锁所引用的对象要一致。 package com.neuedu.shuang.thread; class Resource//定义一个共有资源 {

String name; String sex; }

class Input implements Runnable//输入方法实现Runnable接口 {

private Resource re;

Input(Resource re)//构造方法传值初始化,防止一个类new一个对象,那样资源就不共享了 {

this.re = re; }

publicvoid run() {

int x = 0;

while(true)//死循环多次输入 {

synchronized (re) {//锁

if(x == 0) {

re.name = \; re.sex = \; } else {

re.name = \王爽\; re.sex = \女\; } }

x = (x+1)%2;//x在0和1之间互换,实现交替输出 } } }

class Output implements Runnable//输出方法同上 {

private Resource re; Output(Resource re) {

this.re = re; }

publicvoid run() {

while(true) {

synchronized(re){ //锁 System.out.println(re.name+\+re.sex); } } } }

publicclass InputOutputDemo {

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub

Resource r = new Resource();//建立对象资源

Input in = new Input(r);//实例化实现了runnable接口的方法, Output out = new Output(r);

Thread t1 = new Thread(in);//建立两个线程 Thread t2 = new Thread(out);

t1.start();//线程开启 t2.start(); } }

上面的这个小程序虽然实现了同步,但是出现了一个严重的问题,就是input得到执行权之后会不停的输入并覆盖,而output得到执行权之后会不停打印同一内容,此时需要等待唤醒机制,注意:等待(wait)的线程都会在线程池里面!

Wait().notify();notifyAll()都位于Object类里面,而不是定义在Thread类里面,因为等待、唤醒都需要用同步的对象进行引用,而同步可以用于所有对象,所以这三个方法都要定义在祖宗类里面。并且都要用在同步(synchronized)的里面,因为要对监视器(锁进行操作)。

如下实现等待唤醒代码:

package com.neuedu.shuang.thread; class Resource//定义一个共有资源 {

String name; String sex;

booleanflag = false; }

class Input implements Runnable//输入方法实现Runnable接口 {

private Resource re;

Input(Resource re)//构造方法传值初始化,防止一个类new一个对象,那样资源就不共享了 {

this.re = re; }

publicvoid run() {

int x = 0;

while(true)//死循环多次输入 {

synchronized (re) {//等待

if(re.flag){try {re.wait();} catch (InterruptedException e) { e.printStackTrace();}} if(x == 0) {

re.name = \; re.sex = \; } else {

re.name = \王爽\; re.sex = \女\; }

x = (x+1)%2;//x在0和1之间互换,实现交替输出 re.flag = true;

re.notify();//唤醒 }

} } }

class Output implements Runnable//输出方法同上 {

private Resource re; Output(Resource re) {

this.re = re; }

publicvoid run() {

while(true) {

synchronized(re) {

if(!re.flag)//等待

try {re.wait();} catch (InterruptedException e) {e.printStackTrace();} System.out.println(re.name+\+re.sex); re.flag = false;

re.notify();//唤醒 } } } }

publicclass InputOutputDemo {

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub

Resource r = new Resource();//建立对象资源

Input in = new Input(r);//实例化实现了runnable接口的方法, Output out = new Output(r);

Thread t1 = new Thread(in);//建立两个线程 Thread t2 = new Thread(out);

t1.start();//线程开启 t2.start(); } }

以上修改的程序就实现了线程通信的交替执行,通过的等待(wait)唤醒(notify)机制。但是以上代码并不简洁,需要对代码进行优化! package com.neuedu.shuang.thread; class Resource//定义一个共有资源 {

private String name; private String sex;

privatebooleanflag = false;

publicsynchronizedvoid setResource(String name,String sex) {

if(flag){try{this.wait();}catch(InterruptedException e){}} this.name = name; this.sex = sex; this.flag = true; this.notify(); }

publicsynchronizedvoid show() {

if(!flag){try{this.wait();}catch(InterruptedException e){}} System.out.println(this.name+\+this.sex); this.flag = false; this.notify(); } }

class Input implements Runnable//输入方法实现Runnable接口 {

private Resource re;

public Input(Resource re) {

this.re = re; }

publicvoid run() {

int x = 0;

while(true)//死循环多次输入 {

if(x == 0)

re.setResource(\, \); else

re.setResource(\, \); x = (x+1)%2;//x在0和1之间互换,实现交替输出 } } }

class Output implements Runnable//输出方法同上 {

private Resource re;

public Output(Resource re) {

this.re = re; }

publicvoid run() {

while(true){re.show();} } }

publicclass InputOutputDemo {

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub }

Resource r = new Resource();//建立对象资源 new Thread((new Input(r))).start(); new Thread((new Output(r))).start(); }

集合类

集合框架的概述 为什么会有集合类?

因为面向对象的语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就需要对对象进行存储,集合就是用来存储数据对象的。 集合类与数组的不同?

集合长度可变;数组长度不可变。

集合只能存储对象,数组可以存储基本数据类型。 集合类的特点?

只能存储对象,可以存储不同类型的对象,长度可变。 arraylist List linkedlist vector

Collection hashset (util包) Set treeset 每一个集合的数据结构是不同的

学习面向对象的编程学习方法:要先学习父类,学完父类用子类中的方法 1.集合框架中的共性方法介绍,与代码示例: package collection;

import java.util.ArrayList; publicclass CollectionDemo {

publicstaticvoid main(String[] args) {

//创建一个集合类

ArrayList al = newArrayList(); ArrayList ar = newArrayList(); //添加元素

al.add(\);//add的意思就是往集合里面加入对象的引用(地址值) al.add(\); }

}

al.add(\); al.add(\); //添加元素

ar.add(\); ar.add(\); ar.add(\); //RetainAllDemo(al,ar); RemoveAllDemo(al,ar);

sop(al);//打印集合

sop(\+al.size());//获取集合长度 al.remove(\);//删除集合中的元素 sop(al);//打印集合 al.clear();//清空集合

al.isEmpty();//判断集合是否为空,返回布尔值

al.contains(\);//判断集合中是否含有相应对象。

//显示函数

privatestaticvoid sop(Object obj) { // TODO Auto-generated method stub System.out.println(obj); }

//集合交集运算

publicstaticvoid RetainAllDemo(ArrayList al1,ArrayList al2) {

sop(al1);//交集之前的al全部显示 sop(al2);//交集之前的ar全部显示

sop(al1.retainAll(al2));//交集运算的返回值为boolean性 sop(al1);//al中保存的是交集运算后的结果[java01,java04] }

publicstaticvoid RemoveAllDemo(ArrayList al1,ArrayList al2) { }

sop(al1);//交集之前的al全部显示 sop(al2);//交集之前的ar全部显示

sop(al1.removeAll(al2));//移除部分运算博哦了按性

sop(al1);//al中保存的是移除运算后的结果[java02, java03]

2.迭代器的使用:

iterator接口型的引用只能指向子类对象!!,而这个对象又不能new出来!只能通过集合类的方法获取。

Iteratorit = al.iterator(); while(it.hasNext()) {

it.next();

}

注意:每个容器中的数据结构有所不同,所以对容器内部对象的操作最方便的就是定义一个集合的内部类,这样取出方式那就好可以直接访问容器内部的元素。虽然每一个容器的动作细节不一样,但是他们有一样的判断和取出的功能,因此就把这两部分功能抽象成了集合内部的iterator()方法。 Iterator()

判判判

断断断

提提提

取 取 取

迭代器的更高水平的应用:(it变成了局部变量,用完立即释放,不会占用内存空间) for(Iteratorit = al.iterator();it.hasNext(); ) {

al.next(); }

3. List集合的特有的共性方法

|--List:元素是有序的,并且元素可以重复,因为内部有索引。 |--set:元素是无序的,元素是不可以重复的,因为内部没有索引。 List集合的特有方法,特有的就是跟角标相关的方法: 增

Add(index,element);addAll(index,collection) 删

Remove(index); 改

Set(index,elemnt)

List中特有方法代码示例:

Get(index);sublist(from , to);listIterator(); package collection; import java.util.*; publicclass listDemo {

publicstaticvoid sop(Object obj) {

System.out.println(obj); }

publicstaticvoid main(String[] args) {

}

// TODO Auto-generated method stub ArrayList al = newArrayList(); al.add(\);//依次添加元素 al.add(\); al.add(\); al.add(\); al.add(\); al.add(\); sop(al);//打印原集合; al.add(2, \); sop(al);//打印插入之后的集合; al.remove(2);//删除指定位置的元素

al.set(2, \);//修改指定位置上的元素 al.get(1);//取出指定位置的集合。 for(int x = 0;x < al.size();x++){ al.get(x);//循环取出。 }

//通过indexOf获取角标

sop(al.indexOf(\));

//subList取出拿头去尾

List sb = al.subList(0, 1); sop(sb); }

4.List集合特有的迭代器ListIteartor列表迭代器

ListIteartor是Iterator的子接口,通过列表迭代器可以实现在集合便利过程中的增删改查!!! 先用一组代码说明没有列表迭代器的不方便: package collection;

import java.util.ArrayList; import java.util.Iterator;

publicclass ListIteratorDemo {

publicstaticvoid sop(Object obj) {

System.out.println(obj); }

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub ArrayList al = newArrayList();

al.add(\);//依次添加元素 al.add(\); al.add(\); al.add(\); al.add(\);

al.add(\); //在迭代的过程中,添加或是删除元素 Iterator it = al.iterator(); while(it.hasNext()){//迭代器的判断方法 Object obj = it.next(); if(obj.equals(\)){

al.add(\);//集合的添加方法,这个与迭代器的判断方法并发访问集合,报并发异常!

it.remove();//迭代器的删除操作 }

sop(\+obj );//打印引用,全部显示 }

sop(al);//打印集合发现已经删除 } }

然后用列表迭代器实现以下,因为用列表迭代器可以有增删改查更加多样的功能,增删改查都用列表迭代器,这样还可以消除并发访问的异常!!!! package collection;

import java.util.ArrayList; import java.util.*;

publicclass ListIteratorDemo {

publicstaticvoid sop(Object obj) {

System.out.println(obj); }

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub ArrayList al = newArrayList();

al.add(\);//依次添加元素 al.add(\); al.add(\); al.add(\); al.add(\); al.add(\); //在迭代的过程中,添加或是删除元素

ListIterator li = al.listIterator(); while(li.hasNext()){//列表迭代器的判断方法,

Object obj = li.next();//列表迭代器中的next方法。 if(obj.equals(\)){

li.add(\);//列表迭代器中的添加方法, //li.set(\列表迭代器中的修改功能。 }

sop(\+obj );//打印引用,返现显示原来的集合元素就是,添加仅仅是添加了引用,

}

/*while(li.hasPrevious()){从后往前遍历修改。 Object obj = li.previous(); if(obj.equals(\ li.set(\ } }*/

sop(al);//打印集合发现已经添加 } }

5.List子类的简单介绍

ArrayList:底层数据结构为数组,查询速度快,增删改速度慢,是线程不同步的 LinkedList:底层数据结构W为链表,查询速度慢,增删改速度快。

Vector:底层数据结构为数组,查询速度慢,增删改速度也慢,因为是线程同步的。 6.Vector容器中的枚举

Vector迭代器,遍历循环get方法,按照角标索引,枚举 package collection;

import java.util.Enumeration; import java.util.Vector; publicclass vectorDemo {

publicstaticvoid sop(Object obj){ System.out.println(obj); }

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub }

}

Vector v = newVector();//new一个VECTOR容器 v.add(\);//王容器里面加元素 v.add(\); v.add(\); Enumeration en = v.elements();//容器特有的迭代器---枚举! while(en.hasMoreElements()){

System.out.println(en.nextElement()); }

6.LinkedList中的方法介绍与代码示例 package collection;

import java.util.LinkedList; publicclass linkedListDemo {

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub LinkedList link = newLinkedList();

link.offerFirst(\);//每次都往头部添加

link.offerFirst(\);//1.6以前用addFirst link.offerFirst(\);

link.offerLast(\);//每次都往尾部添加 link.offerLast(\);//1.6以前用addLast link.offerLast(\); sop(link);

//1.6以前删除元素用removeFirst。区别:poll遇到空容器返回null,而remove则抛出异常。

sop(link.pollFirst());//删除原集合的头部元素,并且获取删除的元素。 sop(link.pollLast());//删除原集合尾部元素,并且获取删除的元素。

//1.6以前用getFirst,区别:peek遇到空容器返回null,而get则抛出异常。 sop(link.peekFirst());//获取头部元素不删除。 sop(link.peekLast());//获取尾部元素不删除。 }

publicstaticvoid sop(Object obj) { System.out.println(obj); } }

7.练习:用LinkedList模拟一个队列,堆栈的数据结构 队列:先进先出Queue 堆栈:先进后出Stack package collection;

import java.util.LinkedList;

class Queue//基于LinkedList类构建一个队列,意思就是要把它封装成一个类,对外暴露方法 {

privateLinkedListlink;

Queue(){//构造方法类加载而自动创建一个链表对象 link = newLinkedList(); }

publicvoid myAdd(Object obj){ link.offerFirst(obj); }

public Object myGet(){ returnlink.peekLast(); }

publicboolean myIsEmpty() {

returnlink.isEmpty(); } }

publicclass queueStack {

publicstaticvoid main(String[] args) {

}

}

// TODO Auto-generated method stub Queue q = new Queue(); q.myAdd(\); q.myAdd(\); q.myAdd(\);

System.out.println(q.myGet());

8.练习:去除ArrayList中的重复元素 package collection; import java.util.*;

class single{//讲方法封装成一个类

publicstaticArrayList getSingleElement(ArrayList al){ ArrayList ar = newArrayList(); for(Iterator it = al.iterator();it.hasNext();){ Object obj = it.next(); if(!ar.contains(obj)){//判断ar里面有没有obj ar.add(obj);//没有就加,有就不加。 } }

return ar; } }

publicclass SingleElement {

publicstaticvoid main(String[] args) { // TODO Auto-generated method stub ArrayList al = newArrayList(); al.add(\); al.add(\); al.add(\); al.add(\); System.out.println(single.getSingleElement(al)); } }

9.练习:将自定义对象存入ArrayList中并去除重复对象

东软java高级编程笔记

文件与流部分

File类

File类的构造方法:三种:

1.File变量名 = new File(String pathname); 2.File变量名 = new File(URI uri);

3.File 变量名 = new File(File parent,String child); Child位于parent路径下。

File只创建文件的引用,该文件是否存在与构造方法无关,File不能创建新文件 路径分隔符的写法:“/”

东软web编程笔记

JDBC连接异常说明,显示在console控制台上,

1.“no suitable driver found for”驱动器未找到异常,原因:驱动类名错误或是“jdbc:oracle:thin”这一部分语句错误,

2.“IO异常,the network adapter could not establish the connection ”IP或Port错误,原因:@localhost:1521语句错误。

3.”listener refused the connectionwith the following error:ora-12505”oracle的服务名错误,原因:服务器名应该与计算机服务列表中的“oracleservice?”的后面的词缀一致。

4.“ora-01017:invalid username/password;login denied”用户名或是密码错误。

5.”java.lang.ClassNotFoundException:Oracle.jdbc.OracleDriVER”,没有导入jar包,

jar包放到lib里面,因为

普通用户注册

1. 什么是Servlet?

Servlet其实就是运行在web服务器上的Java程序,这个Java程序也可以认为是一个类,与以前的类不同的是,以前的类都main函数调用, 而web开发阶段的类都是服务器调用的。这个类有两个参数:HttpServletRequest和HttpServletResponse。 2. Servlet API

Servlet接口genericServlet抽象类 HttpServlet类 自己建的类 (实现) (基于B/S结构)

ServletConfig VenderServletConfigImpl 3.servlet生命周期

Service() Init() destroy()

doGet() doPost()

初始化阶段 响应客户请求 销毁阶段 加载类,实例化Servlet,init()

每次生命周期初始化和销毁只执行一次。Init()方法被覆盖之后可以在登陆网页的时候初始化连接数据库。service()服务方法确定请求类型(也就是get,post),调用求方法。doGet和doPost方法理论上必须有一个被覆盖。 4. 配置Servlet

servlet的名字

servlet类 虚拟路径

?& 初始化值的设置可以直接在对应servlet类中用getInitParam的方法获取value

装载servlet的顺序。谁的数值小先加载谁!

5.获取客户报头信息

HTTP请求 = 请求行 + 请求头域 + 空行 + 请求数据

请求方法关键字 头标结束标志 post发送 请求URI 值对

HTTP版本 (提示客户端的功能与标识) 代码整理1:获取报头信息,写在doGet方法中

Enumeration names = request.getHeaderNames(); While(names.nhasMoreElement()) {

String name = names.nextElement();//报头名 String value = request.getHeader();//报头值 System.out.println(name + “:” + value); }

代码整理2:获取请求路径及URI,写在doGet方法 String ocntextPath = request.getContextPath(); String URI = request.getRequestURI();

System.out.println(“contextPath:”+ contextPath);//获取上下文根目录 System.out.println(“URI:”+ URI);//端口号后面的路径 代码整理3:获取HTTP请求的方法

String method = request.getMethod(); 代码整理4:获取IP

String ip = request.getRemoteAddr(); 6.获取注册页信息

请求的方法:get,post,head,options,put,delete,trace,7种

GET:不安全,编码限制,文件大小限制(几K),请求速度快,请求信息放在地址栏 POST:安全,支持编码多,文件大小基本无限制(分段),请求速度慢,请求信息放在主体中 获取信息的过程中,需要表单form的action和method属性。 代码整理5:获取注册页全部信息

String username = request.getParameter(“username”);

(来自网页的name) 7.调用Service类,完成注册功能。

(项目代码实现)

8.响应状态码

1**——请求收到,继续处理。 2**——请求成功。 3**——重定向

4**——客户端引发的错误。404:找不到文件目录;500:可能是重复请求 5**——服务器端引发的错误

9.为什么不能把接收表单输入的User对象标定义为实例变量?

答:为了解决并发访问问题,如果将表单输入的对象定义为实例变量,在并发访问时,多个用户访问一个对象,将造成后注册用户覆盖前面用户的注册内容,造成线程不安全,因此一般讲创建实例这样的而语句放在doPost方法块中,作为局部变量。

登陆基本功能

1. web资源跳转的两种方式?

Web资源跳转的方式有: 重定向(站外跳转) 工作过程:接到用户请求之后发送给用户一个URL,使客户按照提供的URL重新发出HTTP请求,请求方式为get方法。 方法:response.sendRedirect(String URL) 注意:重定向中路径最前面的“/”表示的是服务器根目录,不是上下文的根目录。

“user/index.jsp”这是相对路径,“/Myproject/user/index.jsp”这个是绝对路径,绝对路径会牵扯到换路径后不好使的情况。 请求转发(站内跳转) 工作过程:接收到用户请求之后,将请求转发到web应用内的其他资源进行处理。整个过程浏览器值发出了一次请求,接收到了一次响应。

方法:request.getRequestDespacther();

2. 响应重定向与请求转发的对比?

相同点:都是从webA响应到webB。

不同点:次数:响应重定向有两次请求两次转发,而请求转发有一次请求一次重定向。 性能:请求转发 的新歌能会高一些。

URL地址变化: 响应重定向地址栏会发生变化,请求转发地址栏还是指向原来的servlet。

跳转资源位置:请求转发只能发生在web应用程序的内部,而相应重定向可以到web的外部。 3. JSP简介:

JSP是Java server page的缩写

JSP中HTML的编写和维护更加方便;能够使用标准网页开发工具;能够明确开发人员分工,业务逻辑Java开发,表示逻辑web去开发。

理想状态下的JSP就是不包含Java代码和业务逻辑。

4. JSP实际上就是一种Servlet,因为JSP在处理请求之前,首先会被翻译为Servlet源

文件。

5. JSP的生命周期

翻译 编译

Web容器加载 实例化

jspInit()调用, jspService()调用 jspDestroy()调用

java代理模式(JDK和cglib) JAVA的动态代理 代理模式

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 按照代理的创建时期,代理类可以分为两种。

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

动态代理:在程序运行时,运用反射机制动态创建而成。

首先看一下静态代理: 1、Count.java

1. package net.battier.dao; 2. 3. /**

4. * 定义一个账户接口 5. *

6. * @author Administrator 7. * 8. */

9. public interface Count { 10. // 查看账户方法

11. public void queryCount(); 12.

13. // 修改账户方法

14. public void updateCount(); 15. 16. }

2、CountImpl.java

1. package net.battier.dao.impl; 2.

3. import net.battier.dao.Count; 4. 5. /**

6. * 委托类(包含业务逻辑) 7. *

8. * @author Administrator 9. * 10. */

11. public class CountImpl implements Count { 12.

13. @Override

14. public void queryCount() {

15. System.out.println(\查看账户方法...\); 16. 17. } 18.

19. @Override

20. public void updateCount() {

21. System.out.println(\修改账户方法...\); 22. 23. } 24. 25. } 26.

27. 、CountProxy.java

28. package net.battier.dao.impl; 29.

30. import net.battier.dao.Count; 31. 32. /**

33. * 这是一个代理类(增强CountImpl实现类) 34. *

35. * @author Administrator 36. * 37. */

38. public class CountProxy implements Count { 39. private CountImpl countImpl; 40. 41. /**

42. * 覆盖默认构造器 43. *

44. * @param countImpl 45. */

46. public CountProxy(CountImpl countImpl) { 47. this.countImpl = countImpl; 48. } 49.

50. @Override

51. public void queryCount() {

52. System.out.println(\事务处理之前\); 53. // 调用委托类的方法; 54. countImpl.queryCount();

55. System.out.println(\事务处理之后\); 56. } 57.

58. @Override

59. public void updateCount() {

60. System.out.println(\事务处理之前\); 61. // 调用委托类的方法; 62. countImpl.updateCount();

63. System.out.println(\事务处理之后\); 64. 65. } 66. 67. }

3、TestCount.java

1. package net.battier.test; 2.

3. import net.battier.dao.impl.CountImpl; 4. import net.battier.dao.impl.CountProxy; 5. 6. /**

7. *测试Count类 8. *

9. * @author Administrator 10. * 11. */

12. public class TestCount {

13. public static void main(String[] args) { 14. CountImpl countImpl = new CountImpl();

15. CountProxy countProxy = new CountProxy(countImpl); 16. countProxy.updateCount(); 17. countProxy.queryCount(); 18. 19. } 20. }

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 再来看一下动态代理:

JDK动态代理中包含一个类和一个接口: InvocationHandler接口:

public interface InvocationHandler {

public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; }

参数说明:

Object proxy:指被代理的对象。 Method method:要调用的方法 Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。 Proxy类:

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,

此类提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class[] interfaces,

InvocationHandler h)

throws IllegalArgumentException 参数说明:

ClassLoader loader:类加载器

Class[] interfaces:得到全部的接口

InvocationHandler h:得到InvocationHandler接口的子类实例 Ps:类加载器

在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\\lib\\ext目录中的类;

AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 动态代理

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。

java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 动态代理示例: 1、BookFacade.java

1. package net.battier.dao; 2.

3. public interface BookFacade { 4. public void addBook(); 5. }

2、BookFacadeImpl.java

1. package net.battier.dao.impl; 2.

3. import net.battier.dao.BookFacade;

4.

5. public class BookFacadeImpl implements BookFacade { 6.

7. @Override

8. public void addBook() {

9. System.out.println(\增加图书方法。。。\); 10. } 11. 12. } 13.

14. 、BookFacadeProxy.java 15.

16. package net.battier.proxy; 17.

18. import java.lang.reflect.InvocationHandler; 19. import java.lang.reflect.Method; 20. import java.lang.reflect.Proxy; 21. 22. /**

23. * JDK动态代理代理类 24. *

25. * @author student 26. * 27. */

28. public class BookFacadeProxy implements InvocationHandler { 29. private Object target; 30. /**

31. * 绑定委托对象并返回一个代理类 32. * @param target 33. * @return 34. */

35. public Object bind(Object target) { 36. this.target = target; 37. //取得代理对象

38. return Proxy.newProxyInstance(target.getClass().getClassLoader(), 39. target.getClass().getInterfaces(), this); //要绑定接口(这是

一个缺陷,cglib弥补了这一缺陷) 40. } 41.

42. @Override 43. /**

44. * 调用方法 45. */

46. public Object invoke(Object proxy, Method method, Object[] args)

本文来源:https://www.bwwdw.com/article/0v8o.html

Top