面试(Java)

1 篇文章 0 订阅

http://blog.csdn.net/qq_34120041/article/details/67636202
http://www.cnblogs.com/xrq730/p/5260294.html
https://blog.csdn.net/qq_33314107
这里写图片描述
刷题是为了检测自己学习成果
面试准备需要提前准备一个月
没有平庸的项目只有平庸的人

阿里高级Java面试题(首发,70道,带详细答案)
2017派卧底去阿里、京东、美团、滴滴带回来的面试题及答案
Spring面试题(70道,史上最全)
支付宝系统架构
年末干货!Java技术栈2017年度精选干货总结
阿里巴巴,排行前10的开源项目
2018年必看:关于区块链技术的10本书
天猫双十一是怎么保证高并发、分布式系统中,数据一致性的?
字节跳动抖音社招后台开发工程师面经

  • 亮点总结

分布式

Redis的那些最常见面试问题
Redis常见面试题
redis过期机制
redis做消息队列
消息队列面试题
分布式事务面试题
2pc和3pc
zk面试
NWR理论与强一致性
通俗易懂 强一致性、弱一致性、最终一致性、读写一致性、单调读、因果一致性 的区别与联系
向量时钟算法
过去这几十年,分布式系统的「数据一致性」精华都在这了!
常用的分布式事务解决方案介绍有多少种?
*分布式锁通常有三种实现方式:

  1. 数据库悲观锁;?
  2. 根据ZooKeeper的分布式锁;?
  3. 基于Redis的分布式锁;?

*软件分层的原因是为了实现"高内聚、低耦合"。把问题划分开来各个解决,易于控制,易于延展,易于分配资源。

*CAP原则是指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。

*分布式锁之redis实现方式,除此之外,还有另一种方法,通过redis提供的lua脚本保证线程安全链接

*mq如何保证消息的幂等性

*如何保证消息不重复消费

*深入了解幂等性

*乐观锁一般使用version字段或者timestamp(时间戳)或者使用条件限制解决并发问题>>原文内容

*Dubbo中服务消费者和服务提供者之间的请求和响应过程

*dubbo的心跳机制
目的:检测provider与consumer之前的connection连接是不是连接着的,如果连接断了,需要作出相应的处理.
原理:provider:dubbo的心跳默认是在heatbeat(默认60s)内如果没有接收到消息,就会发送心跳消息,如果连着3次(180s)没有收到心跳响应,provider会关闭channel
consumer:dubbo的心跳默认是在60s内如果没有接收到消息,就会发送心跳消息,如果连着3次(180s)没有收到心跳响应,consumer会进行重连.
原文内容

RPC和RMI的区别

Java部分

*为什么说 Java 是编译与解释共存的语言。
我们需要格外注意的是 .class->机器码 这一步。在这一步 【JVM 类加载器】首先加载字节码文件,然后通过【解释器】逐行解释执行,这种方式的执行速度会相对比较慢。而且,有些方法和代码块是经常需要被调用的(也就是所谓的热点代码),所以后面引进了【 JIT 编译器】,而 JIT 属于运行时编译。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。而我们知道,机器码的运行效率肯定是高于 Java 解释器的。这也解释了我们为什么经常会说 Java 是编译与解释共存的语言。

*阐述实体对象的三种状态以及转换关系?在这里插入图片描述
*StackOverflowError:递归过深,递归没有出口(一个线程对应至少一个栈,递归过深)。
OutOfMemoryError:JVM空间溢出,创建对象速度高于GC回收速度。

*虚拟机栈:临时变量和部分结果,一线程一堆栈
本地方法栈:提供给native方法的栈
堆:存储对象
方法区:运行时常量池,字段和方法数据,方法和构造函数代码,编译代码存储,方法区仅仅只是逻辑上独立,实际上还是包含在Java堆区的,也就是说,方法区在物理上当然属于Java堆区的一部分
寄存器:计数器

*hashcode 方法和 equals 方法均已按规范重写时

*当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里是值传递还是引用传递?
是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的内存地址。这个值(内存地址)被传递后,同一个内存地址指向堆内存当中的同一个对象,所以通过哪个引用去操作这个对象,对象的属性都是改变的。

hashcode相等,两个类不一定相等(存在哈希冲突)
equals返回true的两个类一定相等
两个类相等hashcode一定相等
两个类相等equals一定返回true

*HashMap为什么要重写 hashcode 和 equals 方法?
自定义hashMap的key的时候,在hashMap.put key和value的时候,会先对key做hash计算,因为没有重写key的hash方法,所以会默认使用Object的hash方法,而Object默认的hash方法是通过地址来计算的,所以也就导致了存入的key其实是不一致的,所以就导致取出的值不一致。如果只重写key的hash方法,按理说就不会出现取不出值的情况,但是对key取hash值对时候可能存在hash冲突的情况,所以同时得重写equals方法保证key一定是一样的。

*向上转型和向下转型

*禁止指令重排序
指令重排序有利于多核处理器同时处理任务,避免了处理器资源的浪费,但多线程的情况下,禁止指令重排序是为了保证结果的正确。
线程的可见性问题是指,在副线程运行之后,主线程修改了全局变量的值,但对于副线程而言,副线程中的全局变量仍为旧值,所以副线程所做的一切都是错误的。

