JavaSE和 Sql复习

封装:

  1. 对外隐藏复杂的实现细节,暴露出简单的使用方法。
  2. 提高代码重用性
  3. 隔离变化
  4. 保护数据。

 

 

将一个10进制的数字,转换为2进制。

 

 

进行封装:

 

以上代码其实有bug!

 

为了重用性再次封装一把!

 

 

随着作者技术水平的提升,作者会觉得以前的代码太low

作者为了优化以上代码,使用位运算。

 

算法如下:

 

 

 

 

还有一个问题,就是那个transfer方法,不应该暴露给用户! why?  

Transfer方法一旦暴露出去,则后期改动起来,不方便! 注意,下面把transfer方法的访问修饰符改为了private!

 

 

 

保护数据的例子:

 

 

 

 

继承:

 

定义一个学生类、超人类

class Student {

String name;

String gender;

int age;

 

void eat() {

System.out.println("吃KFC");

}

void study() {

System.out.println("锲而不舍,金石可镂!");

}

}

 

 

class SuperMan {

String name;

String gender;

int age;

 

void eat() {

System.out.println("吃10碗泡馍!");

}

 

void fly() {

System.out.println("拜拜了您那!");

}

}

 

发现,学生类与超人类中,有相同的属性和方法! 将来定义的类还有律师类,条子类,城管类... 都需要name gender age属性,难道说,都要在每个类中写一遍?

 

所以,应该使用继承:

 

如何判断两个类之间能不能发生继承关系:原则就是判断两个类之间有没有”is a”关系

 

波斯猫, 有继承关系。

三角形 等边三角形, 有继承关系。

学生 超人 没有继承关系

显像管 电视机 没有继承关系

儿子 父亲 没有继承关系

 

继承的另外一个作用是 多态的前提。

 

总结继承:

  1. 提高代码重用性
  2. 多态的前提

 

 

多态:  多种表现形态。

比如: 人表现为 男人 女人 老人 好人 坏人。

比如: 动物表现为 熊猫 ...

 

预备知识: 向上转型.

向上转型就是一个父类引用指向了子类的对象。

可以理解为把子类当作父类看待

把老师当作普通人

把西安人当作中国人

把中国人当作地球人

 

向上转型的语法特点

A. 向上转型发生后,子类独有的方法和属性无法使用.

B. 向上转型发生后

调用的方法只与new的对象有关(动态绑定).

调用的静态方法只与引用类型有关(静态绑定).

调用的属性只与引用类型有关(静态绑定).

 

向下转型:

把一个父类类型的对象,强制类型转换为子类类型。

向下转型的前提是,先向上转型!!

 

 

 

人演奏乐器的例子:

 

package com.chinasofti.test;

class Person {

public void play(Piano p) {

System.out.println("开始演奏...");

p.sound();

}

public void play(Guitar g) {

System.out.println("开始演奏...");

g.sound();

}

public void play(Drum d) {

System.out.println("开始演奏...");

d.sound();

}

}

class Piano {

public void sound() {

System.out.println("一闪一闪亮晶晶...");

}

}

 

// ==========================================================

 

class Guitar {

public void sound() {

System.out.println("光辉岁月");

}

}

class Drum {

public void sound() {

System.out.println("二泉映月");

}

}

public class Demo2 {

public static void main(String[] args) {

Piano piano = new Piano();

Guitar guitar = new Guitar();

Drum drum = new Drum();

Person p = new Person();

p.play(piano);

p.play(guitar);

p.play(drum);

}

}

 

吐槽:

该程序没有任何扩展性可言!! 每次用户额外添加一个乐器,都不得不要求作者重载一次play方法,这样不好,很麻烦!!!

 

进化以上代码:

package com.chinasofti.test;

 

class Instrument {

public void sound() {

System.out.println("发出声音..");

}

}

class Person {

public void play(Instrument i) {

System.out.println("开始演奏...");

i.sound();

}

}

class Piano extends Instrument {

public void sound() {

System.out.println("一闪一闪亮晶晶...");

}

}

 

// ==========================================================

 

class Guitar extends Instrument {

public void sound() {

System.out.println("光辉岁月");

}

}

class Drum extends Instrument {

public void sound() {

System.out.println("二泉映月");

}

}

class DiZi extends Instrument {

public void sound() {

System.out.println("笑傲江湖");

}

}

 

public class Demo2 {

public static void main(String[] args) {

Piano piano = new Piano();

Guitar guitar = new Guitar();

Drum drum = new Drum();

DiZi dizi = new DiZi();

Person p = new Person();

p.play(piano);

p.play(guitar);

p.play(drum);

p.play(dizi);

}

}

 

优点,以上代码,确实提高了扩展性。

吐槽:父类Instrumentplay方法,算是白写了!

 

继续优化:

