1. HashMap与HashTable的区别
Hashmap的key、value都可以为空,但key只能有一个为空,value可以有多个,非同步
HashTable的key、value都不能为空,是同步的,线程安全
因为hashtable,concurrenthashmap它们是用于多线程的,并发的 ,如果map.get(key)得到了null,不能判断到底是映射的value是null,还是因为没有找到对应的key而为空,而用于单线程状态的hashmap却可以用contains(key) 去判断到底是否包含了这个null。
HashMap的默认长度为16,是为了降低hash碰撞的几率,而HashTable的initialCapacity为11。HashMap中初始容量必须是2的幂,如果初始化传入的initialCapacity不是2的幂,将会自动调整为大于出入的initialCapacity最小的2的幂。
HashMap的存储原理:1.HashMap允许存放null键和null值,先判断key是否为null,如果为null则调用putForNullKey方法,将value放 在数组的第一个位置
- 根据key的hashcode重新计算hash值
- 通过hash值算出对应table中的索引下标
- 如果索引处的Entry不为null,通过循环不断遍历下一个元素
- 如果存在key相等的情形,则用新的value值覆盖老的value值
- 如果索引处的Entry为null,将key-value添加到此处
- 判断此处的bucketindex是否相同,如果相同就放生了hash冲突
- 创建新的Entry放入bucketyIndex索引处,并让新的Entry指向原来的Entry
- 如果新加入后的大小超过了当前最大容量,则把table对象的长度扩充到原来的2倍
- 获取entry时,如果key为null,则直接获取数组的第一个元素,如果不是,先计算key的hashcode下标,再用可以的equals方法判断是否相等,如果相等则返回对应的Entry,如果不相等则返回为null。
2.Mysql的索引
1.选择唯一性索引
唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。例如,学生表中学号是具有唯一性的字段。为该字段建立唯一性索引可以很快的确定某个学生的信息。如果使用姓名的话,可能存在同名现象,从而降低查询速度。
2.为经常需要排序、分组和联合操作的字段建立索引
经常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作会浪费很多时间。如果为其建立索引,可以有效地避免排序操作。
3.为常作为查询条件的字段建立索引
如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度。因此,为这样的字段建立索引,可以提高整个表的查询速度。
4.限制索引的数目
索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。
5.尽量使用数据量少的索引
如果索引的值很长,那么查询的速度会受到影响。例如,对一个CHAR(100)类型的字段进行全文检索需要的时间肯定要比对CHAR(10)类型的字段需要的时间要多。
6.尽量使用前缀来索引
如果索引字段的值很长,最好使用值的前缀来索引。例如,TEXT和BLOG类型的字段,进行全文检索会很浪费时间。如果只检索字段的前面的若干个字符,这样可以提高检索速度。
7.删除不再使用或者很少使用的索引
表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。
8 . 最左前缀匹配原则,非常重要的原则。
mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a 1=”” and=”” b=”2” c=”“> 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
9 .=和in可以乱序。
比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
10 . 尽量选择区分度高的列作为索引。
区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就 是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条 记录
11 .索引列不能参与计算,保持列“干净”。
比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本 太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);
12 .尽量的扩展索引,不要新建索引。
比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可
注意:选择索引的最终目的是为了使查询的速度变快。上面给出的原则是最基本的准则,但不能拘泥于上面的准则。读者要在以后的学习和工作中进行不断的实践。根据应用的实际情况进行分析和判断,选择最合适的索引方式。
3.Jvm的原理
Jvm是java virtual machine(java虚拟机)的缩写,他包含一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和一个存储方法域。
Jre是java运行环境,所有java程序都要在jre下才能运行,普通用户只要运行已开发好的java程序,安装jre即可
Jdk是程序开发者用来编译,调试java程序用的开发工具包。
Jvm是jre的一部分,Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。
第一块:PC寄存器
PC寄存器是用于存储每个线程下一步将执行的JVM指令,如该方法为native的,则PC寄存器中不存储任何信息。
第二块:JVM栈
JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址。
第三块:堆(Heap)
它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。
4.Spring与SpringBoot的区别
Spring boot是一个在Spring 的基础上搭建的全新的微框架,其目的是简化Spring的搭建和开发过程。
1》对第三方插件分装和整合,提供第三方接口
2》无需配置复杂的XML
3》内嵌式web服务器(tomcat,jetty等)
4》提供POM,简化Maven配置
5》核心功能-自动配置
5.SpringBoot的微服务
注册服务,配置服务,解析服务,预处理服务,消费服务,控制接收服务
6.线程的几种状态
线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态
线程在运行的过程中因为某些原因而发生阻塞,阻塞状态的线程的特点是:该线程放弃CPU的使用,暂停运行,只有等到导致阻塞的原因消除之后才回复运行。或者是被其他的线程中断,该线程也会退出阻塞状态,同时抛出InterruptedException。
导致阻塞的原因有很多种,大致分为三种来讨论,分别是一般线程中的阻塞,Socket客户端的阻塞,Socket服务器端的阻塞。
7.线程池的优点
1〉线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用
2〉根据系统承受能力,调节线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃。
**8.**提交一个任务到线程池中,线程池的处理流程
1>判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。
2>线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3>判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
9.jdk提供的四种线程池实现方法
1》cachedThreadPool 用于并发执行大量短期的小任务,或者负载较轻的服务器
2》FixedThreadPool 用于负载较重的服务器,为了资源的合理利用,需要限制当前线程数量
3》singleThreadExecutor 用于串行执行任务的场景,每个任务必须按顺序执行,不需要并发执行
4》ScheduledThreadPoolExecutor 用于需要多个后台线程执行周期任务,同时需要限制线程数量的场景。
**10.**线程池与数据库连接池的区别
线程池
其实线程池的原理很简单,类似于操作系统中的缓冲区的概念,它的流程如下:先启动若干数量的线程,并让这些线程都处于睡眠状态,当客户端有一个新请求时,就会唤醒线程池中的某一个睡眠线程,让它来处理客户端的这个请求,当处理完这个请求后,线程又处于睡眠状态。当然为每一个请求单独的创建线程是很方便的,但是并发量很大时,如果为每一个请求都创建新的线程,那么耗费CPU时间和内存是很惊人的,同时反复创建、销毁线程带来的结果将是一场灾难
连接池
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。一个数据库连接对象均对应一个物理数据库连接,每次操作都打开一个物理连接,使用完都关闭连接,这样造成系统的 性能低下。 数据库连接池的解决方案是在应用程序启动时建立足够的数据库连接,并讲这些连接组成一个连接池(简单说:在一个“池”里放了好多半成品的数据库联接对象),由应用程序动态地对池中的连接进行申请、使用和释放。对于多于连接池中连接数的并发请求,应该在请求队列中排队等待。并且应用程序可以根据池中连接的使用率,动态增加或减少池中的连接数。
连接池技术尽可能多地重用了消耗内存地资源,大大节省了内存,提高了服务器地服务效率,能够支持更多的客户服务。通过使用连接池,将大大提高程序运行效率,同时,我们可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
- 最小连接数是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费;
- 最大连接数是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求将被加入到等待队列中,这会影响之后的数据库操作。
11. java类库和框架中用到的设计模式
1》Java io
装饰器模式:
有一些流处理器可以对另一些流处理器起到装饰作用,形成新的、具有改善了的功能的流处理器。
适配器模式:
有一些流处理器是数组适配器对流处理器的适配。
2》Java 集合框架
装饰器模式:
通过阅读源码发现TreeSet和 HashSet 的实现其实是对 TreeMap 和 HashMap 的包装,set 在 map 的基础上删减了一些功能并增加了一些特性。
3》Tomcat
观察者模式:
Tomcat 对组件生命周期的控制和监听可以说都是通过观察者模式实现的。观察者模式 jdk中有类库实现它,但 Tomcat使用了自己的实现。
责任链模式:
Tomcat 的初始化过程和启动过程都是责任链模式实现的。
模板方法模式:
Tomcat 源码中到处充满着模板方法模式,每个组件的实现控制都用到了模板方法模式。
门面(外观)模式:
Tomcat 内部 Request和Response对象通过门面模式转化为servlet中的Request和Response对象。
4》Spring
工厂模式:
Spring 数据库,bean的实现都用到了工厂模式。
模板方法模式:
Spring 源码中预留了很多扩展点,通过继承父类并重写某些方法可以自定义过程。
建造者模式:
Bean 的组装。
代理模式:
在Aop实现中用到了JDK的动态代理;
单例模式:
这个比如在创建bean的时候
5》其他用到的设计模式
策略模式:
Sort 中的 Comparator这个接口。多线程的实现。
原型模式:
Object 类的 clone方法。
迭代器模式:
Java 集合框架中的各种迭代器。
12. mysql的存储引擎
MyISAM:
- 不支持事务,但是每次查询都是原子的;
- 支持表级锁,即每次操作是对整个表加锁;
- 存储表的总行数;
- 采用菲聚集索引
InnoDb:
- 支持ACID的事务,支持事务的四种隔离级别;
- 支持行级锁及外键约束:因此可以支持写并发;
- 不存储总行数
- 采用聚集索引
13. Mysql的聚集索引
利用下面的命令可以查看默认的存储引擎
show variables like '%storage_engine%';
1〉聚集索引:
索引中键值的逻辑顺序决定了表中相应行的物理顺序(索引中的数据物理存放地址和索引的顺序是一致的)
2非聚集索引
索引的逻辑顺序与磁盘上的物理存储顺序不同
14. SpringMVC与Struts2的区别
Springmvc:
1》采用Servlet实现
2》方法级别的拦截
3》零配置
Struts2:
1》采用Filter
2》类级别的拦截
**15.**Hibernate和Mybatis的区别。
相同点:
1》都支持jdbc和JTA
2》Hibernate与MyBatis都是通过SessionFactoryBuider由XML配置文件生成SessionFactory,由SessionFactory 生成Session,由Session来开启执行事务和SQL(Structured Query Language,结构化查询语言)语句。
3》基于ORM思想解决了Entity和数据库的映射问题
不同点:1》Mybatis的sql是由Mapper.xml配置的,需要手写,更加灵活,优化方便
Hibernate的hql是自动生成的,不方便优化,级联删除时效率低
2》都支持第三方缓存,但hibernate的二级机制比Mybatis的好
16.抽象类与接口的区别
语法层面上的区别:
1>一个类只可以继承一个抽象类,但却可以实现多个接口
2>抽象类中可以有静态方法和静态代码块,但接口中不能
3>抽象类中的成员变量可以是各种类型的,但接口的成员变量只能是public static final类型的
4>抽象类可提供成员方法的实现细节,而接口只能存在public abstract方法
设计层面上的区别:
1》抽象类是对事务整体的抽象,而接口只是对行为的抽象
2》 如果一个类A继承了抽象类B,但是又对B中的方法不满意,那么我们可以在B中修改抽象方法(所有子类的公共方法),但是A中的代码却不需要改动。如果一个接口C中的方法做了更改,那么所有实现这个接口的非抽象方法都必须做出相应的改动。抽象类是一种模板式的定义,而接口则是一种规范的定义。
17. 成员变量,局部变量,静态变量的区别
成员变量
局部变量
静态变量
定义位置
在类中,方法外
方法中,或者方法的形式参数
在类中,方法外
初始化值
有默认初始化值
无,先定义,赋值后才能使用
有默认初始化值
调用方式
对象调用
---
对象调用,类名调用
存储位置
堆中
栈中
方法区
生命周期
与对象共存亡
与方法共存亡
与类共存亡
别名
实例变量
---
类变量
18. 多线程如何确保线程安全
线程安全
一般说来,确保线程安全的方法有这几个:竞争与原子操作、同步与锁、可重入、过度优化
19. ready()与window.onload()的区别
1〉ready()是在dom结构加载完成后执行的,而window.onload()是在页面全部加载完成后才能执行,ready先于onload执行
2>ready是可以重复执行的,而onload只能执行最后一个
**20.**final、finally、finalize的区别
1>final是修饰符,被final修饰的类,就意味着不能再派生出新的子类,不能作为父类而被子类继承。因此一个类不能既被abstract声明,又被final声明。将变量或方法声明为final,可以保证他们在使用的过程中不被修改。被声明为final的变量必须在声明时给出变量的初始值,而在以后的引用中只能读取。被final声明的方法也同样只能使用,即不能方法重写。
2〉finally是在异常处理时提供finally块来执行任何清除操作。不管有没有异常被抛出、捕获,finally块都会被执行
3〉finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
21.Mysql常用的关键字
Order by,group by,limit,having,AVG,SUM,MIN,distinct,rownum,desc,asc
22.线程池参数的设置技巧
一、ThreadPoolExecutor的重要参数
- corePoolSize:核心线程数
- 核心线程会一直存活,及时没有任务需要执行
- 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
- 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
- queueCapacity:任务队列容量(阻塞队列)
- 当核心线程数达到最大时,新任务会放在队列中排队等待执行
- maxPoolSize:最大线程数
- 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
- 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
- keepAliveTime:线程空闲时间
- 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
- 如果allowCoreThreadTimeout=true,则会直到线程数量=0
- allowCoreThreadTimeout:允许核心线程超时
- rejectedExecutionHandler:任务拒绝处理器
- 两种情况会拒绝处理任务:
- 当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务
- 当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务
- 线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常
- ThreadPoolExecutor类有几个内部实现类来处理这类情况:
- AbortPolicy 丢弃任务,抛运行时异常
- CallerRunsPolicy 执行任务
- DiscardPolicy 忽视,什么都不会发生
- DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
- 实现RejectedExecutionHandler接口,可自定义处理器
二、ThreadPoolExecutor执行顺序:
线程池按以下行为执行任务
- 当线程数小于核心线程数时,创建线程。
- 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
- 当线程数大于等于核心线程数,且任务队列已满
- 若线程数小于最大线程数,创建线程
- 若线程数等于最大线程数,抛出异常,拒绝任务
三、如何设置参数
- 默认值
- corePoolSize=1
- queueCapacity=Integer.MAX_VALUE
- maxPoolSize=Integer.MAX_VALUE
- keepAliveTime=60s
- allowCoreThreadTimeout=false
- rejectedExecutionHandler=AbortPolicy()
- 如何来设置
- 需要根据几个值来决定
- tasks :每秒的任务数,假设为500~1000
- taskcost:每个任务花费时间,假设为0.1s
- responsetime:系统允许容忍的最大响应时间,假设为1s
- 做几个计算
- corePoolSize = 每秒需要多少个线程处理?
- threadcount = tasks/(1/taskcost) =tasks*taskcout = (500
1000)*0.1 = 50100 个线程。corePoolSize设置应该大于50 - 根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可
- queueCapacity = (coreSizePool/taskcost)*responsetime
- 计算可得 queueCapacity = 80/0.1*1 = 80。意思是队列里的线程可以等待1s,超过了的需要新开线程来执行
- 切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。
- maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost)
- 计算可得 maxPoolSize = (1000-80)/10 = 92
- (最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数
- rejectedExecutionHandler:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理
- keepAliveTime和allowCoreThreadTimeout采用默认通常能满足
- threadcount = tasks/(1/taskcost) =tasks*taskcout = (500
- 以上都是理想值,实际情况下要根据机器性能来决定。如果在未达到最大线程数的情况机器cpu load已经满了,则需要通过升级硬件(呵呵)和优化代码,降低taskcost来处理。
23. 数据库的设计原则(三大范式)
1》确保每一列都是原子性
2》确保表中的每一列 都与主键相关
3》确保表的每一列都与主键直接相关,而不是间接相关
//规则1:表必须要有主键。
//规则2:一个字段只表示一个含义。
//规则3:总是包含两个日期字段:gmt_create(创建日期),gmt_modified(修改 日期),且这两个字段不应该包含有额外的业务逻辑。
//规则4:MySQL中,gmt_create、gmt_modified使用DATETIME类型。
//规则5:禁止使用复杂数据类型(数组,自定义类型等)。
//规则6: MySQL中,附属表拆分后,附属表id与主表id保持一致。不允许在附属表新增主键字段。
//规则7: MySQL中,存在过期概念的表,在其设计之初就必须有过期机制,且有明确的过期时间。过期数据必须迁移至历史表中。
//规则8: MySQL中,不再使用的表,必须通知DBA予以更名归档。
//规则9: MySQL中,线上表中若有不再使用的字段,为保证数据完整,禁止删除。
//规则10: MySQL中,禁止使用OCI驱动,全部使用THI驱动。
**24.**drop、delete与truncate分别在什么场景之下使用?
- 不再需要一张表的时候,用drop
- 想删除部分数据行时候,用delete,并且带上where子句
- 保留表而删除所有数据的时候用truncate
25.Mysql中in和exists的区别
In适合内小外大的,exists适合内大外小的
select * from A where id in(select id from B)
26.Object对象的函数都有哪些?
1》equals()2》toString()3》hashCode()4》wait()
5》clone()保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常
6》getClass()
7》notify()该方法唤醒在该对象上等待的某个线程。
8》notifyAll()该方法唤醒在该对象上等待的所有线程。
9》finalize()释放资源
27.有关获取时间的方法
1、Date day=new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(day));
通过Date类来获取当前时间
2、SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(df.format(System.currentTimeMillis()));
通过System类中的currentTimeMillis方法来获取当前时间
3、Calendar c = Calendar.getInstance();//可以对每个时间域单独修改
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int date = c.get(Calendar.DATE);
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
int second = c.get(Calendar.SECOND);
System.out.println(year + "/" + month + "/" + date + " " +hour + ":" +minute + ":" + second);
通过Calendar类来获取当前时间
4、 Date date = new Date();
String year = String.format("%tY", date);
String month = String.format("%tB", date);
String day = String.format("%te", date);
System.out.println("今天是:"+year+"-"+month+"-"+day);
通过Date类来获取当前时间
28. 单点登录实现原理
1》单点登录
有一个独立的认证中心,只有认证中心才能接受用户的用户名和密码等信息进行认证,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,当用户提供的用户名和密码通过认证中心认证后,认证中心会创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌即得到了授权,然后创建局部会话。
示例:
下面对上图进行解释:
- 当用户还没进行用户登录的时候
- 用户去访问系统1的保护资源 ,系统1检测到用户还没登录,跳转至SSO认证中心,SSO认证中心也发现用户没有登录,就跳转到用户至认证中心的登录页面
- 用户在登录页面提交用户相应信息后,认证中心会校验用户信息,如果用户信息正确的话认证中心就会创建与该用户的全局会话(全局会话过期的时候,用户就需要重新登录了。全局会话中存的信息可能有令牌,用户信息,及该在各个系统的一些情况),同时创建授权令牌,然后进行下一步,否则认证中心给出提示(用户信息有误),待用户再次点击登录的时候,再一次进行校验用户信息
- 认证中心带着令牌跳转到用户最初请求的地址(系统1),系统1拿到令牌后去SSO认证中心校验令牌是否有效,SSO认证中心校验令牌,若该令牌有效则进行下一步
- 注册系统1,然后系统1使用该令牌创建和用户的局部会话(若局部会话过期,跳转至SSO认证中心,SSO认证中心发现用户已经登录,然后执行第3步),返回受保护资源
- 当用户还没进行用户登录的时候
用户已经通过认证中心的认证后
用户访问系统2的保护资源,系统2发现用户未登录,跳转至SSO认证中心,SSO认证中心发现用户已经登录,就会带着令牌跳转回系统2,系统2拿到令牌后去SSO认证中心校验令牌是否有效,SSO认证中心返回有效,注册系统2,系统2使用该令牌创建与用户的局部会话,返回受保护资源。
如果系统1的局部会话存在的话,当用户去访问系统1的保护资源时,就直接返回保护资源,不需要去认证中心验证了
局部会话存在,全局会话一定存在;全局会话存在,局部会话不一定存在;全局会话销毁,局部会话必须销毁
如果在校验令牌过程中发现客户端令牌和服务器端令牌不一致或者令牌过期的话,则用户之前的登录就过期了,用户需要重新登录
- 单点注销
在一个子系统中注销,全局会话也会被注销,所有子系统的会话都会被注销
示例:
用户向系统1发出注销请求,系统1根据用户与系统1建立的会话id从会话中拿到令牌,向SSO认证中心发起注销请求,认证中心校验令牌有效,会销毁全局会话,同时取出此令牌注册的系统地址,认证中心向所有注册系统发出注销请求,各系统收到注销请求后销毁局部会话,认证中心引导用户跳转值登录页面。
- 整体陈述
- 单点登录涉及SSO认证中心与多个子系统,子系统与SSO认证中心需要通信(交换令牌、校验令牌及发起注销请求等),子系统中包含SSO的客户端,SSO认证中心是服务端
- 认证中心与客户端通信可通过 httpClient、web service、rpc、restful api(url是其中一种) 等实现
- 客户端与服务器端的功能
- 客户端:
- 拦截子系统未登录用户请求,跳转至sso认证中心
- 接收并存储sso认证中心发送的令牌
- 与服务器端通信,校验令牌的有效性
- 建立局部会话
- 拦截用户注销请求,向sso认证中心发送注销请求
- 接收sso认证中心发出的注销请求,销毁局部会话
- 服务器端:
- 验证用户的登录信息
- 创建全局会话
- 创建授权令牌
- 与客户端通信发送令牌
- 校验客户端令牌有效性
- 系统注册
- 接收客户端注销请求,注销所有会话
- 客户端:
29. post,delete,put,get请求的区别
1、GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的。
2、与GET不同的是,PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。
3、POST请求同PUT请求类似,都是向服务器端发送数据的,但是该请求会改变数据的种类等资源,就像数据库的insert操作一样,会创建新的内容。几乎目前所有的提交操作都是用POST请求的。
4、DELETE请求顾名思义,就是用来删除某一个资源的,该请求就像数据库的delete操作。
就像前面所讲的一样,既然PUT和POST操作都是向服务器端发送数据的,那么两者有什么区别呢。。。POST主要作用在一个集合资源之上的(url),而PUT主要作用在一个具体资源之上的(url/xxx),通俗一下讲就是,如URL可以在客户端确定,那么可使用PUT,否则用POST。
综上所述,我们可理解为以下:
1、POST /url 创建
2、DELETE /url/xxx 删除
3、PUT /url/xxx 更新
4、GET /url/xxx 查看
30.API接口的安全性设计
接口的安全性主要围绕Token、Timestamp和Sign三个机制展开设计,保证接口的数据不会被篡改和重复调用
1、客户端通过用户名密码登录服务器并获取Token
2、客户端生成时间戳timestamp,并将timestamp作为其中一个参数
3、客户端将所有的参数,包括Token和timestamp按照自己的算法进行排序加密得到签名sign
4、将token、timestamp和sign作为请求时必须携带的参数加在每个请求的URL后边(http://url/request?token=123×tamp=123&sign=123123123)
5、服务端写一个过滤器对token、timestamp和sign进行验证,只有在token有效、timestamp未超时、缓存服务器中不存在sign三种情况同时满足,本次请求才有效
31.Spring Boot与SpringMVC的区别
Spring 是一个“引擎”;
Spring MVC 是基于Spring的一个 MVC 框架 ;
Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。
32. SpringMVC的实现流程
(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet通过HandlerAdapter处理器适配器调用处理器;
(5)执行处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewReslover视图解析器进行解析;
(9)ViewReslover解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。
33.查询两门及两门以上不及格同学的平均分
Select name,AVG(score),SUM(score<60) as gk from table group by name having gk>=2
34.redis,mongodb,mysql/oracle的区别
1》Redis: 分布式缓存,用来存session, 页面权限,系统参数缓存等。速度快,适合做缓存。2》mongodb: 通过字段冗余,减少跨表查询,数据可支持横向发展,不支持事务,对数据性能要求高,对数据安全性要求不高。
3》Oracle: 支持事务 数据安全性高 。Oracle不能存数组,只能存字符串,mongodb却可以存数组,但是查询会比较麻烦。
35.mysql,oracle,mongodb的分页方法
Mysql:select * from table limit 30,10
Oracle:SELECT * FROM( SELECT T.*, ROWNUM rn FROM(SELECT * FROM LG_ADMIN )t)WHERE rn > 0 AND rn <= 10
Mongodb: db.test.find().sort({"age":1}).skip(30).limit(10);
36. java中jdbc事物
JDBC的一切行为包括事务是基于一个Connection的,在JDBC中是通过Connection对象进行事务管理。在JDBC中,常用的和事务相关的方法是: setAutoCommit、commit、rollback等。