*强引用、软引用、弱引用、虚引用

*序列化的作用
简单的说,就像你要搬一个东西,为了好搬,你先把这个东西拆散,搬到了之后再组合起来,java对象序列话也是为了对象便于"传输",下面几种情况会用到序列话:
a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;

*char 型变量中能不能存储一个中文汉字,为什么?
char 类型可以存储一个中文汉字,因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个char 类型占2个字节(16 比特),所以放一个中文是没问题的。

补充

*转发和跳转的小结
1、转发使用的是getRequestDispatcher()方法;重定向使用的是sendRedirect(); 2、转发:浏览器URL的地址栏不变。重定向:浏览器URL的地址栏改变;
3、转发是服务器行为,重定向是客户端行为;
4、转发是浏览器只做了一次访问请求。重定向是浏览器做了至少两次的访问请求;
5、转发2次跳转之间传输的信息不会丢失,重定向2次跳转之间传输的信息会丢失(request范围)。

*jdbc编程流程
1.第1步:注冊驱动 (仅仅做一次) D
第2步:配置jdbc连接的URL地址 U
第3步:建立连接(Connection) C
第4步:创建运行SQL的语句(Statement) S
第5步:运行SQL语句 S
第6步:处理运行结果(ResultSet) R
第7步:关闭连接 C

springboot之拦截器与过滤器

*Spring AOP底层实现原理》原理1原理2
Spring IOC底层实现原理》原理1
Spring框架IOC和AOP的实现原理
Spring AOP管理事务》XML/annotation
动态代理的几种方式>>动态代理
cglib代理与JDK中的代理比较:
JDK动态代理: 只能代理实现了接口的类
没有实现接口的类不能实现JDK动态代理。
Cglib代理: 针对类来实现代理,对指定目标
产生一个子类 通过方法拦截技术拦截所有父类方法的调用。
我们要使用cglib代理必须引入 cglib的jar包

*① 为什么要使用动态代理
在编程中我们希望自己的代码是灵活的而不是死板的,能动态配置的东西就不要写死。这样来提高程序的可扩展性。如果不使用代理模式,将来我们想在当前的业务逻辑下添加一些其他的处理,比如日志、校验等等,就不得不侵入原有的业务代码。而这些操作其实和真正的业务无关,我们不想它们侵入业务代码。这时候就需要使用代理模式登场了。我们通过代理来调用原有的业务代码,又可以在业务逻辑之前和之后添加一些其他的逻辑。
②然而为什么要用动态代理?
考虑以下各种情况,有多个提供类,每个类都有getXxx(String name)方法,每个类都要加入缓存功能,使用静态代理虽然也能实现,但是也是略显繁琐,需要手动一一创建代理类。

*JAVA内存泄漏和内存溢出的区别和联系
内存泄漏是在申请内存时,对应的内存未释放,内存溢出是放到对应内存中的数据超出内存大小
内存泄漏的类型:常发性,偶发性,一次性,隐式
内存溢出原因:
1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2.集合类中有对对象的应用,使用完后未清空,使得jvm不能回收;
3.代码中存在死循环或循环产生过多重复的对象实体;
4.使用的第三方软件中的bug;
5.启动参数内存值设定得过小;
内存溢出的解决方案:
第一步,修改jvm启动参数,直接增加内存
第二步,检查错误日志,查看oom错误前是否有其他异常或错误
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置.
重点排查一下几点
1.检查对数据库查询中,是否有一次获得全部数据的查询.
2.检查代码中是否有死循环/递归调用
3.检查是否有大循环重复产生新对象实体
4.检查List,Map等集合对象是否有使用完未清除的问题
5.使用内存查看工具动态查看内存使用情况,如jstack,JVisualVM等

java内存溢出类型:
1.Java Heap 溢出
2.虚拟机栈和本地方法栈溢出
3.运行时常量池溢出
4.方法区溢出
原文

*Lock与synchronized有以下区别:

Lock是一个接口,而synchronized是关键字。
synchronized会自动释放锁,而Lock必须手动释放锁。
Lock可以让等待锁的线程响应中断,而synchronized不会,线程会一直等待下去。
通过Lock可以知道线程有没有拿到锁,而synchronized不能。
Lock能提高多个线程读操作的效率。
synchronized能锁住类、方法和代码块,而Lock是块范围内的

*linux查看文件命令,grep,cat,tac,less,more,nl,head
cat和tac刚好相反,cat从第一行开始,tac从最后一行开始
less命令允许用户向前或向后浏览文件,而more命令只能向前浏览
head用于显示文件的开头内容.默认情况下,显示文件头10行内容

*ps命令:可以查看进程的瞬间信息。
top命令:可以持续的监视进程的信息。

*CAS算法的原理就是里面包含三个值:内存值V,预估【旧值】E 更新值U 当且仅当V==E时,V=U; 否则,不会执行任何操作。
原文内容
利用cas实现自旋锁

public class SpinLock {

  private AtomicReference<Thread> sign =new AtomicReference<>();

  public void lock(){
    Thread current = Thread.currentThread();
    while(!sign .compareAndSet(null, current)){
    }
  }

  public void unlock (){
    Thread current = Thread.currentThread();
    sign .compareAndSet(current, null);
  }
}