package com.chinasofti.test;

 

abstract class Instrument {

public abstract void sound();

}

class Person {

public void play(Instrument i) {

System.out.println("开始演奏...");

i.sound();

}

}

class Piano extends Instrument {

public void sound() {

System.out.println("一闪一闪亮晶晶...");

}

}

 

// ==========================================================

 

class Guitar extends Instrument {

public void sound() {

System.out.println("光辉岁月");

}

}

class Drum extends Instrument {

public void sound() {

System.out.println("二泉映月");

}

}

class DiZi extends Instrument {

public void sound() {

System.out.println("笑傲江湖");

}

}

 

public class Demo2 {

public static void main(String[] args) {

Piano piano = new Piano();

Guitar guitar = new Guitar();

Drum drum = new Drum();

DiZi dizi = new DiZi();

Person p = new Person();

p.play(piano);

p.play(guitar);

p.play(drum);

p.play(dizi);

}

}

 

优点,父类Instrument中的sound不用写方法体了(写了也白写)

吐槽:因为java中是单继承,一个类只能有一个父类! 如果此时用户想让自定义的乐器继承其它类,就不行! 为了避免单继承的限制,需要把Instrument改为接口!

 

 

优化以上代码:

package com.chinasofti.test;

 

interface Instrument {

public void sound();

}

class Person {

public void play(Instrument i) {

System.out.println("开始演奏...");

i.sound();

}

}

class Piano implements Instrument {

public void sound() {

System.out.println("一闪一闪亮晶晶...");

}

}

 

// ==========================================================

 

class Guitar implements Instrument {

public void sound() {

System.out.println("光辉岁月");

}

}

class Drum implements Instrument {

public void sound() {

System.out.println("二泉映月");

}

}

class A {

}

class DiZi extends A implements Instrument {

public void sound() {

System.out.println("笑傲江湖");

}

}

 

public class Demo2 {

public static void main(String[] args) {

Piano piano = new Piano();

Guitar guitar = new Guitar();

Drum drum = new Drum();

DiZi dizi = new DiZi();

Person p = new Person();

p.play(piano);

p.play(guitar);

p.play(drum);

p.play(dizi);

}

}

 

 

 

接口的作用:

  1. 提高代码扩展性()
  2. 统一访问

当接口的实现类替换掉以后,调用的方法没有任何变化,这一点叫做统一访问。

  1. 完全解耦

高耦合:替换起来不容易。

一个人睡觉认床。

一个人一辈子只喜欢一个人。

一个5头插销,只能用于5孔插座。

低耦合:替换起来很容易

一个人见床就能睡床。

一个人见一个爱一个。

一个2头插销能用于任何2空插座。

 

代码中的完全解耦如何理解?

  1. 一个类能实现多少个接口? 无数个。
  2. 一个接口能被多少个类实现? 无数个。

如果一个变量的类型是接口类型,则该变量能接收无数个接口的实现类。

 

 

 

Orcale复习:

 

ed,用于命令行,

1)作用是打开一个可编辑的文档.

2)ed中总是存放上一条sql命令

3)在命令行中直接输入 / 回车,就会自动执行ed中的sql命令!

4)我们可以修改ed中的命令,然后再使用/来执行。

5)save 数字, 表示把目前的ed中的代码存盘!

  1. 比如 save 1, 就是把ed中的代码存入1.sql文件中。
  2. 下次可以写ed 1打开1.sql文件
  3. 注意,1.sqled打开的是2个不同的文件!
  4. @ 数字,可以指定要执行的文件!

 

 

分区表:

 

问题:如果dept表有1000万行记录,则以下条件执行几次?

select * from dept where dname =abc;

1000w次!! 针对每一行都判断一次! 这叫做全表扫描! 这样不好! 效率太低!!

 

为了解决以上问题,才需要分区表!

 

select * from users partition(少年);  只在少年分区中查询! 这样能缩小查询范围,从而提高查询速度!!

 

 

修改日期格式:

 

 

 

 

事务(重点):

什么是事务:就是一系列步骤,要么都执行,要么都不执行!

事务的4大特性:

原子性:就是一系列步骤,要么都执行,要么都不执行!

一致性:在事务执行前后,数据库中的数据在逻辑上保持一致!

隔离性:并发情况下,一个事务对另外一个事务的影响。

4个隔离级别(oralce中只有2个隔离级别)

持久性: 事务一旦提交或者回滚,对数据库的操作就会一直保存下去,任何设备故障、断电都不会影响数据的存储!

 

 

事务操作:

开启事务:

Oracle中,事务是隐式事务,也就是在一个新事务中执行DML语句的时候,就会自动开启事务!

 

提交事务

回滚事务

 

 

 

 

一旦回滚就算事务结束!

 

 

事务保存点:

savepoint 保存点名字(符合标识符命名规则)

