1.集合有哪些?数据结构?初始长度?扩容机制?哪些是线程安全的?hashmap的底层原理?
集合类型主要有3种:set(集)、list(列表)和map(映射)。
1、List(有序、可重复)
List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。
2、Set(无序、不能重复)
Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。
3、Map(键值对、键唯一、值不唯一)
Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。
Set接口数据结构
哈希表存储结构
List
有序可重复
ArrayList
ArrayList数据结构是数组。查询快,增删慢。ArrayList是线程不安全的,允许元素为null 。
Vector
线程安全的数组,效率较差,已经过时不用。
LinkedList
LinkedList 数据结构是双向链表,插入删除比较方便。LinkedList 是线程不安全的,允许元素为null 。
Map
HashMap :
jdk1.8中HashMap底层是哈希表数据结构,数组+链表+红黑树,HashMap是线程不安全的,允许使用null键和null值,
HashMap根据键的HashCode值存储数据,具有很快的访问速度。
HashMap存入的键值对在遍历时的顺序是随机的。
HashMap不支持并发
HashTable:
线程安全,使用synchronized锁住全部数据,效率较低。
LinkedHashMap:
LinkedHashMap 是HashMap的一个子类,默认LinkedHashMap遍历时输出的顺序和put输入的顺序是相同的。
LinkedHashMap有两种排序方式:插入排序和访问排序(修改或访问一个元素后,将该元素移到队列末尾),默认是插入排序。使用accessOrder来标记使用哪种排序方式,accessOrder==true时,表示使用访问排序,默认为false;
LinkedHashMap使用了双向链表来保证了顺序性。
TreeMap:
TreeMap底层是红黑树数据结构,线程不安全,可以用于给Map集合中的键进行排序
TreeMap遍历出来的是排序后的键值对。
ConcurrentHashMap
ConcurrentHashMap是线程安全的,jdk1.8使用CAS和volatile实现。而jdk1.8以前通过锁分段技术、可重入锁实现。
支持并发,可以一边更新一边遍历
初始长度 扩容机制
线程安全和线程不安全的集合
Vector、HashTable、Properties是线程安全的;
ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是线程不安全的。
值得注意的是:为了保证集合是线程安全的,相应的效率也比较低;线程不安全的集合效率相对会高一些。
HashMap 的实现原理?
HashMap的put()和get()的实现
map.put:
1.调用hashcode方法得出hash值 2.通过哈希算法转化成下标 3.下标位置上如果没有任何元素,就把Node添加到这个位置上 4.如果对应位置有链表 用key和链表上的key进行equals 5.如果map.put返回值都为false则添加到末尾 如果有为true的 覆盖value
map.get:
1.调用hashcode方法得出hash值 2.通过哈希算法转化成下标 3.下标位置上如果没有任何元素,就返回null 4.如果对应位置有链表 用key和链表上的key进行equals 5.如果map.get 都是false则返回null 如果有true就返回对应value
2.线程的创建?开启?状态? sleep和wait的区别?线程池?死锁?如何保证线程安全
创建线程有哪几种方式?
①.继承Thread类创建线程类
定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
创建Thread子类的实例,即创建了线程对象。
调用线程对象的start()方法来启动该线程。
②. 通过Runnable接口创建线程类
定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
调用线程对象的start()方法来启动该线程。
③. 通过Callable和Future创建线程
创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
使用FutureTask对象作为Thread对象的target创建并启动新线程。
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
调用线程对象的start()方法来启动该线程
线程有哪些状态?
线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪
sleep() 和 wait() 有什么区别?
sleep():线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。
wait():同时释放对象的机锁,使得其他线程能够访问
创建线程池有哪几种方式?
①. newFixedThreadPool(int nThreads)
创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。
②. newCachedThreadPool()
创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制。
③. newSingleThreadExecutor()
这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来串行执行。
④. newScheduledThreadPool(int corePoolSize)
创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。
什么是死锁?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者进程在运行过程中,请求和释放资源的顺序不当而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
怎么防止死锁?
加锁顺序(线程按照一定的顺序加锁)
加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
死锁检测
在 java 程序中怎么保证多线程的运行安全?
1、使用线程安全的类;
2、使用synchronized同步代码块,或者用Lock锁;
3、多线程并发情况下,线程共享的变量改为方法局部级变量;
3.==和 equals的区别?
== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
4.对反射的理解?获取 Class类的方式有哪些?如何用反射取私有属性 Filed?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
获取Class对象的三种方式
第一种,使用 Class.forName 静态方法。
前提:已明确类的全路径名。
第二种,使用 .class 方法。
说明:仅适合在编译前就已经明确要操作的 Class
第三种,使用类对象的 getClass() 方法。
适合有对象示例的情况下
如何用反射取私有属性?
利用反射,首先是Class字节码对象的获取,
// 获得指定类的属性
Field field = clazz.getDeclaredField("name");
// 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
field.setAccessible(true);取消 Java 语言访问检查
5.常用设计模式有哪些?在项目中哪里有用到?单例中懒汉饿汉优缺点?
单例模式
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建
装饰者模式
对已有的业务逻辑进一步的封装,使其增加额外的功能
工厂模式
一个抽象的接口,多个抽象接口的实现类,一个工厂类,用来实例化抽象的接口
单例中懒汉饿汉优缺点
1.饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的
2.从实现方式来讲他们最大的区别就是懒汉式是延时加载,他是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,饿汉式无需关注多线程问题,写法简单明了,能用则用。真正用到的时候才去建这个单例对象,“饿汉式”是在不管用不用得上,一开始就建立这个单例对象。
懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间。
饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。
6.JDK1.8中有哪些新特性?
Lambda表达式:Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 ,读作(goes to)。
Default关键字:通过使用default修饰方法,可以让我们在接口里面定义具体的方法实现 接口的实现类实现了这个接口之后,可以直接调用
方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
Date Time API:加强对日期与时间的处理。
Optional类:Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
7. session的实现原理? session的生命周期? session如何存储数据?
session的实现原理
当客户端访问服务器时,服务器根据需求设置session,将会话信息保存在服务器上,同时将标示session的session_id传递给客户端浏览器,浏览器将这个session_id保存在内存中(还有其他的存储方式,例如写在url中),我们称之为无过期时间的cookie。浏览器关闭后,这个cookie就清掉了,它不会存在用户的cookie临时文件。以后浏览器每次请求都会额外加上这个参数值,再服务器根据这个session_id,就能取得客户端的数据状态。
如果客户端浏览器意外关闭,服务器保存的session数据不是立即释放,此时数据还会存在,只要我们知道那个session_id,就可以继续通过请求获得此session的信息;但是这个时候后台的session还存在,但是session的保存有一个过期时间,一旦超过规定时间没有客户端请求时,他就会清除这个session。
session的生命周期
Session存储在服务器的内存中(为了高速存取)。
Session何时生效
Sessinon在用户访问第一次访问服务器时创建,需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session,可调用request.getSession(true)强制生成Session。
Session何时失效
服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效。Tomcat中Session的默认失效时间为20分钟。
Java中的session存储
sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。
session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid。
存储在服务器的内存中,tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等。客户端只保存sessionid到cookie中,而不会保存session,session销毁只能通过invalidate或超时,关掉浏览器并不会关闭session。
8.类加载机制?代码块的执行顺序?
类加载分为三个步骤:加载、连接、初始化。
1.加载
类加载指的是将class文件读入内存,并为之创建一个java.lang.Class对象,即程序中使用任何类时,系统都会为之建立一个java.lang.Class对象,系统中所有的类都是java.lang.Class的实例。
类的加载由类加载器完成,JVM提供的类加载器叫做系统类加载器,此外还可以通过继承ClassLoader基类来自定义类加载器。
通常可以用如下几种方式加载类的二进制数据:
从本地文件系统加载class文件。
从JAR包中加载class文件,如JAR包的数据库启驱动类。
通过网络加载class文件。
把一个Java源文件动态编译并执行加载。
2.连接
连接阶段负责把类的二进制数据合并到JRE中,其又可分为如下三个阶段:
验证:确保加载的类信息符合JVM规范,无安全方面的问题。
准备:为类的静态Field分配内存,并设置初始值。
解析:将类的二进制数据中的符号引用替换成直接引用。
3.初始化
该阶段主要是对静态Field进行初始化,在Java类中对静态Field指定初始值有两种方式:
声明时即指定初始值,如static int a = 5;
使用静态代码块为静态Field指定初始值,如:static{ b = 5; }
JVM初始化一个类包含如下几个步骤:
假如这个类还没有被加载和连接,则程序先加载并连接该类。
假如该类的直接父类还没有被初始化,则先初始化其直接父类。
假如类中有初始化语句,则系统依次执行这些初始化语句。
所以JVM总是最先初始化java.lang.Object类。
类初始化的时机(对类进行主动引用时):
创建类的实例时(new、反射、反序列化)。
调用某个类的静态方法时。
使用某个类或接口的静态Field或对该Field赋值时。
使用反射来强制创建某个类或接口对应的java.lang.Class对象,如Class.forName("Person")
初始化某个类的子类时,此时该子类的所有父类都会被初始化。
直接使用java.exe运行某个主类时。
代码块的执行顺序?
静态代码块 >>> 构造代码块 >>>> 构造方法
如果有继承的话
父类静态代码块>>>子类的静态代码块>>>父类的构造代码块>>>父类的构造方法>>>子类的构造代码块>>>子类的构造方法
9. cookie和 session的区别?
cookie保存在客户端,session保存在服务器端,
cookie目的可以跟踪会话,也可以保存用户喜好或者保存用户名密码
session用来跟踪会话
10.java中字符串的方法有哪些? string stringbuild stringbuffer的区别
1、equals():比较两个字符串是否相等
2、equalsIgnoreCase( ):忽略大小写的两个字符串是否相等比较
3、toString():转换成String类型
4、equalsIgnoreCase( ):忽略大小写的两个字符串是否相等比较
5、String.valueOf():转换成String类型(不用担心object是否为null值这一问题)
6、split():分隔符
7、subString():截取字符串中的一段字符串
8、charAt():返回指定索引处char值
9、toLowerCase():将所有在此字符串中的字符转化为小写(使用默认语言环境的规则)
10、indexOf():指出 String 对象内子字符串的开始位置
11、replace和replaceAll
12、getBytes():得到一个系统默认的编码格式的字节数组
string stringbuild stringbuffer的区别
String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
11.jvm调优和垃圾回收机制?
JVM调优目标:使用较小的内存占用来获得较高的吞吐量或者较低的延迟。
程序在上线前的测试或运行中有时会出现一些大大小小的JVM问题,比如cpu load过高、请求延迟、tps降低等,甚至出现内存泄漏(每次垃圾收集使用的时间越来越长,垃圾收集频率越来越高,每次垃圾收集清理掉的垃圾数据越来越少)、内存溢出导致系统崩溃,因此需要对JVM进行调优,使得程序在正常运行的前提下,获得更高的用户体验和运行效率。
这里有几个比较重要的指标:
内存占用:程序正常运行需要的内存大小。
延迟:由于垃圾收集而引起的程序停顿时间。
吞吐量:用户程序运行时间占用户程序和垃圾收集占用总时间的比值。
当然,和CAP原则一样,同时满足一个程序内存占用小、延迟低、高吞吐量是不可能的,程序的目标不同,调优时所考虑的方向也不同,在调优之前,必须要结合实际场景,有明确的的优化目标,找到性能瓶颈,对瓶颈有针对性的优化,最后进行测试,通过各种监控工具确认调优后的结果是否符合目标。
2、JVM调优工具
调优可以依赖、参考的数据有系统运行日志、堆栈错误信息、gc日志、线程快照、堆转储快照等。
垃圾回收机制
gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。
如何将垃圾回收?
在Java中存在着四种垃圾回收算法,标记清除算法、复制算法、标记整理算法以及分代回收算法。
标记清除算法
该算法分为“标记”和“清除”两个阶段:标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。
复制算法
它可以将内存分为大小相同的两块,每次使用其中的一块。当第一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。
标记整理算法
该算法标记阶段和标记清除一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。
分代收集算法
当前虚拟机的垃圾收集都采用分代收集算法,这种算法就是根据具体的情况选择具体的垃圾回收算法。一般将 java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
(1)新生代-复制 回收机制
对于新生代区域,由于每次 GC 都会有大量新对象死去,只有少量存活。因此采用 复制 回收算法,GC 时把少量的存活对象复制过去即可。但是从上面我们可以看到,新生代也划分了三个部分比例:Eden:S1:S2=8:1:1。
其中 Eden 意为伊甸园,形容有很多新生对象在里面创建;S1和S2中的S表示Survivor,为幸存者,即经历 GC 后仍然存活下来的对象。
工作原理如下:
首先,Eden对外提供堆内存。当 Eden区快要满了,触发垃圾回收机制,把存活对象放入 Survivor A 区,清空 Eden 区;Eden区被清空后,继续对外提供堆内存;当 Eden 区再次被填满,对 Eden区和 Survivor A 区同时进行垃圾回收,把存活对象放入 Survivor B区,同时清空 Eden 区和Survivor A 区;当某个 Survivor区被填满,把多余对象放到Old 区;当 Old 区也被填满时,进行 下一阶段的垃圾回收。下面看看老年代的垃圾回收。
(2)老年代-标记整理 回收机制
老年代的特点是:存活对象多、垃圾少。因此,根据老年代的特点,这里仅仅通过少量地移动对象就能清理垃圾,而且不存在内存碎片化。也就是标记整理的回收机制。既然是标记整理算法,而且老年代内部也不存在着内存划分,所以只需要根据标记整理的具体步骤进行垃圾回收就好了。
到了这,基本上对堆内存的分代回收机制进行了描述。但是要有一个问题没有解决,那就是jvm提供的垃圾回收器。
什么是垃圾?垃圾指所有不再存活的对象。
常见的判断是否存活有两种方法:引用计数法和可达性分析。
引用计数法
为每一个创建的对象分配一个引用计数器,用来存储该对象被引用的个数。当该个数为零,意味着没有人再使用这个对象,可以认为“对象死亡”。但是,这种方案存在严重的问题,就是无法检测“循环引用”:当两个对象互相引用,即时它俩都不被外界任何东西引用,它俩的计数都不为零,因此永远不会被回收。而实际上对于开发者而言,这两个对象已经完全没有用处了。
因此,Java 里没有采用这样的方案来判定对象的“存活性”。
可达性分析
基本思路是把所有引用的对象想象成一棵树,从树的根结点 GC Roots 出发,持续遍历找出所有连接的树枝对象,这些对象则被称为“可达”对象,或称“存活”对象。其余的对象则被视为“死亡”的“不可达”对象,或称“垃圾”。
12.java中锁的种类和基本原理?
1、分类
(1)乐观锁/悲观锁
(2)独享锁/共享锁
(3)互斥锁/读写锁
(4)可重入锁
(5)公平锁/非公平锁
(6)分段锁
(7)偏向锁/轻量级锁/重量级锁
(8)自旋锁
总结:以上是一些锁的名词,这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计。
2、基本原理
2.1 :乐观锁/悲观锁
(1)乐观锁与悲观锁是从设计理念上来分类的。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS(Compare and Swap 比较并交换)实现的。
(2)悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改自己的数据,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。比如Java里面的同步synchronized关键字的实现就是悲观锁。悲观锁适合写操作非常多的场景,乐观锁适合读操作非常多的场景,不加锁会带来大量的性能提升。
2.2:独享锁/共享锁
(1) 独享锁是指该锁一次只能被一个线程所持有,Java ReentrantLock就是独享锁,Synchronized也是独享锁。
(2)共享锁是指该锁可被多个线程所持有,Java ReadWriteLock其读锁是共享锁,其写锁是独享锁,读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的。
(3)独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。
(4)独享锁/共享锁是一种广义的说法。
2.3:互斥锁/读写锁
(1)互斥锁/读写锁是具体的实现。
(2)互斥锁在Java中的具体实现就是ReentrantLock,读写锁在Java中的具体实现就是ReadWriteLock。
2.4:可重入锁
可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁,ReetrantLock和Synchronized都是可重入锁。
13. collection和 collections的区别?
java.util.Collection 是一个集合接口(集合类的一个顶级接口)。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
14.java如何跳出循环?
continue:跳出本次循环,继续下一次循环,也就是不执行本次循环continue下面的语句。
break:跳出本层循环,也就是这个循环体的结束。
如何跳出多层循环呢?
可以使用break来实现。使用break loop直接跳出loop循环。
return:跳出这个方法
15.java排序有哪些?原理是什么?
冒泡排序
冒泡排序顾名思义就是像开水一样不断冒泡泡。简单地说,如果是将元素从小到大排序,每次就冒出一个最大的元素,放在数组的最后面。怎样保证冒一次泡后最大的元素就放在最后面了呢?冒泡排序是通过交换相邻元素来实现的。
快速排序算法通过多次比较和交换来实现排序,其排序流程如下: [2]
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。 [2]
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。 [2]
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。 [2]
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
选择排序
选择排序的思想:假如我们要从小到大排序,假设第一个元素arr[0]是最小的元素,然后将arr[0]与之后的所有元素依次比较,谁小谁就到前面来,遍历完以后整个数组中最小的元素就在arr[0]这个位置上了。再从arr[1]开始,假设arr[1]是最小的元素,arr[1]与之后所有的元素依次比较,谁小就到arr[1]这个位置上来。依次类推,当arr[arr.length-2]这个位置元素确定时,最后一个元素就在最后一个位置了,排序结束了
16.什么是堆栈?什么是内存溢出?有垃圾回收机制为什么还会出现内存溢出的情况?
堆栈就是只能在一端插入和删除数据的链表,这个端就叫做栈顶(top),最后一个添加的数据第一个被删除。因此,这也叫后进先出(LAST IN FIRST OUT)链表或是先进后出链表(FIRST IN LAST OUT)。
内存溢出(Out Of Memory,简称OOM)是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存。此时程序就运行不了,系统会提示内存溢出
有垃圾回收机制为什么还会出现内存溢出的情况?
内存资源是有限的,垃圾回收只回收垃圾,对于你的程序运行有用的对象不会被回收。
内存溢出分两种情况一种是栈溢出,比如调用了一个无限递归。还有一种是堆溢出,即new出来的对象没有即使销毁,比如一直new。
17.内存模型的理解?
18.泛型的理解?(泛型擦除)
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),
然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,
操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
擦除是将泛型类型以其父类代替,如String 变成了Object等。其实在使用的时候还是进行带强制类型的转化,只不过这是比较安全的转换,因为在编译阶段已经确保了数据的一致性。
19.java的基本类型有哪些,int占几个字节?byte占几个字节?
1)四种整数类型(byte、short、int、long): byte:8 位,用于表示最小数据单位,如文件中数据,-128~127 short:16 位,很少用,-32768 ~ 32767 int:32 位、最常用,-2^31-1~2^31 (21 亿) long:64 位、次常用 注意事项: int i=5; // 5 叫直接量(或字面量),即 直接写出的常数。 整数字面量默认都为 int 类型,所以在定义的 long 型数据后面加 L或 l。 小于 32 位数的变量,都按 int 结果计算。 强转符比数学运算符优先级高。见常量与变量中的例子。
2)两种浮点数类型(float、double): float:32 位,后缀 F 或 f,1 位符号位,8 位指数,23 位有效尾数。 double:64 位,最常用,后缀 D 或 d,1 位符号位,11 位指数,52 位有效尾 注意事项: 二 进 制 浮 点 数 : 1010100010=101010001.0*2=10101000.10*2^10(2次方)=1010100.010*2^11(3次方)= . 1010100010*2^1010(10次方) 尾数: . 1010100010 指数:1010 基数:2 浮点数字面量默认都为 double 类型,所以在定义的 float 型数据后面加F 或 f;double 类型可不写后缀,但在小数计算中一定要写 D 或 X.X float 的精度没有 long 高,有效位数(尾数)短。 float 的范围大于 long 指数可以很大。 浮点数是不精确的,不能对浮点数进行精确比较。
3)一种字符类型(char): char:16 位,是整数类型,用单引号括起来的 1 个字符(可以是一个中文字符),使用 Unicode 码代表字符,0~2^16-1(65535) 。 注意事项: 不能为 0个字符。 转义字符:\n 换行 \r 回车 \t Tab 字符 \" 双引号 \\ 表示一个\ 两字符 char 中间用“+”连接,内部先把字符转成 int 类型,再进行加法运算,char 本质就是个数!二进制的,显示的时候,经过“处理”显示为字符。
4)一种布尔类型(boolean):true 真 和 false 假。
20.常见的异常类有哪些?处理方式?
NullPointerException:当应用程序试图访问空对象时,则抛出该异常。
SQLException:提供关于数据库访问错误或其他错误信息的异常。
IndexOutOfBoundsException:指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
NumberFormatException:当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
FileNotFoundException:当试图打开指定路径名表示的文件失败时,抛出此异常。
IOException:当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。
ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出该异常。
处理方式
Java异常机制用到的几个关键字:try、catch、finally、throw、throws。
try -- 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
catch -- 用于捕获异常。catch用来捕获try语句块中发生的异常。
finally -- finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
throw -- 用于抛出异常。
throws -- 用在方法签名中,用于声明该方法可能抛出的异常。主方法上也可以使用throws抛出。如果在主方法上使用了throws抛出,就表示在主方法里面可以不用强制性进行异常处理,如果出现了异常,就交给JVM进行默认处理,则此时会导致程序中断执行。
21.枚举的了解?
枚举是列出某些有穷序列集的所有成员的程序,一个类里定义几个静态变量,每个变量都是这个类的实例。
22. final、 finally、 finalize关键字的区别? volatile关键字的了解?
final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System的gc()方法的时候,由垃圾回收器调用finalize(),回收垃圾。
volatile关键字的作用:
内存可见性
禁止指令重排
volatile不会让线程阻塞,响应速度比synchronized高
volatile和synchronized的区别(自加)
volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
synchronized和lock的用法区别
synchronized:在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
lock:需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁
23.在一个list中存放的 String类型的字符串,如何实现把其中所有带“王”的字符串从list中去除?
1.遍历集合for(String s:list)
2.判断遍历的对象中是否含有“王”if(s.indexOf(“王”)!=-1)
3.执行删除list.remove(s)
24.string a=“123”;string b=“123”;a+=b;生成了几个对象?
25.如何序列化和反序列化?序列化的目的?
序列化是指将Java对象转换为字节序列的过程,而反序列化则是将字节序列转换为Java对象的过程。
实现序列化:实现Serializable、Externalizable接口
实现反序列化:用ObjectInputStream(对象输入流)类包含一个readObject()方法用来“反序列化”一个对象
目的:
1)Java序列化就是把对象转换成字节序列,而Java反序列化就是把字节序列还原成Java对象。
2)采用Java序列化与反序列化技术,一是可以实现数据的持久化;二是可以对象数据的远程通信
1.sql优化有哪些?如何创建索引?创建索引的原则是什么?索引的优缺点?(索引失效的几种情况)
1、在表中建立索引,优先考虑where、group by使用到的字段(较频繁地作为查询条件且唯一性不太差),不会在where中用到的字段不建立索引,因为建立索引也需要系统的开销。
2、减少使用 * ,用列名代替
select * from user;
要写成 select userID, userName, userSalary from user;
因为在使用 * 的时候,数据库还得查询数据字典,进而解析得到列名,而直接写出列名效率会更高些。
3、避免在开头使用模糊查询(%),该查询数据库引擎会放弃索引进行全表扫描。
4、需要删除所有记录的时候,用truncate而不用detele
因为delete删除表的时候,会扫描整个表再一条一条删除;
而truncate会一次性删除整个表的所有内容,不进行扫描,效率高。
5、避免使用in和not in,会导致全表扫描
优化方式:如果是连续数值,用between代替;如果是子查询,用exists代替。
6、如果表名或列名过长,就使用别名,因为长的表名和列名也会消耗扫描时间。
如何创建索引?
建表时创建:
CREATE TABLE 表名(
字段名 数据类型 [完整性约束条件],
……,
[UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY
[索引名](字段名1 [(长度)] [ASC | DESC]) [USING 索引方法]
);
建表后创建:
ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY [索引名] (字段名1 [(长度)] [ASC | DESC]) [USING 索引方法];
或
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX 索引名 ON 表名(字段名) [USING 索引方法];
创建索引的原则是什么?
在mysql中使用索引的原则有以下几点:
1、 对于查询频率高的字段创建索引;
2、 索引的数目不宜太多
原因:a、每创建一个索引都会占用相应的物理空间;
b、过多的索引会导致insert、update、delete语句的执行效率降低;
3. 对于经常存取的列避免建立索引;
因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能.因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。因此,当修改性能远远大于检索性能时,不应该创建索引。
MySQL中索引的优点和缺点和使用原则
优点:
加快数据的查询速度
缺点:
创建索引会耗费时间和占用磁盘空间,并且随着数据量的增加所耗费的时间也会增加
2.sql如何去重?
mysql去除重复查询的方法:1、使用distinct,代码为【select distinct name from a where statesign=0】;2、使用group by,代码为【statesign=0 group by .】。
mysql去除重复查询的方法:
1:使用distinct
select distinct name from a where statesign=0
查询表a中的name字段,去除重复记录
2:使用group by
select name from a where statesign=0 group by name
查询表a中的name字段,分组,去除重复记录
内连接和外连接的区别?
内连接:指连接结果仅包含符合连接条件的行,参与连接的两个表都应该符合连接条件。
外连接:连接结果不仅包含符合连接条件的行同时也包含自身不符合条件的行。包括左外连接、右外连接和全外连接。
左外连接:左边表数据行全部保留,右边表保留符合连接条件的行。
右外连接:右边表数据行全部保留,左边表保留符合连接条件的行。
4.Java中何使用 Redis? Redis支持的数据类型及各数据类型的使用场景? redis如何解决数据过期?
1.在pom.xml引入redis依赖包
<!--SpringBoot在pom.xml中引入redis依赖包 重要!!!! --><!--redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
2.在application.properties中配置redis
##redis settings##本地连接spring.redis.host=127.0.0.1##使用默认端口spring.redis.port=6379##未设密码,默认pwd为空spring.redis.password=
配置RestTemplate 的序列化方式
Redis支持的数据类型及各数据类型的使用场景?
string
此类型和memcache相似,作为常规的key-value缓存应用。
例如微博数、粉丝数等
注:一个键最大能存储512MB
list
list列表是简单的字符串列表,按照插入顺序排序(内部实现为LinkedList),可以选择将一个链表插入到头部或尾部
常用命令 :lpush(添加左边元素),rpush,lpop(移除左边第一个元素),rpop,lrange(获取列表片段,LRANGE key start stop)等。
应用场景:Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。
zset
常用命令:zadd,zrange
实现方式:Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,跳跃表按score从小到大保存所有集合元素。使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。时间复杂度与红黑树相同,增加、删除的操作较为简单。
输入方式
应用场景:排行榜
redis如何解决数据过期?(如何持久化到硬盘)
在 Redis 中,是可以设置过期数据的,Redis 提供了两种的方式,用于删除过期的数据!
定期删除
惰性删除
Redis 默认 100ms 随即抽取部分设置过期时间的 key,过期了就删除。优点是避免长时间的在扫描过期 key,缺点是有些过期 key 无法被删除。
不扫描全部 key 的原因是,当设置了过期时间的 key 太多的情况下,会很耗时间,O(n) 的时间复杂度。
如果查询了某个过期 key,但定期删除没有删除掉,那就将其删除了。key 没过期就正常返回
如何持久化到硬盘
redis提供两种方式进行持久化,一种是RDB持久化
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
5.数据库表的设计注意事项有哪些?三大范式的了解?
表设计:
1、 数据库表命名,将业务和基础表区分,采用驼峰表示法等。
2、 排序字段,按照某种类型来排序(sortcode)最好不依赖id排序,这样方便我们查询记录时按照某种方式排序,而不依赖id。
3、 增加备注字段,虽然我们考虑了很多用户需要输入信息的需求,但是无论何时我们都不可能考虑全,因此可以定义一个备注字段,允许用户将其它的信息填写在这里。无论表设计的再神奇,那么还是加一个备注字段。
4、 添加时间,有添加时间可以明确知道记录什么时候添加的。
5、 修改时间,可以知道记录什么时候被修改了,一旦数据出现问题,可以根据修改时间来定位问题。比如某人在这个时间做了哪些事。
数据库的三范式是什么?
第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。
第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。
第三范式:任何非主属性不依赖于其它非主属性。
6.存储过程的了解和使用?
存储过程的概念
存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集。经编译后存储在数据库中。
存储过程是数据库中的一个重要对象,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。
可由应用程序通过一个调用来执行,而且允许用户声明变量。
存储过程的使用
1、创建一个存储过程
create procedure GetUsers()
begin
select * from user;
end;12345
2、调用存储过程
call GetUsers();12
3、删除存储过程
drop procedure if exists GetUsers;
7.数据库如何实现分页?百万级量的数据分页查询如何优化?
Mysql:limit
Oracle:rownum
百万级量的数据分页查询如何优化?
利用表的覆盖索引来加速分页查询
我们都知道,利用了索引查询的语句中如果只包含了那个索引列(覆盖索引),那么这种情况会查询很快。
因为利用索引查找有优化算法,且数据就在查询索引上面,不用再去找相关的数据地址了,这样节省了很多时间。另外Mysql中也有相关的索引缓存,在并发高的时候利用缓存就效果更好了。
8.数据库的乐观锁和悲观锁的理解和使用?
乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。
数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁。
使用悲观锁来实现:
在上面的场景中,商品信息从查询出来到修改,中间有一个处理订单的过程,使用悲观锁的原理就是,当我们在查询出goods信息后就把当前的数据锁定,直到我们修改完毕后再解锁。那么在这个过程中,因为goods被锁定了,就不会出现有第三者来对其进行修改了。
注:要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。
我们可以使用命令设置MySQL为非autocommit模式:
set autocommit=0;
9.数据库中字符串和日期的相互转换?(oracle和mysql的日期如何转换,oracle如何分页)
1、使用date_format
select * from day where date_format(dateTime,'%Y-%m-%d') > '2016-03-15'
2、日期转换还可以使用str_to_date()
select str_to_date(dateTime,'%Y-%m-%d %H:%i:%s')
3、oracle是to_date
10. union和 unionall区别?
UNION 会做去重和排序处理,UNION ALL只是简单地将两个结果集合并;因此UNION 效率比UNION ALL慢很多,
11. mysql的存储引擎有哪些?
12.事务的隔离级别有哪些?mysql和 oracle默认的隔离级别是什么?
事务隔离级别
(1)read uncommitted 未提交读
所有事务都可以看到没有提交事务的数据。
(2)read committed 提交读
事务成功提交后才可以被查询到。
(3)repeatable 重复读
同一个事务多个实例读取数据时,可能将未提交的记录查询出来,而出现幻读。mysql默认级别
mysql和 oracle默认的隔离级别是什么?
MySQL
mysql默认的事务处理级别是'REPEATABLE-READ',也就是可重复读
Oracle
默认系统事务隔离级别是READ COMMITTED,也就是读已提交
13.mysql如何行转列和列转行
行转列:
1.使用case...when....then 进行行转列
CASE <单值表达式>
WHEN <表达式值> THEN <SQL语句或者返回值>
列转行:
本质是将一列数据分散成一条记录显示出来
用UNION ALL将结果集加起来
14.如何查看mysql的sql的执行计划?
可以通过(explain+执行sql)查看sql的执行计划
查看心法:
1.首先从查询类型type列开始查看,如果出现all关键字,那么不用继续看了,全表扫描了
2.查看key列,看是否使用了索引,null代表没有使用索引
3.查看rows列,该列代表在SQL执行过程中被扫描的行数,该数值越大,意味着需要扫描的行数越多,相应的耗时就更长
15. oracle中的分析函数有哪些?
--------------聚合函数
SUM :该函数计算组中表达式的累积和
MIN :在一个组中的数据窗口中查找表达式的最小值
MAX :在一个组中的数据窗口中查找表达式的最大值
AVG :用于计算一个组和数据窗口内表达式的平均值。
COUNT :对一组内发生的事情进行累积计数
16.数据库中除了聚合函数之外还有哪些常用的函数? oracle数据库 merge()函数的作用和使用?
除了聚合函数之外还有哪些常用的函数
destinct(去除重复行)
to_char(转换自符串)
to_date(日期格式函数)
substr(截取自符串)
lower(将字母转换为小写)
upper(将字母转换为小写)
oracle数据库 merge()函数的作用和使用?
能够在一个SQL语句中对一个表同时执行inserts和updates操作. MERGE命令从一个或多个数据源中选择行来updating或inserting到一个或多个表
比如向数据库插入一条数据 如果ID和name都相同 就更新AGE的数据,否则就插入
17.sql中drop、 truncate、 delete的区别?
drop:drop table 表名
删除内容和定义,并释放空间。执行drop语句,将使此表的结构一起删除。
truncate (清空表中的数据):truncate table 表名
删除内容、释放空间但不删除定义(也就是保留表的数据结构)。与drop不同的是,只是清空表数据而已。
truncate不能删除行数据,虽然只删除数据,但是比delete彻底,它只删除表数据。
delete:delete from 表名 (where 列名 = 值)
与truncate类似,delete也只删除内容、释放空间但不删除定义;但是delete即可以对行数据进行删除,也可以对整表数据进行删除。
都删除整张表的话
TRUNCATE TABLE 速度更快,占用的日志更少,这是因为 TRUNCATE TABLE 直接释放数据页并且在事务日志中也只记录数据页的释放,而 DELETE 是一行一行地删除,在事务日志中要记录每一条记录的删除
18.mysql如何忽略表名的大小写?
找到你mysql的配置文件my.ini(linux下是my.cnf),打开后找到“[mysqld]”节点,在下面加上一句话:
lower_case_table_names=1
即可,重启mysql,就不用担心表名的大小写问题了。
19. having和 where的区别?
having是在分组后对数据进行过滤
where是在分组前对数据进行过滤
having后面可以使用聚合函数
where后面不可以使用聚合
在查询过程中执行顺序:from>where>group(含聚合)>having>order>select
20.游标的作用和使用?
游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标充当指针的作用。尽管游标能遍历结果中的所有行,但他一次只指向一行。
游标可以被看作是一个查询结果集和结果集中指向特定记录的游标位置组成的一个临时文件,提供了在查询结果集中向前或向后浏览数据、处理结果集中数据的能力
1 作用: 用来存储查询结果集的
2 使用: 遍历游标中的数据, 相当于有一个指针指向游标中的第一行数据,每获取一行记录,指针向下移一行
3 语法格式
1 声明游标
1 格式
declare cursor_name cursor for select_statement
2 格式介绍
1 cursor_name:游标名称,存储sql语句执行的结果
2 select_statement:sql语句
2 打开游标
1 格式
open cursor_name;
3 遍历游标中的数据
1 介绍
1 相当于有一个指针指向游标中的第一行数据,每获取一行记录,指针向下移一行
2 格式
fetch cursor_name into var_name [, var_name] ...
3 格式介绍
1 一行fetch只能获取游标中的一行记录,并把记录中每一列的值赋值给var_name
2 一个var_name保存一行记录中一个列的值,若有多个列,需要多个变量
3 要输出游标中的所有数据,需要使用循环语句
4 关闭游标
1 格式
close cursor_name;
21.如何使用数据库中的定时器、触发器、定时任务?
如何使用数据库中的定时器
create一个event on schedule 后跟时间
整体流程简介:
1.开启mysql数据库的event功能
2.创建一个类似于要执行的代码块。
3.创建一个事件,这个事件中有诸多属性,可以设置执行时间间隔以及指定执行的代码块
4.因为创建的事件的执行属性默认是关闭的,所以我们要去修改这个事件的属性为开启。
触发器
CREATE TRIGGER trigger_name trigger_time trigger_event
ON tbl_name FOR EACH ROW trigger_stmt
其中trigger_name标识触发器名称,用户自行指定;
trigger_time标识触发时机,用before和after替换;
trigger_event标识触发事件,用insert,update和delete替换;
tbl_name标识建立触发器的表名,即在哪张表上建立触发器;
trigger_stmt是触发器程序体;触发器程序可以使用begin和end作为开始和结束,中间包含多条语句;
定时任务
#创建计划任务
CREATE EVENT IF NOT EXISTS testInsert
ON SCHEDULE EVERY 3 SECOND
ON COMPLETION PRESERVE
DO INSERT INTO aa(`name`,sex) VALUES('aa',2),('bb',1);
#开启计划任务
ALTER EVENT testInsert ENABLE;
#关闭计划任务
ALTER EVENT testInsert DISABLE;
22. oracle中如何实现递归查询?
在oracle中使用 start with 条件一
connect by prior 条件二
where 条件三
23.高并发下如何保证修改数据安全?
乐观锁 悲观锁 Synchronized Lock
24. oracle中如何实现主键自增?
Oracle没有”auto_increment”属性,所以它没法像MySQL般在表内定义自增主键。
但是Oracle里的序列(SEQUENCE),可间接实现自增主键的作用
25. delete误删数据没有备份怎么恢复?
可以使用数据库闪回
--得到一个当前序列号.
select dbms_flashback.get_system_change_number scn from dual;
--7827319是序列号
select * from table as of scn 7827319;
你可以慢慢减序列号,直到你能查询到数据.
例如, 我删除数据提交, Oracle会给这个操作一个序列号. 然后每一次操作都会生成序列号.
你用 as of scn 序列 查询时, 查询当时那个操作的数据情况.
26. oracle死锁如何处理?
--1.查看数据库中那些用户产生了锁
--2.杀掉ORACLE进程:
--3.查找并杀死死锁的进程
1. spring的特性是什么?ioc和aop的原理是什么?aop的注解有哪些?
Spring拥有两大特性:IoC和AOP。IoC,英文全称Inversion of Control,意为控制反转。AOP,英文全称Aspect-Oriented Programming,意为面向切面编程。
ioc:控制反转,简单点说,就是创建对象的控制权,被反转到了Spring框架上
aop:面向切面编程 将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面", 简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码, 降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
aop注解:
(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可
(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值
(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名
来访问目标方法中所抛出的异常对象
(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式
(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint
2. springboot自动装配原理是什么? springboot 配置文件中常用配置有哪些
SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration
将类路径下META-INF/spring.factories里面配置的所有EnableAutoConfiguration的值加入到了容器中
properties文件和yml文件
3. Springboot项目如何打包、部署、运行?
用idea开发工具右侧的maven projects intall package 然后就会出来我们需要的jar
然后到这个jar的根目录下执行java -jar smallsystem-0.0.1-SNAPSHOT.jar
4. spring是如何控制事务的?
使用注解配置
使用@Transactional注解 需要在配置文件中开启对这个注解的扫描:<tx:annotation-driven transaction-manager=“transactionManager” />,引用了事务管理器
然后就可以使用@Transactional注解,此注解可以使用在类上,也可以使用在方法上,使用在类上即对此类的所有方法都起作用,使用在方法上则表示对单个方法起作用
5. springmvc常用注解及作用?
1、@Controller
在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。
2、@RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
3、@Resource和@Autowired
@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
4、@PathVariable
用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。如:
7、@ResponseBody
作用:将方法的返回值,以特定的格式写入到response的body区域,进而将数据返回给客户端。
如果返回值是字符串,那么直接将字符串写到客户端;如果是一个对象,会将对象转化为json串,然后写到客户端。