synchronized和ReentrantLock都是可重入锁
ReentrantLock 和 synchronized 不一样,需要手动释放锁,所以使用 ReentrantLock的时候一定要手动释放锁,并且加锁次数和释放次数要一样

*AtomicReference,AtomicStampedReference与AtomicMarkableReference的区别:
AtomicReference是自旋锁应用的类,他的类型是引用类型,但是会出现ABA问题,AtomicStampedReference和AtomicMarkableReference就是为了解决这个问题,AtomicStampedReference通过采用int作为时间戳(一般做成自增的,如果时间戳如果重复,还会出现ABA的问题。AtomicMarkableReference则只是做标记,返回值为布尔值,只关心是否相同,不关心修改过几次。

*CAS的缺点:
1) CPU开销过大
在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。
2) 不能保证代码块的原子性
CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。

*垃圾收集器的演进
在这里插入图片描述
*常见的垃圾回收算法:1.标记-清除法,2.复制算法,3.标记-整理法;分代回收算法只是根据对象存活周期的不同将内存划分为几块。一般是把堆划分为新生代和老年代,这样就可以根据各个年代的特点采用最适合的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或者“标记-整理”算法来进行回收.

*并发收集器和并行收集器的区别

并行收集器(parallel)
多条垃圾收集线程同时进行工作,此时用户线程处于等待状态

并发收集器(concurrent)
指多条垃圾收集线程与用户线程同时进行(但不一定是并行的,有可能交替进行工作)

如cms就是典型的并发收集器

*cms重新标记和g1最终标记的区别

*CMS收集器和G1收集器的区别
区别一: 使用范围不一样
CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用

G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用

区别二: STW的时间
CMS收集器以最小的停顿时间为目标的收集器。

G1收集器可预测垃圾回收的停顿时间(建立可预测的停顿时间模型)

区别三: 垃圾碎片
CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片

G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片。

区别四: 垃圾回收的过程不一样
CMS收集器 G1收集器

  1. 初始标记 1.初始标记
  2. 并发标记 2. 并发标记
  3. 重新标记 3. 最终标记
  4. 并发清除 4. 筛选回收

cms和g1的执行过程和区别

*cms重新标记和g1最终标记的区别
cms的重新标记不会标记并发标记期间产生的垃圾,所以不能处理浮动垃圾,宁愿放到下次回收处理,也不愿错删.
G1的最终标记并发运行期间产生的垃圾,所以能处理浮动垃圾
在这里插入图片描述

*跨代引用解决办法在这里插入图片描述

*说说Mysql的隔离级别,哪个事务隔离级别最高?什么是脏读,脏读是对一个事务来说的,还是多个事务来说的? 参考一参考二
mysql有四个隔离级别,分别是【读未提交】,【不可重复读】,【可重复读】,【串行化】;脏读是对两个事务来说的。

*你觉得HBase与Mysql的区别是什么?
hbase和mysql的区别》原文内容
为什么HBase支持百亿级的行存储而Mysql不行。
hbase只支持简单查询。mysql复杂查询.

*hibernate有一级缓存,为什么还要二级缓存?
一级缓存只对当前session可见。
二级缓存作用域则可以跨越多个session,当一些数据不常发生变化或者允许偶尔的并发的时候,二级缓存可能更有效率,因为它的缓存时间更久,不会像一级缓存一样一旦session销毁就销毁。
Mybatis一级缓存作用域是session,session commit之后缓存就失效了

Mybatis二级缓存作用域是sessionfactory,该缓存是以namespace为单位的(也就是一个Mapper.xml文件),不同namespace下的操作互不影响。所有对数据表的改变操作都会刷新缓存。但是一般不要用二级缓存,例如在UserMapper.xml中有大多数针对user表的操作。但是在另一个XXXMapper.xml中,还有针对user单表的操作。这会导致user在两个命名空间下的数据不一致。如果在UserMapper.xml中做了刷新缓存的操作,在XXXMapper.xml中缓存仍然有效,如果有针对user的单表查询,使用缓存的结果可能会不正确,读到脏数据。

*MyBatis定义的接口,怎么找到实现的?
1.Mapper接口在初始SqlSessionFactory注册
2.Mapper接口注册在了名为MapperRegistry类的HashMap中,key=MapperClassValue=创建当前Mapper的工厂
3.Mapper注册之后,可以从SqlSession中get
4.SqlSession.getMapper运用了JDK动态代理,产生了目标Mapper接口的代理对象
5.动态代理的代理类是MapperProxy,这里边最终完成了增删改查方法的调用

Redis比之一、二级缓存的好处很多,Redis可以搭建在其他服务器上,缓存容量可扩展。Redis可以灵活的使用在需要缓存的数据上,比如一些热点数据。

*什么样的数据适合存放到第二级缓存中?
1、很少被修改的数据
2、不是很重要的数据,允许出现偶尔并发的数据
3、不会被并发访问的数据
4、参考数据
不适合存放到第二级缓存的数据?
1、经常被修改的数据
2、财务数据,绝对不允许出现并发
3、与其他应用共享的数据。

*private、默认、protected、public作用范围
1)private,同类
2)默认,同类、同包
3)protected,同类,同包,子类
4)public,所有

*String直接赋值和new String()的区别:https://www.cnblogs.com/qiaoyanlin/p/6877628.html