rollback to 保存点名字

 

 

 

Oracle中有以下两种锁

  1. 共享锁
  2. 排他锁

 

共享锁与共享锁之间能相互兼容

排他锁与任何锁不兼容

 

select语句默认不加任何锁!

DMLinsert delete update)语句会自动加排它锁!

 

所有锁,在事务结束时,自动释放!

 

例子,演示排它锁与排它锁之间不兼容:

 

 

当左边的事务结束(要么提交,要么回滚),锁就释放了!

 

 

 

测试:select与排它锁是否兼容

测试结果,因为select压根就不加锁,所以没有任何冲突!

 

我们已经知道select默认不加任何锁!其实我们可以强制让select语句也能加排他锁:

How:  

 

 

如何添加共享锁?

不像排它锁那样,使用DML语句或select..for update就能自动添加

共享锁有单独的语法:  lock table 表名 in share mode

 

 

测试共享锁,与共享锁是否兼容:

 

 

悲观锁 乐观锁

  1. 不是什么新东西,没有新语法。
  2. 悲观锁就是,查询数据之前,总觉得别的事务会修改我要看的数据。

   所以,在每次查询数据之前,都把表锁住的这种情况,称之为“悲观锁”

  1. 乐观锁,查询数据之前,总觉得没有人会修改我要看的数据。

   在每次查询数据之前,都不加锁,直到提交数据的那一刻,才检查是否有锁的冲突(后面讲到JDBC再说。)

 

行级锁, 表级锁。

 

行锁,就是只锁住表中的某些行,并不是锁住整表!

 

 

表锁,就是把整个表锁住!

Lock table in share(共享)/exclusive(排他) mode

 

 

面试题

for update for update of的区别

 

 

 

 

 

 

for udpate nowait 表示如果获取不到资源就潇洒地走开! 抛出一个异常!

 

 

 

 

Oracle数据库的事务隔离级别默认有2种(SQL标准中有4种!)

  1. 读已提交(默认级别)

a) 保证一个事务不能读取到另外一个事务还没有提交的数据!

 

在读已提交的隔离级别之下,有一个问题:不可重复读.

 

所谓不可重复读,就是,在同一次事务之间,两次完全相同的查询语句,查出了不同的数据!

 

 

 

  1. 序列化

a) 保证一个数据,同一时刻只能有一个事务操作!(就好像是单机程序一样,完全没有并发!)

 

 

为了避免不可重复读的问题,需要把隔离级别设置为 serializable

set transaction isolation level serializable

 

 

多表连接查询。

 

笛卡尔积

(a+b)(c+d)=ac+ad+bc+bd;

 

笛卡尔积模型演示:

 

笛卡尔积的特点就是,管他三七二十一,先弄个大表再说!

 

进一步,我们要在大表的基础之上,留下有用的行,去掉没有用的行:

有用的行,就是外键与主键相等的行。

没有用的行,就是外键与主键不相等的行。

 

然后,随便筛选列就行!(投影)

 

 

 

禁止使用笛卡尔积,因为搞一张大表,实在是太浪费内存空间了!(太2了!!)

 

应该使用内连接!!

 

 

内连接

内连接是一边拼接,一边判断,只有条件成立,才把拼接的行存入最终的结果集中!

这样就能避免大表的产生!

 

 

 

外连接

 

左外连接  右外连接

 

完全外连接

 

 

 

自然连接:

 

 

 

分组:

 

 

 

 

举一反三:

 

 

举一反三:

 

 

 

查询闰年入职的员工

 

 

查询在当月倒数第8天输入的员工:

 

 

问题:

 

4. 查询每个部门的平均月薪

select  deptno,avg(sal) from emp

group by deptno

  1. 查询每个月各入职多少人

select extract(month from hiredate),count(1) from emp

group by extract(month from hiredate);

 

6. 查询月薪大于1500的员工中,每个部门各多少人

select deptno,count(1) from emp

where sal > 1500

group by deptno

 

7. 查询没有奖金的员工中,每个职位的最高月薪。

select job,max(sal) from emp

where comm is null

group by job

 

 

8. 查询上级不是7566的员工中,每个部门的最低月薪。

select deptno,min(sal) from emp

where mgr != 7566

group by deptno

 

  1. 查询月薪比20部门平均月薪低的员工中,每个部门多少人。

select deptno,count(*) from emp

where sal < (

      select avg(sal) from emp

      where deptno = 20

)

group by deptno

 

 

 

10. 查询部门人数超过2人的部门.

select deptno,count(*) from emp

group by deptno

having count(*) > 2

  1. 查询平均月薪小于2000的部门

select deptno,avg(sal) from emp

group by deptno

having avg(sal) < 2000

posted @ 2017-12-07 15:18  Evan789  阅读(249)  评论(0编辑  收藏  举报