*Java基础之三大特性
1、封装:
概念:隐藏对象的成员变量和方法,只对外提供公共的访问方式
优点:将变化隔离、便于使用、提高复用性、提高安全性
2、继承:
优点:提高代码复用性,同时继承是多态的前提
注意:子类所有的构造函数都会默认访问父类中的空参数的构造函数,默认第一行有super(),若无空参数构造函数,需要在子类中指定
3、多态:顾名思义同种引用不同的实现
环境:父类或接口的引用变量可以指向子类或具体实现类的实例对象
有点:提高程序的扩展性
弊端:父类引用指向子类对象时,虽然提高了扩展性,但只能访问父类中具备的方法,不可以方法问子类中的方法。访问局限性。

*事务的四大特性(ACID):
1.原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。
2.一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态。
3.隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务是不可见的。
4.持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。

继承和多态的区别
继承,子类继承父类中所以的属性和方法,但是对于private的属相和方法,由于这个是父类的隐私,所以子类虽然是继承了,但是没有可以访问这些属性和方法的引用,所以相当于没有继承到。很多时候,可以理解为,没有继承。
多态:就是父类引用可以持有子类对象。这时候只能调用父类中的方法,而子类中特有方法是无法访问的,因为这个时候(编译时)你把他看作父类对象的原因,但是到了运行的时候,编译器就会发现这个父类引用中原来是一个子类的对像,所以如果父类和子类中有相同的方法时,调用的会是子类中的方法,而不是父类的(即重载)。
可以这么说:编译时看父类,运行时看子类。

*抽象类与接口的异同
https://blog.csdn.net/wangxin1982314/article/details/70804793
同:具有抽象方法
异:
1)抽象类可以有构造器,非抽象方法,非公有属性,仅可以单继承抽象类
2)接口仅有公有抽象方法或者公有静态常量,可以同时实现多个接口

通俗说法:接口比抽象类更抽象(接口不能有属性,只能有方法,但抽象类可以,抽象类还可以有具体实现的方法,接口则只能有抽象方法),对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。
个人使用经验:一般在控制层使用抽象类,提取公共初始化方法、框架定制化工具方法等
一般会在业务层使用接口

*重写和重载的区别
重写方法的规则:
1)、参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。
2)、返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。
3)、访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4)、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:
父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。

重载的规则:
1)、必须具有不同的参数列表;
2)、可以有不同的返回类型,只要参数列表不同就可以了;
3)、可以有不同的访问修饰符;
4)、可以抛出不同的异常;

*Super关键字:super和this关键字都可以用来覆盖Java语言的默认作用域,使被屏蔽的方法或变量变为可见。
父类的成员变量和方法为private使用super访问编译出错
在类的构造方法种,通过super语句调用这个类的父类的构造方法
在子类种访问父类的被屏蔽的方法和属性
只能在构造方法或实例方法内使用super关键字,而在静态方法和静态代码块内不能使用super

5、多态:
对于一个引用类型的变量,Java编译器按照它的声明的类型来处理
对于一个引用类型的变量,运行时Java虚拟机按照它的实际引用的对象来处理
运行时环境中,通过引用类型变量来访问所引用对象的方法和属性时,Java虚拟机采用以下绑定规则
1)实例方法与引用变量实际引用的对象的方法绑定,属于动态绑定
2)静态方法与引用变量所声明的类型的方法绑定,属于静态绑定
3)成员变量(包括静态和实例变量)与引用变量所声明的类型的成员变量绑定,属于静态绑定
6、继承的利弊和使用原则:
集成数的层次不可太多
集成数的上层为抽象层
1)定义了下层子类都用友的相同属性和方法,并且尽可能默认实现,从而提高重用性
2)代表系统的接口,描述系统所能提供的服务
继承关系最大的弱点:打破封装
精心设计专门用于被继承的类
1)对这些类必须提供良好的文档说明
2)尽可能的封装父类的实现细节,把代表时间细节的属性和方法定义为private类型
3)如果某些实现细节必须被子类访问,定义为protected类型
4)把不允许子类覆盖的方法定义为final类型
5)父类的构造方法不允许调用可被子类覆盖的方法
6)如果某些类不是专门为了继承而设计,那么随意继承它是不安全的

*ArrayList和LinkedList的大致区别:
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

*HashMap的数据结构>>原文内容
在这里插入图片描述
首先将高16位无符号右移16位与低十六位做异或运算。如果不这样做,而是直接做&运算那么高十六位所代表的部分特征就可能被丢失 将高十六位无符号右移之后与低十六位做异或运算使得高十六位的特征与低十六位的特征进行了混合得到的新的数值中就高位与低位的信息都被保留了 ,而在这里采用异或运算而不采用& ,| 运算的原因是 异或运算能更好的保留各部分的特征,如果采用&运算计算出来的值会向1靠拢,采用|运算计算出来的值会向0靠拢

接下来将得到的值与与0xf做&运算 目的是得到后四位的数值,得到后四位的下标在0~15之间 对应的放在哪个桶里面,当然这里存在扩容的问题,根据实际情况确定桶的个数

hashMap的存储机制实际上是数组加链表,在这里数组就代表桶的数量 检索时一次性就可以排除掉n-1个区间

*List、Set、Collections区别
1)List,有序可重复
2)Set, 无序不可重复
3)Collections,集合工具类

*TreeSet去重原理
1,treeSet去重原理:compareTo
可以实现排序及去重:如果compareTo返回0,说明是重复的,返回的是自己的某个属性和另一个对象的某个属性的差值,如果是负数,则往前面排,如果是正数,往后面排;

应用:类实现compareable接口,覆写其compareto方法,根据自己的需要改变其排序及去重规则,比如person类,根据其年龄进行去重和排序

2,hashSet去重原理:1,hashCode 2,equals是否相同
两个方法可以快速生成,hashCode是几个属性的hashCode共同计算的结果
(基本数据类型的实现类生成的hashCode是其拆箱后的值的比较,跟引用数据类型的规则不同,如Integer类)

应用:从网上过来的数据有的不符合要求,可以通过覆写hashCode和equals方法改变其去重规则,进行自定义去重;

*Collection和Collections的区别
java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。Collections中常用的方法有Collections.sort(),Collectios.max(),Collections.binarySearch(),Collections.replaceAll(),Collections.reverse(),Collections.fill()等等

*向上转型,向下转型
向下转型Father f = new Son();
向上转型Son s = new Father();

*线程总共有5大状态
1)新建状态:新建线程对象,并没有调用start()方法之前
2)就绪状态:调用start()方法之后线程就进入就绪状态,但是并不是说只要调用start()方法线程就马上变为当前线程,在变为当前线程之前都是为就绪状态。值得一提的是,线程在睡眠和挂起中恢复的时候也会进入就绪状态哦。
3)运行状态:线程被设置为当前线程,开始执行run()方法。就是线程进入运行状态
4)阻塞状态:线程被暂停,比如说调用sleep()方法后线程就进入阻塞状态
5)死亡状态:线程执行结束

*Java 启动线程三种方式
继承Thread,实现Runnable接口,直接在函数体使用
实现Runnable接口优势:
1)适合多个相同的程序代码的线程去处理同一个资源
2)可以避免Java中的单继承的限制
3)增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
继承Thread类优势:
1)可以将线程类抽象出来,当需要使用抽象工厂模式设计时。
2)多线程同步(值得商榷,实现Runnable接口也可以实现多线程同步)
在函数体使用优势
1)无需继承thread或者实现Runnable,缩小作用域。
另外,实现Runnable接口的线程自身无法启动,只能通过系统线程启动,如:Thread t = new Thread(new Runnable()).start();

*线程传入参数
1.继承Thread类,通过构造函数传入
2.实现Runnable接口,通过变量和方法传入
3.自建一个类【继承】Runnable接口,在这个方法中塞入参数

*Java实现多线程的3种方法:继承Thread类、实现runnable接口、使用ExecutorService,Callable、Future实现有返回值的多线程。前2种线程的实现方式没有返回值,第三种实现方式可以获取线程执行的返回值。

*BIO、NIO和AIO的区别、三种IO的原理与用法
BIO同步并阻塞
NIO同步非阻塞
AIO异步非阻塞

*同步和异步

同步就是烧开水,需要自己去轮询(每隔一段时间去看看水开了没),异步就是水开了,然后水壶会通知你水已经开了,你可以回来处理这些开水了。
同步和异步是相对于操作结果来说,会不会等待结果返回。

阻塞和非阻塞

阻塞就是说在煮水的过程中,你不可以去干其他的事情,非阻塞就是在同样的情况下,可以同时去干其他的事情。阻塞和非阻塞是相对于线程是否被阻塞。

*CyclicBarrier和CountDownLatch的区别
CountDownLatch强调一个线程等多个线程完成某件事情。CyclicBarrier是多个线程互等,等大家都完成。 >>原文地址

*线程池的submit和execute方法的区别:前者执行会返回一个future对象,可以通过这个future对象获取到线程内部的内容,后者只是会执行线程,但是没有返回

*三次握手和四次挥手

  1. 三次握手
    第一次握手:客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。

理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP连接都将被一直保持下去。
确认号:其数值等于发送方的发送序号+1(即接收方期望接收的下一个序列号)。
三次握手
2. 四次挥手
第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可以接受数据。

第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。

第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。

第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。
四次挥手

*重写就是再写一遍,重载就是再多一个。
重写:父类里有,子类再照猫画虎写一个。
重载:自己类里面有,觉得不够再写一个。
java的重写,是指在子类中对父类的某方法进行重新定义,其子类的该方法名以及参数搜索位置和个数均与父类相同,从而在调用子类的该方法时,不会执行父类的方法.如果在父类中以final定义的方法,在子类中无法重写.
1、重载:
方法名相同,参数列表不同
2、重写:
也叫覆盖,指在子类中定义一个与父类中方法同名同参数列表的方法。因为子类会继承父类的方法,而重写就是将从父类继承过来的方法重新定义一次,重新填写方法中的代码。
重写方法上可以加@Override,重载不可以
重写是覆盖,重载是多态

*覆写equals方法必须覆写hashCode方法是为了保证数据的唯一性
解释:对象存入带hash的集合,如hashSet,hashMap,都要基于hashCode和equals方法,当hashCode方法返回的值一样时,还会调用equals方法判断,如果两个方法返回的都是一致,才判断两个对象是同一个对象,不存入集合(带hash的集合都保证数据是唯一的!)。
equals是object类的方法,所有没有重写这个方法的类中的这个方法比较的都是地址,也就是和’'是一样的,重写过这个方法的类就按照重写的方法来比较,比如String类就重写了这个方法,比较的是内容。
当你对比两个对象时,在选择
和equals方法中很容易困惑,当你比较的两个引用指向的对象是Object的类型的时候,那么你看到的结果和==是一致的,因为默认的equals方法实现仅仅比较的内存地址。

*乐观锁和悲观锁的区别(最全面的分析)
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。

本质上,数据库的乐观锁做法和悲观锁做法主要就是解决下面假设的场景,避免丢失更新问题:
一个比较清楚的场景
下面这个假设的实际场景可以比较清楚的帮助我们理解这个问题:
假设当当网上用户下单买了本书,这时数据库中有条订单号为001的订单,其中有个status字段是’有效’,表示该订单是有效的;
后台管理人员查询到这条001的订单,并且看到状态是有效的
用户发现下单的时候下错了,于是撤销订单,假设运行这样一条SQL: update order_table set status = ‘取消’ where order_id = 001;
后台管理人员由于在b这步看到状态有效的,这时,虽然用户在c这步已经撤销了订单,可是管理人员并未刷新界面,看到的订单状态还是有效的,于是点击”发货”按钮,将该订单发到物流部门,同时运行类似如下SQL,将订单状态改成已发货:update order_table set status = ‘已发货’ where order_id = 001

观点1:只有冲突非常严重的系统才需要悲观锁;“所有悲观锁的做法都适合于状态被修改的概率比较高的情况,具体是否合适则需要根据实际情况判断。”,表达的也是这个意思,不过说法不够准确;的确,之所以用悲观锁就是因为两个用户更新同一条数据的概率高,也就是冲突比较严重的情况下,所以才用悲观锁。

观点2:最后提交前作一次select for update检查,然后再提交update也是一种乐观锁的做法,的确,这符合传统乐观锁的做法,就是到最后再去检查。但是wiki在解释悲观锁的做法的时候,’It is not appropriate for use in web application development.’, 现在已经很少有悲观锁的做法了,所以我自己将这种二次检查的做法也归为悲观锁的变种,因为这在所有乐观锁里面,做法和悲观锁是最接近的,都是先select for update,然后update

在实际应用中我们在更新数据的时候,更严谨的做法是带上更新前的“状态”,如

update order_table set status = ‘取消’ where order_id = 001 and status = ‘待支付’ and …;

update order_table set status = ‘已发货’ where order_id = 001 and status = ‘已支付’ and …;

然后在业务逻辑代码里判断更新的记录数,为0说明数据库已经被更新了,否则是正常的。

java虚拟机jvm1
java虚拟机jvm2

*jvm
jvm内存结构主要有三大块:堆内存,方法区和栈。堆内存是jvm中最大的一块由年轻代和年老代组成,而年轻代又被分成三部分,Eden区,FromSurvivor区,ToSurvivor区,默认情况下年轻代按照8:1:1的比例来分配;
方法区存储类信息,常量,静态变量等数据,是县城共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);
栈又分为Java虚拟机栈和本地方法栈,主要用于方法的执行。
-在Java中,对象实例都是在堆上创建。一些类信息,常量,静态变量等存储在方法区。堆和方法区都是线程共享的。
-GC机制是由JVM提供,用来清理需要清除的对象,回收堆内存。
-GC机制将Java程序员从内存管理中解放了出来,可以更关注于业务逻辑。
-在Java中,GC是由一个被称为垃圾回收器的守护线程执行的。
-在从内存回收一个对象之前会调用对象的finalize()方法。
-作为一个Java开发者不能强制JVM执行GC;GC的触发由JVM依据堆内存的大小来决定。
-System.gc()和Runtime.gc()会向JVM发送执行GC的请求,但是JVM不保证一定会执行GC。
-如果堆没有内存创建新的对象了,会抛出OutOfMemoryError。

*TLAB和栈上分配,堆上分配的关系
TLAB的出现是为了方便线程快速创建对象,在多线程的情况下,直接在堆上分配对象会出现指针碰撞的问题,从而导致对象引用混乱的问题。对象的分配会首先做逃逸分析,如果符合逃逸分析,jvm优先使用栈上分配,这里可能会有疑问,为什么符合逃逸分析就可以使用栈上分配,而不考虑是否是大对象,然后考虑使用堆上分配呢?我找了半天没有找到答案,但我有两个推测:1)对象的创建首先应该是在年轻代而不是年老代,要进入年老代是需要经过数次年轻代gc

*Java对象分配的过程
1.编译器通过逃逸分析,确定对象是在栈上分配还是在堆上分配。如果是在堆上分配,则进入选项2.
2.如果tlab_top + size <= tlab_end,则在在TLAB上直接分配对象并增加tlab_top 的值,如果现有的TLAB不足以存放当前对象则3.
3.重新申请一个TLAB,并再次尝试存放当前对象。如果放不下,则4.
4.在Eden区加锁(这个区是多线程共享的),如果eden_top + size <= eden_end则将对象存放在Eden区,增加eden_top 的值,如果Eden区不足以存放,则5.
5.执行一次Young GC(minor collection)。
6.经过Young GC之后,如果Eden区任然不足以存放当前对象,则直接分配到老年代。

*新生代,年轻代和年老代的关系
年轻代=1个新生代(Eden)+2个复活代(Survivor)
年轻代用来存放新近创建的对象,默认是堆大小堆1/15,这个比例可以调整,年轻代的特点是对象更新速度快,在短时间内产生大量“死亡对象”;
应用程序只能使用一个Eden和一个Survivor,当发生初级垃圾回收时,【gc挂起程序】,然后将Eden和Survivor复制到另一个【非活动Survivor】,然后一次性清除Eden和Survivor,【并将原来的非活动Survivor标记为活动Survivor】,将【指定次数回收后仍然存在的对象】移动到年老代中,初级回收后,得到一个空的可用的新生代。

*堆内存是如何划分的?
Java中对象都在堆上创建。为了GC,堆内存分为三个部分,也可以说三代,分别称为新生代,老年代和永久代。其中新生代又进一步分为Eden区,Survivor 1区和Survivor 2区(如下图)。新创建的对象会分配在Eden区,在经历一次Minor GC后会被移到Survivor 1区,再经历一次Minor GC后会被移到Survivor 2区,直到升至老年代,需要注意的是,一些大对象(长字符串或数组)可能会直接存放到老年代。永久代有一些特殊,它用来存储类的元信息。对于GC是否发生在永久代有许多不同的看法,在我看来这取决于采用的JVM。大家可以通过创建大量的字符串来观察是发生了GC还是抛出了OutOfMemoryError。>>原文内容

*web容器的四种作用域
几乎所有web应用容器都提供了四种类似Map的结构:application session request page,Jsp或者Servlet通过向着这四个对象放入数据,从而实现Jsp和Servlet之间数据的共享。
application:整个应用,对应servlet中ServletContext
session:会话 对应servlet中HttpSession
request:一次请求 对应servlet中的HttpServletRequest
page:当前页面

-HTTP状态码分类
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:
HTTP状态码分类 分类 分类描述
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误

HTTP状态码列表:
HTTP状态码列表 状态码 状态码英文名称 中文描述
100 Continue 继续。客户端应继续其请求
101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
200 OK 请求成功。一般用于GET与POST请求
201 Created 已创建。成功请求并创建了新的资源
202 Accepted 已接受。已经接受请求,但未处理完成
203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206 Partial Content 部分内容。服务器成功处理了部分GET请求
300 Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303 See Other 查看其它地址。与301类似。使用GET和POST请求查看
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305 Use Proxy 使用代理。所请求的资源必须通过代理访问
306 Unused 已经被废弃的HTTP状态码
307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
405 Method Not Allowed 客户端请求中的方法被禁止
406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
409 Conflict 服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突
410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息
412 Precondition Failed 客户端请求信息的先决条件错误
413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理
415 Unsupported Media Type 服务器无法处理请求附带的媒体格式
416 Requested range not satisfiable 客户端请求的范围无效
417 Expectation Failed 服务器无法满足Expect的请求头信息
500 Internal Server Error 服务器内部错误,无法完成请求
501 Not Implemented 服务器不支持请求的功能,无法完成请求
502 Bad Gateway 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理

*springMVC原理、SpringMVC流程(为什么给一个请求地址就能请求到后台)
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 HandlerMapping处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、 DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
原理图
组件说明:
以下组件通常使用框架提供实现:
DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。
HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。
ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。
原文内容

*hibernate中evict()和clear()的区别
session.evict(obj):会把指定的缓冲对象进行清除;
session.clear():把缓冲区内的全部对象清除,但不包括操作中的对象。

数据库部分

*数据性能优化方案:
sql优化
缓存
建好索引
读写分离
分库分表

*mysql的select_type叫索引类型,如果没有用到索引,则为all
常用的索引类型有:all<index<range<ref<eq_ref<const<system<null(从左到右,性能从差到好)
system最快:不进行磁盘IO
const:PK或者unique上的等值查询
eq_ref:PK或者unique上的join查询,等值匹配,对于前表的每一行(row),后表只有一行命中
ref:非唯一索引,等值匹配,可能有多行命中
range:索引上的范围扫描,例如:between/in/>
index:索引上的全集扫描,例如:InnoDB的count
ALL最慢:全表扫描(full table scan)

*并不是使用like一定不会走索引,‘key%’,’%key’,’%key%'都可能不走索引或者走索引。
如果是[select *]的情况下,'key%‘走索引,其他两种不走
如果是[select 字段]的情况下,如果字段都在索引中,走索引,如果出现查询的字段不在索引中,则’%key%'不走索引。
总结:尽量不使用like,因为like会降低查询速度,如果一定要用,尽量select具体的字段,且select的字段必须在索引中,否则不走索引,如果不select具体的字段,只有’key%'走range索引,但查询效率依然较低。优化sql尽量使索引类型大于等于ref级别
like使用索引如何避免失效

*inner join、left join、 right join区别
1)inner join,两表字段都有值才会显示一条记录
2)left join,两表字段值相同,以及左表字段有值,右表字段值为null,如果用where的话,右表字段为null,查询的时候会报错。
3)right join,与上相反

*浅析mvcc

*索引是如何加快查询的>>原文内容

*1. in()适合内表比外表数据小的情况
2. exists()适合内表比外表数据大的情况

*防止SQL注入
参数化查询和词法分析(正则表达式)

*mysql中limit不是全表查询

*数据库优化
1 查询语句的优化,这个主要是根据语句和数据库索引的情况,结合查询计划的分析结果,对性能较低的查询语句进行重写,在执行查询前执行表分析语句也可以算这里;再比如用使用存储过程;
2 数据结构优化,这个包括根据实际的应用中业务逻辑,对数据库的结构进行重新设计,或者创建相关索引里提高查询效率;
3 数据库设置优化,这方面主要是调整数据库和数据结构的相关参数提高应用访问系统的效率;
4 存储结构优化,在数据量较大的情况下,可以考虑通过数据库的存储结构进行优化,比如对数据进行partition,将数据存储在磁盘阵列服务器上等。
对多个表进行连接查询时应遵循的优化原则:
(1) 用于连接的子句的列应被索引、在Where子句中应尽量利用索引,而不是避开索引。
(2) 连接操作应从返回较少行上驱动。
(3) 如果所连接的表A和B,A表长度远远大于B表,建议从较大的A表上驱动。
(4) 如果Where子句中含有选择性条件,Where No=20,将最具有选择性部分放在表达式最后。
(5) 如果只有一个表有索引,另一表无索引,无索引的表通常作为驱动表。如A表的No列以被索引,而B表的No 列没被索引,则应当B表作为驱动表,A表作为被驱动表。
(6) 若用于连接的列和Where子句中其他选择条件列均有索引,则按各个索引对查询的有效性和选择性分别定出级别,结合表中具体数据构成情况,从中选出优化路径,一般需要考虑:子句中哪些列可以使用索引、哪些索引具有唯一性及被查询表行数目等。

*oracle的行列转换

固定行列转换
方法一:
SELECT ID,NAME,
SUM(DECODE(course,‘语文’,score,0)) 语文,–这里使用max,min都可以
SUM(DECODE(course,‘数学’,score,0)) 数学,
SUM(DECODE(course,‘英语’,score,0)) 英语,
SUM(DECODE(course,‘历史’,score,0)) 历史,
SUM(DECODE(course,‘化学’,score,0)) 化学
FROM kecheng
GROUP BY ID ,NAME
方法二:
Case方式
SELECT ID,NAME,
MAX(CASE WHEN course=‘语文’ THEN score ELSE 0 END) 语文,
MAX(CASE WHEN course=‘数学’ THEN score ELSE 0 END) 数学,
MAX(CASE WHEN course=‘英语’ THEN score ELSE 0 END) 英语,
MAX(CASE WHEN course=‘历史’ THEN score ELSE 0 END) 历史,
MAX(CASE WHEN course=‘化学’ THEN score ELSE 0 END) 化学
FROM kecheng
GROUP BY ID ,NAME
方法三:
wmsys.wm_concat行列转换函数
SELECT ID,NAME,
wmsys.wm_concat(course || ‘:’||score) course
FROM kecheng
GROUP BY ID ,NAME;
方法四:
SELECT NAME,
wmsys.wm_concat(course ||score) OVER (PARTITION BY NAME)
FROM kecheng

动态转换
方法五:使用PL/SQL
DECLARE
–存放最终的SQL
LV_SQL VARCHAR2(3000);
–存放连接的SQL
SQL_COMMOND VARCHAR2(3000);
–定义游标
CURSOR CUR IS
SELECT COURSE FROM KECHENG GROUP BY COURSE;
BEGIN
–定义查询开头
SQL_COMMOND := 'SELECT NAME ';

FOR I IN CUR LOOP
–将结果相连接
SQL_COMMOND := SQL_COMMOND || ’ ,SUM(DECODE(course,’’’ || I.COURSE ||
‘’’,score,0)) ’ || I.COURSE;
DBMS_OUTPUT.PUT_LINE(SQL_COMMOND);
END LOOP;
SQL_COMMOND := SQL_COMMOND || ’ from KECHENG group by name’;
LV_SQL := 'INSERT INTO temp_ss ’ || SQL_COMMOND;
DBMS_OUTPUT.PUT_LINE(LV_SQL);
EXECUTE IMMEDIATE LV_SQL;
END;

*过程主要是针对数据处理。业务性的。视图主要是取得数据。一般来说,视图只是select,没有update,delete功能。过程啥都能干。

Oracle sql"NOT IN"语句优化,查询A表有、B表没有的数据
记录量大的情况下,采用NOT IN查询,那肯定会慢的无法接受。比如:
[sql] view plain copy
SELECT A.

FROM TABLE_A
WHERE A.USER_ID NOT IN (SELECT B.USER_ID FROM TABLE_B)

目前找到的最优方法,可以秒查。示例如下,查询A表有、B表没有的DEPT_ID数据:
[sql] view plain copy
SELECT A.*
FROM TB_DEPT A, TB_DEPT_LEV B
WHERE A.DEPT_ID = B.DEPT_ID(+)
AND B.DEPT_ID IS NULL
(+)号可以这样来理解: + 表示补充,即哪个表有加号,这个表就是匹配表。这里加号写在右表,左表就是全部显示,故是左连接。
原文链接:http://blog.csdn.net/dengjh_business/article/details/35226227

算法

http://blog.csdn.net/Tri_Color_Flag/article/details/52523723

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值