1.java是如何实现跨平台的
注意:跨平台的是 Java 程序,而不是 JVM。JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 JVM
答:我们编写的 Java 源码,编译后会生成一种 .class 文件,称为字节码文件。Java 虚拟机(JVM)就是负责将字节码文件翻译成特定平台下的机器码然后运行,也就是说,只要在不同平台上安装对应的 JVM,就可以运行字节码文件,运行我们编写的 Java 程序。
而这个过程,我们编写的 Java 程序没有做任何改变,仅仅是通过 JVM 这一 “中间层” ,就能在不同平台上运行,真正实现了 “一次编译,到处运行” 的目的。
2.类加载器有了解吗
解析:底层原理的考察,其中涉及到类加载器的概念,功能以及一些底层的实现。
答:顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。
类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。
3.JVM的特性
JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完成,通过下面4步来完成JVM环境.
创建JVM装载环境和配置
装载JVM.dll
初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例
调用JNIEnv实例装载并处理class类。
4.JVM的内存分配
方法区(线程共享):各个线程共享的一个区域,用于存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却又一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。
运行时常量池:是方法区的一部分,用于存放编译器生成的各种字面量和符号引用。
堆内存(线程共享):所有线程共享的一块区域,垃圾收集器管理的主要区域。目前主要的垃圾回收算法都是分代收集算法,所以 Java 堆中还可以细分为:新生代和老年代;再细致一点的有 Eden 空间、From Survivor 空间、To Survivor 空间等,默认情况下新生代按照8:1:1的比例来分配。根据 Java 虚拟机规范的规定,Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘一样。
程序计数器: Java 线程私有,类似于操作系统里的 PC 计数器,它可以看做是当前线程所执行的字节码的行号指示器。如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。
虚拟机栈(栈内存):Java线程私有,虚拟机展描述的是Java方法执行的内存模型:每个方法在执行的时候,都会创建一个栈帧用于存储局部变量、操作数、动态链接、方法出口等信息;每个方法调用都意味着一个栈帧在虚拟机栈中入栈到出栈的过程;
本地方法栈 :和Java虚拟机栈的作用类似,区别是该区域为 JVM 提供使用 native 方法的服务
5.java的内存模型
Java 虚拟机规范中试图定义一种 Java 内存模型(Java Memory Model, JMM)来屏蔽掉各层硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。
Java 内存模型规定了所有的变量都存储在主内存(Main Memory)中。每条线程还有自己的工作内存(Working Memory),线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在主内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程间的变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者的关系
6.两个线程之间是如何通信的
在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信,典型的共享内存通信方式就是通过共享对象进行通信。
java创建一个对象的过程
Java中对象的创建就是在堆上分配内存空间的过程,此处说的对象创建仅限于new关键字创建的普通Java对象,不包括数组对象的创建。
大致过程如下:
1.检测类是否被加载:
当虚拟机执行到new时,会先去常量池中查找这个类的符号引用。如果能找到符号引用,说明此类已经被加载到方法区(方法区存储虚拟机已经加载的类的信息),可以继续执行;如果找不到符号引用,就会使用类加载器执行类的加载过程,类加载完成后继续执行。
2.为对象分配内存:
类加载完成以后,虚拟机就开始为对象分配内存,此时所需内存的大小就已经确定了。只需要在堆上分配所需要的内存即可。
具体的分配内存有两种情况:第一种情况是内存空间绝对规整,第二种情况是内存空间是不连续的。
对于内存绝对规整的情况相对简单一些,虚拟机只需要在被占用的内存和可用空间之间移动指针即可,这种方式被称为指针碰撞。
对于内存不规整的情况稍微复杂一点,这时候虚拟机需要维护一个列表,来记录哪些内存是可用的。分配内存的时候需要找到一个可用的内存空间,然后在列表上记录下已被分配,这种方式成为空闲列表。
分配内存的时候也需要考虑线程安全问题,有两种解决方案:
第一种是采用同步的办法,使用CAS来保证操作的原子性。
另一种是每个线程分配内存都在自己的空间内进行,即是每个线程都在堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB),分配内存的时候再TLAB上分配,互不干扰。
3.为分配的内存空间初始化零值:
对象的内存分配完成后,还需要将对象的内存空间都初始化为零值,这样能保证对象即使没有赋初值,也可以直接使用。
4.对对象进行其他设置:
分配完内存空间,初始化零值之后,虚拟机还需要对对象进行其他必要的设置,设置的地方都在对象头中,包括这个对象所属的类,类的元数据信息,对象的hashcode,GC分代年龄等信息。
5.执行 init 方法:
执行完上面的步骤之后,在虚拟机里这个对象就算创建成功了,但是对于Java程序来说还需要执行init方法才算真正的创建完成,因为这个时候对象只是被初始化零值了,还没有真正的去根据程序中的代码分配初始值,调用了init方法之后,这个对象才真正能使用。
到此为止一个对象就产生了,这就是new关键字创建对象的过程。
7.java中堆和栈的区别
JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。
接口的意义
接口的意义用三个词就可以概括:规范,扩展,回调.
代码中是如何实现多态
实现多态主要有以下三种方式:
1. 接口实现
2. 继承父类重写方法
3. 同一类中进行方法重载
什么是不可变对象
不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer及其它包装类
8.静态变量和实例变量的区别
静态变量存储在方法区,属于类所有.实例变量存储在堆当中,其引用存在当前线程栈
java创建对象的几种方式
采用new
通过反射
采用clone
通过序列化机制
前2者都需要显式地调用构造方法. 造成耦合性最高的恰好是第一种,因此你发现无论什么框架,只要涉及到解耦必先减少new的使用.
9.你对string对象的intern()了解吗?
intern()方法会首先从常量池中查找是否存在该常量值,如果常量池中不存在则现在常量池中创建,如果已经存在则直接返回.
比如
String s1=”aa”;
String s2=s1.intern();
System.out.print(s1==s2);//返回true
10.java的四种引用
强引用,软引用,弱引用,虚引用.不同的引用类型主要体现在GC上:
强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象
软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象
虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。
11.内部类的作用
内部类可以有多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立.在单个外围类当中,可以让多个内部类以不同的方式实现同一接口,或者继承同一个类.创建内部类对象的时刻不依赖于外部类对象的创建.内部类并没有令人疑惑的”is-a”关系,它就像是一个独立的实体.
内部类提供了更好的封装,除了该外围类,其他类都不能访问
12.深拷贝和浅拷贝的区别
浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
13.static都有哪些用法
乎所有的人都知道static关键字这两个基本的用法:静态变量和静态方法.也就是被static所修饰的变量/方法都属于类的静态资源,类实例所共享.
除了静态变量和静态方法之外,static也用于静态块,多用于初始化操作:
此外static也多用于修饰内部类,此时称之为静态内部类.
最后一种用法就是静态导包,即import static.import static是在JDK 1.5之后引入的新特性,可以用来指定导入某个类中的静态资源,并且不需要使用类名.资源名,可以直接使用资源名
14.创建两个种线程的方式?他们有哪些区别
通过实现java.lang.Runnable或者通过扩展java.lang.Thread类.相比扩展Thread,实现Runnable接口可能更优.原因有二:
Java不支持多继承.因此扩展Thread类就代表这个子类不能扩展其他类.而实现Runnable接口的类还可能扩展另一个类.
类可能只要求可执行即可,因此继承整个Thread类的开销过大.
15.Thread类中的start()和run()方法有什么区别
start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
16.Runnable和Callable的区别
Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。
这其实是很有用的一个特性,因为多线程相比单线程更难、更复杂的一个重要原因就是因为多线程充满着未知性,某条线程是否执行了?某条线程执行了多久?某条线程执行的时候我们期望的数据是否已经赋值完毕?无法得知,我们能做的只是等待这条多线程的任务执行完毕而已。而Callable+Future/FutureTask却可以方便获取多线程运行的结果,可以在等待时间太长没获取到需要的数据的情况下取消该线程的任务
17.什么是多线程上下文切换
多线程的上下文切换是指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程.
一个线程如果出现了运行时异常怎么办
如果这个异常没有被捕获的话,这个线程就停止执行了。另外重要的一点是:如果这个线程持有某个某个对象的监视器,那么这个对象监视器会被立即释放
如何在两个线程间共享数据
通过在线程之间共享对象就可以了,然后通过wait/notify/notifyAll、await/signal/signalAll进行唤起和等待,比方说阻塞队列BlockingQueue就是为线程之间共享数据而设计的
线程的局部变量
线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java提供ThreadLocal类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。
18.jdk1.7的特性
然 JDK 1.7 不像 JDK 5 和 8 一样的大版本,但是,还是有很多新的特性,如 try-with-resource 语句,这样你在使用流或者资源的时候,就不需要手动关闭,Java 会自动关闭。Fork-Join 池某种程度上实现 Java 版的 Map-reduce。允许 Switch 中有 String 变量和文本。菱形操作符(\<>)用于类型推断,不再需要在变量声明的右边申明泛型,因此可以写出可读写更强、更简洁的代码
19.jdk1.8的特性
java 8 在 Java 历史上是一个开创新的版本,下面 JDK 8 中 5 个主要的特性:
Lambda 表达式,允许像对象一样传递匿名函数
Stream API,充分利用现代多核 CPU,可以写出很简洁的代码
Date 与 Time API,最终,有一个稳定、简单的日期和时间库可供你使用
扩展方法,现在,接口中可以有静态、默认方法。
重复注解,现在你可以将相同的注解在同一类型上使用多次。
20.如何格式化日期
Java 中,可以使用 SimpleDateFormat 类或者 joda-time 库来格式日期。DateFormat 类允许你使用多种流行的格式来格式化日期。参见答案中的示例代码,代码中演示了将日期格式化成不同的格式,如 dd-MM-yyyy 或 ddMMyyyy。
21Mavernhe 和 ANT的区别
虽然两者都是构建工具,都用于创建 Java 应用,但是 Maven 做的事情更多,在基于“约定优于配置”的概念下,提供标准的Java 项目结构,同时能为应用自动管理依赖(应用中所依赖的 JAR 文件.
22.如何实施打印日志
导入jar包
配置log4j.properties文件
创建工具类(接口)
使用(核心代码介绍)
23.linux的常用命令有哪些
1.man 对你熟悉或不熟悉的命令提供帮助解释
注:按q键或者ctrl+c退出,在linux下可以使用ctrl+c终止当前程序运行。
2. cp 拷贝文件
3. rm 删除文件和目录
eg: rm 1.c //将1.c这个文件删除
4. mv 移走目录或者改文件名
eg: mv filename1 filename2 //将filename1 改名为filename2
5. cd 改变当前目录 pwd 查看当前所在目录完整路径
eg: pwd //查看当前所在目录路径
6. cat,more命令
将某个文件的内容显示出来。两个命令所不同的是:cat把文件内容一直打印出来,而 more则分屏显示
eg; cat>1.c //就可以把代码粘帖到1.c文件里,按ctrl+d 保存代码。
cat 1.c 或more 1.c //都可以查看里面的内容。
gcc -o 1 1.c //将1.c编译成.exe文件,我们可以用此命编译出代码。
7.chmod 命令 权限修改 用法:chmod 一位8进制数 filename。
eg: chmod u+x filenmame //只想给自己运行,别人只能读
//u表示文件主人, g 表示文件文件所在组。 o 表示其他人 ;r 表可读,w 表可写,x 表可以运行
chmod g+x filename //同组的人来执行
8. clear,date命令`
clear:清屏,相当与DOS下的cls;date:显示当前时间。
9. mount 加载一个硬件设备
用法:mount [参数] 要加载的设备 载入点
eg: mount /dev/cdrom
cd /mnt/cdrom //进入光盘目录
24.mysql语句优化
选取最适用的字段属性。
MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。
2、使用连接(JOIN)来代替子查询(Sub-Queries)。
MySQL从4.1开始支持SQL的子查询。这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。
3、使用联合(UNION)来代替手动创建的临时表。
MySQL 从4.0的版本开始支持UNION查询,它可以把需要使用临时表的两条或更多的SELECT查询合并的一个查询中。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。
4、事务。
要把某个数据同时插入两个相关联的表中,可能会出现这样的情况:第一个表中成功更新后,数据库突然出现意外状况,造成第二个表中的操作没有完成,这样,就会造成数据的不完整,甚至会破坏数据库中的数据。要避免这种情况,就应该使用事务,它的作用是:要么语句块中每条语句都操作成功,要么都失败。
5、锁定表。
尽管事务是维护数据库完整性的一个非常好的方法,但却因为它的独占性,有时会影响数据库的性能,尤其是在很大的应用系统中。由于在事务执行的过程中,数据库将会被锁定,因此其它的用户请求只能暂时等待直到该事务结束。
6、使用外键。
锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。
7、使用索引
索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(), MIN()和ORDERBY这些命令的时候,性能提高更为明显。
8、优化的查询语句
绝大多数情况下,使用索引可以提高查询的速度,但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用。
25.mysql存储引擎有哪些区别
MyISAM:
不支持事务,但是每次查询都是原子的;
支持表级锁,即每次操作是对整个表加锁;
存储表的总行数;
一个MYISAM表有三个文件:索引文件、表结构文件、数据文件;
采用菲聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不用保证唯一性。
InnoDb:
支持ACID的事务,支持事务的四种隔离级别;
支持行级锁及外键约束:因此可以支持写并发;
不存储总行数;
一个InnoDb引擎存储在一个文件空间(共享表空间,表大小不受操作系统控制,一个表可能分布在多个文件里),也有可能为多个(设置为独立表空,表大小受操作系统文件大小限制,一般为2G),受操作系统文件大小的限制;
主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要先通过辅索引找到主键值,再访问辅索引;最好使用自增主键,防止插入数据时,为维持B+树结构,文件的大调整。
mysql常用引擎有MYISAM和InnoDB,而InnoDB是mysql默认的引擎。MYISAM不支持行锁,而InnoDB支持行锁和表锁。
1.行锁和表锁
2.行锁的类型
3.行锁的实现
1.行锁和表锁
在mysql 的 InnoDB引擎支持行锁,与Oracle不同,mysql的行锁是通过索引加载的,即是行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,
行锁则无法实现,取而代之的是表锁。
表锁:不会出现死锁,发生锁冲突几率高,并发低。
行锁:会出现死锁,发生锁冲突几率低,并发高。
锁冲突:例如说事务A将某几行上锁后,事务B又对其上锁,锁不能共存否则会出现锁冲突。(但是共享锁可以共存,共享锁和排它锁不能共存,排它锁和排他锁也不可以)
死锁:例如说两个事务,事务A锁住了1~5行,同时事务B锁住了6~10行,此时事务A请求锁住6~10行,就会阻塞直到事务B施放6~10行的锁,而随后事务B又请求锁住1~5行,事务B也阻塞直到事务A释放1~5行的锁。死锁发生时,会产生Deadlock错误。
锁是对表操作的,所以自然锁住全表的表锁就不会出现死锁。
Mysql数据库隔离级别和传播行为:
MY SUN与INNODB的区别?
Innodb不支持全文
26.什么是乐观锁和悲观锁
乐观锁:乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-替换这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么就应该有相应的重试逻辑。
悲观锁:悲观锁认为竞争总是会发生,因此每次对某资源进行操作时,都会持有一个独占的锁,就像synchronized,不管三七二十一,直接上了锁就操作资源了。
27.单点登录的实现原理
相比于单系统登录,sso需要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。这个过程,也就是单点登录的原理
28.扫码登录的实现原理
原理解释
网页端+服务器
原理:用户打开网站的登录页面的时候,向浏览器的服务器发送获取登录二维码的请求。服务器收到请求后,随机生成一个uuid,将这个id作为key值存入redis服务器,同时设置一个过期时间,再过期后,用户登录二维码需要进行刷新重新获取。同时,将这个key值和本公司的验证字符串合在一起,通过二维码生成接口,生成一个二维码的图片(二维码生成,网上有很多现成的接口和源码,这里不再介绍。)然后,将二维码图片和uuid一起返回给用户浏览器。
浏览器拿到二维码和uuid后,会每隔一秒向浏览器发送一次,登录是否成功的请求。请求中携带有uuid作为当前页面的标识符。这里有的同学就会奇怪了,服务器只存了个uuid在redis中作为key值,怎么会有用户的id信息呢?
这里确实会有用户的id信息,这个id信息是由手机服务器存入redis中的。具体操作如下:
手机端+服务器
话说,浏览器拿到二维码后,将二维码展示到网页上,并给用户一个提示:请掏出您的手机,打开扫一扫进行登录。用户拿出手机扫描二维码,就可以得到一个验证信息和一个uuid(扫描二维码获取字符串的功能在网上同样有很多demo,这里就不详细介绍了)。由于手机端已经进行过了登录,在访问手机端的服务器的时候,参数中都回携带一个用户的token,手机端服务器可以从中解析到用户的userId(这里从token中取值而不是手机端直接传userid是为了安全,直接传userid可能会被截获和修改,token是加密的,被修改的风险会小很多)。手机端将解析到的数据和用户token一起作为参数,向服务器发送验证登录请求(这里的服务器是手机服务器,手机端的服务器跟网页端服务器不是同一台服务器)。服务器收到请求后,首先对比参数中的验证信息,确定是否为用户登录请求接口。如果是,返回一个确认信息给手机端。
手机端收到返回后,将登录确认框显示给用户(防止用户误操作,同时使登录更加人性化)。用户确认是进行的登录操作后,手机再次发送请求。服务器拿到uuId和userId后,将用户的userid作为value值存入redis中以uuid作为key的键值对中。
登录成功
然后,浏览器再次发送请求的时候,浏览器端的服务器就可以得到一个用户Id,并调用登录的方法,声成一个浏览器端的token,再浏览器再次发送请求的时候,将用户信息返回给浏览器,登录成功。这里存储用户id而不是直接存储用户信息是因为,手机端的用户信息,不一定是和浏览器端的用户信息完全一致。
mysql的索引优化
主键就是聚集索引
2、只要建立索引就能显著提高查询速度
3、把所有需要提高查询速度的字段都加进聚集索引,以提高查询速度
(四)其他书上没有的索引使用经验总结
1、用聚合索引比用不是聚合索引的主键速度快
2、用聚合索引比用一般的主键作order by时速度快,特别是在小数据量情况下
3、使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个
4 、日期列不会因为有分秒的输入而减慢查询速度
(五)其他注意事项
1. 不要索引常用的小型表
2. 不要把社会保障号码(SSN)或身份证号码(ID)选作键
3. 不要用用户的键
4. 不要索引 memo/notes 字段和不要索引大型文本字段(许多字符)
5. 使用系统生成的主键
二、改善SQL语句
1、Like语句是否属于SARG取决于所使用的通配符的类型
2、or 会引起全表扫描
3、非操作符、函数引起的不满足SARG形式的语句
4、IN 的作用相当与OR
5、尽量少用NOT
6、exists 和 in 的执行效率是一样的
7、用函数charindex()和前面加通配符%的LIKE执行效率一样
8、union并不绝对比or的执行效率高
9、字段提取要按照“需多少、提多少”的原则,避免“select *”
10、count(*)不比count(字段)慢
11、order by按聚集索引列排序效率最高
12、高效的TOP
29.分布式与集群的区别
分布式是以缩短单个任务的执行时间来提升效率的,而集群则是通过提高单位时间内执行的任务数来提升效率。
30.Get和Post的区别
1.get是从服务器上获取数据,post是向服务器传送数据,
2.get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。
3.get安全性非常低,post安全性较高。但是执行效率却比Post方法好。
4.在进行文件上传时只能使用post而不能是get。
31.JAVA面向对象编程的特征
面向对象编程有四个特征:抽象,封装,继承,多态。
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者 对象操作,对不可信的进行信息隐藏。
继承是指使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组 合”(Composition)来实现。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情 况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
多态有四种体现形式:(JAVA多态的具体体现)
1. 接口和接口的实现。
2. 类和类的继承。
3. 重载:重载发生在同一个类中,在该类中如果存在多个同名方
法,但是方法的参数类型和个数不一样,那么说明该方法被重
载了。
4. 重写:重写发生在子类继承父类的关系中,父类中的方法被子
类继承,方法名,返回值类型,参数完全一样,但是方法体不
一样,那么说明父类中的该方法被子类重写了。
String 字符串常量 不可变 使用字符串拼接时是不同的2个空间
StringBuffer 字符串变量 可变 线程安全 字符串拼接直接在字符串后追加
StringBuilder 字符串变量 可变 非线程安全 字符串拼接直接在字符串后追加
1.StringBuilder执行效率高于StringBuffer高于String.
2.String是一个常量,是不可变的,所以对于每一次+=赋值都会创建一个新的对象, StringBuffer和StringBuilder都是可变的,当进行字符串拼接时采用append方 法,在原来的基础上进行追加,所以性能比String要高,又因为StringBuffer 是 线程安全的而StringBuilder是线程非安全的,所以StringBuilder的效率高于 StringBuffer.
3.对于大数据量的字符串的拼接,采用StringBuffer,StringBuilder.
HashMap不是线程安全的,HashTable是线程安全。
HashMap允许空(null)的键和值(key),HashTable则不允许。
HashMap性能优于Hashtable。
Map
1.Map是一个以键值对存储的接口。Map下有两个具体的实现,分别是HashMap和HashTable.
2.HashMap是线程非安全的,HashTable是线程安全的,所以HashMap的效率高于HashTable.
3.HashMap允许键或值为空,而HashTable不允许键或值为空.
输入/输出对象:
request表示HttpServletRequest对象。它包含了有关浏览器请求的信息,并且提供了几个用于获取 cookie, header, 和session数据的有用的方法。
response表示HttpServletResponse对象,并提供了几个用于设置送回 浏览器的响应的方法(如 cookies,头信息等)
out是javax.jsp.JspWriter的一个实例,提供了几个方法使你能用于向浏览器回送输出结果。
作用域通信对象:
session表示一个请求的javax.servlet.http.HttpSession对象。Session可以存贮用户的状态信息。
application 表示一个javax.servle.ServletContext对象。这有助于查找有关servlet引擎和 servlet环境的信息
pageContext 表示一个javax.servlet.jsp.PageContext对象。它是用于方便存取各种范围的名字空 间、servlet相关的对象的API,并且包装了通用的servlet相关功能的方法。
Servlet 对象:
page 表示从该页面产生的一个servlet实例
config 表示一个javax.servlet.ServletConfig对象。该对象用于存取servlet实例的初始化参数。
错误对象: exception
1、从数据共享上
Forword是一个请求的延续,可以共享request的数据
Redirect开启一个新的请求,不可以共享request的数据
2、从地址栏
Forword转发地址栏不发生变化
Redirect转发地址栏发生变化
Xml特点:
1、有且仅有一个根节点;
2、是独立与软件和硬件的信息传输工具(传输量较大)
3、所有的标签都需要自定义
4、仅仅是纯文本文件
Json(JavaScript Object Notation)特点:
json分为两种格式: json对象(就是在{}中存储键值对,键和值之间用冒号分隔, 键 值 对之间用逗号分隔),json数组(就是[]中存储多个json对象,json对象之间用逗号分隔)(两者间可以进行相互嵌套)
数据传输的载体之一
区别:
xml的传输数据量比json的要大,流行的是基于json的数据传输。
共同点:
Xml和json都是传输数据的载体,并且具有跨平台跨语言的特性。
Ajax的核心是JavaScript对象XmlHttpRequest(XHR)。
Ajax的优点:
提高用户体验度(UE)
提高应用程序的性能
进行局部刷新
AJAX不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 Web 应用程序的技术。
2. 通过 AJAX,我们的 JavaScript 可使用JavaScript的XMLHttpRequest对象来直接与服务器进行通信。通过这个对象,我们的 JavaScript 可在不重载页面的情况与Web服务器交换数据,即可局部刷新。
3. AJAX 在浏览器与 Web 服务器之间使用异步数据传输(HTTP 请求),这样就可使网页从服务器请求少量的信息,而不是整个页面,减轻服务器的负担,提升站点的性能。
AJAX 可使因特网应用程序更小、更快,更友好,用户体验(UE)好。
四个作用域从大到小:appliaction>session>request>page
application:全局作用范围,整个应用程序共享.生命周期为:应用程序启动到停止。
session:会话作用域,当用户首次访问时,产生一个新的会话,以后服务器就可以记 住这个会话状态。
request:请求作用域,就是客户端的一次请求。
page:一个JSP页面。
以上作用范围使越来越小, request和page的生命周期都是短暂的,他们之间的区别就是:一个request可以包含多个page页(include,forward)。
数据类型 大小
byte(字节) 1(8位)
shot(短整型) 2(16位)
int(整型) 4(32位)
long(长整型) 8(32位)
float(浮点型) 4(32位)
double(双精度) 8(64位)
char(字符型) 2(16位)
boolean(布尔型) 1位
1.线程(Thread)与进程(Process)
进程定义的是应用程序与应用程序之间的边界,通常来说一个进程就代表一个与之对应的应用程序。不同的进程之间不能共享代码和数据空间,而同一进程的不同线程可以共享代码和数据空间。
内存泄露 (memory leak),是指应用程序在申请内存后,
无法释放已经申请的内存空间.一次内存泄露危害可以忽略,
但如果任其发展最终会导致内存溢出(out of memory).
如读取文件后流要进行及时的关闭以及对数据库连接的释放。
内存溢出(out of memory)是指应用程序在申请内存时,
没有足够的内存空间供其使用。
如我们在项目中对于大批量数据的导入,采用分段批量提交的方式。
1、 解析xml的几种技术
dom4j:是一个Java的XML API,类似于jdom,用来读写XML文件的。dom4j 是一个非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点, 同时它也是一个开放源代码的软件。
sax:(simple API for XML)是一种XML解析的替代方法。相比于DOM,SAX是一种 速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX 可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就 是操作复杂。
Jaxb:(Java Architecture for XML Binding) 是一个业界的标准,是一项可以 根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向 生 成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档。从另一 方面 来讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得 Java开 发者在Java应用程序中能方便地结合XML数据和处理函数。
2、dom4j 与 sax 之间的对比:【注:必须掌握!】
dom4j不适合大文件的解析,因为它是一下子将文件加载到内存中,所以有可能出现内存溢出,
sax是基于事件来对xml进行解析的,所以他可以解析大文件的xml
也正是因为如此,所以dom4j可以对xml进行灵活的增删改查和导航,而sax没有这么强的灵活性
所以sax经常是用来解析大型xml文件,而要对xml文件进行一些灵活(crud)操作就用dom4j
1.需求分析
2.概要设计
3.详细设计(用例图,流程图,类图)
4.数据库设计(powerdesigner)
5.代码开发(编写)
6.单元测试(junit 白盒测试)(开发人员)
svn版本管理工具(提交,更新代码,文档)
7.集成测试 (黑盒测试,loadrunner(编写测试脚本)(高级测试))
8.上线试运行 (用户自己体验)
9.压力测试(loadrunner)
10.正式上线
11.维护
java 异常是程序运行过程中出现的错误。Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。在Java API中定义了许多异常类,分为两大类,错误Error和异常Exception。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常(非runtimeException),也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。
1、Error与Exception
Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。
这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。程序中应当尽可能去处理这些异常。
2、运行时异常和非运行时异常
运行时异常: 都是RuntimeException类及其子类异常: IndexOutOfBoundsException 索引越界异常
ArithmeticException:数学计算异常
NullPointerException:空指针异常
ArrayOutOfBoundsException:数组索引越界异常
ClassNotFoundException:类文件未找到异常
ClassCastException:造型异常(类型转换异常)
这些异常是不检查异常(Unchecked Exception),程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的。
非运行时异常:是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如:
IOException、文件读写异常
FileNotFoundException:文件未找到异常
EOFException:读写文件尾异常
MalformedURLException:URL格式错误异常
SocketException:Socket异常
SQLException:SQL数据库异常
session是存储在服务器端,cookie是存储在客户端的,所以安全来讲session的安全性要比cookie高,然后我们获取session里的信息是通过存放在会话cookie里的sessionid获取的。又由于session是存放在服务器的内存中,所以session里的东西不断增加会造成服务器的负担,所以会把很重要的信息存储在session中,而把一些次要东西存储在客户端的cookie里,然后cookie确切的说分为两大类分为会话cookie和持久化cookie,会话cookie确切的说是存放在客户端浏览器的内存中,所以说他的生命周期和浏览器是一致的,浏览器关了会话cookie也就消失了,然而持久化cookie是存放在客户端硬盘中,而持久化cookie的生命周期就是我们在设置cookie时候设置的那个保存时间,然后我们考虑一问题当浏览器关闭时session会不会丢失,从上面叙述分析session的信息是通过sessionid获取的,而sessionid是存放在会话cookie当中的,当浏览器关闭的时候会话cookie消失所以我们的sessionid也就消失了,但是session的信息还存在服务器端,这时我们只是查不到所谓的session但它并不是不存在。那么,session在什么情况下丢失,就是在服务器关闭的时候,或者是sessio过期,再或者调用了invalidate()的或者是我们想要session中的某一条数据消失调用session.removeAttribute()方法,然后session在什么时候被创建呢,确切的说是通过调用session.getsession来创建,这就是session与cookie的区别
Final是一个修饰符:
当final修饰一个变量的时候,变量变成一个常量,它不能被二次赋值
当final修饰的变量为静态变量(即由static修饰)时,必须在声明这个变 量的时候给它赋值
当final修饰方法时,该方法不能被重写
当final修饰类时,该类不能被继承
Final不能修饰抽象类,因为抽象类中会有需要子类实现的抽 象方法,(抽 象类中可以有抽象方法,也可以有普通方法,当一个抽象类中没有抽象方 法时,这个抽象类也就没有了它存在的必要)
Final不能修饰接口,因为接口中有需要其实现类来实现的方法
Finally:
Finally只能与try/catch语句结合使用,finally语句块中的语句一定会执行, 并且会在return,continue,break关键字之前执行
finalize:
Finalize是一个方法,属于java.lang.Object类,finalize()方法是GC (garbage collector垃圾回收)运行机制的一部分,finalize()方法是在 GC清理它所从 属的对象时被调用的
从流的方向
输入流 输出流
从流的类型上
字符流 字节流
inputstream和outputstream都是抽象类
它们下面的实现包括
FileInputStream,BufferedInputStream
FileOutputStream,BufferedOutputStream
reader 和 writer
FileReader,BufferedReader,StringReader
FileWriter,BufferedWriter,StringWriter,PrintWriter
数据库篇
1、加载JDBC驱动程序:
通过Class类的forName方法实现,并将驱动地址放进去
成功加载后,会将Driver类的实例注册到DriverManager类中。
2、提供JDBC连接的URL 、创建数据库的连接
•要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象,
该对象就代表一个数据库的连接。
•使用DriverManager的getConnectin()方法传入指定的欲连接的数据库的路径、数 据库的用户名和密码。
Connection con=DriverManager.getConnection(url , username , password);
&&&:"jdbc:mysql://localhost/test?user=root&password=123&useUnicode=true&characterEncoding=utf-8”;
3、创建一个Statement
•要执行SQL语句,必须获得java.sql.Statement实例
•执行静态SQL语句。通常通过Statement实例实现。
•执行动态SQL语句。通常通过PreparedStatement实例实现。
String sql = “”;
Statement st = con.createStatement() ;
PreparedStatement pst = con.prepareStatement(sql) ;
4、执行SQL语句
Statement接口提供了executeQuery、executeUpdate、execute三种方法
executeQuery:执行select语句,返回ResultSet结果集
ResultSet rst = pst.executeQuery();
• executeUpdate:执行insert、update、delete语句
pst.executeUpdate();
5、关闭JDBC对象
操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源。
数据库连接池简介:
数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
什么是数据库连接池:
Connection pooling,它是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。
数据库连接池的运行机制:
1.从连接池获取或创建可用的连接;
2.使用完毕之后,把连接返还给连接池;
3.在系统关闭前,断开所有连接并释放连接占用的系统资源;
4.还能够处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时、通讯问题),并能限制连接池中的连接总数不低于某个预定值和不超过某个预定值;
配置:
首先找到mysql的安装目录,进入bin目录下复制路径
将mysql的bin目录粘贴在计算机环境变量的path中
授权:
登录mysql
将某张表的某个权限赋给某个用户
grant [select,insert,update,delete,create,drop] on [databaseName].[tableName] to [userName]@[userIP] identified by [‘连接口令’]
grant select,insert,update,delete,create,drop on oa_ssh.user to root@[IP] identified by 'root';
将所有库的所有权限赋给某个用户
grant all privileges on *.* to [userName]@[userIp] identified by [‘连接口令’]
grant all privileges on *.* to root@[IP] identified by ‘root';
将所有库的所有权限赋给所有用户
grant all privileges on *.* to root@'%' identified by ‘root’;
导出本地数据库:
mysqldump -u 用户名 -p 数据库名 > 磁盘:导出的文件名(加后缀)
远程导出数据库:
mysqldump -h IP -u 用户名 -p 数据库名称 >导出的文件名(加后缀)
远程导出数据表:
mysqldump -u root -p -d --add-drop-table 数据库名称 > 导出文件
名(加后缀)
导入数据:
mysql -u root -p登录成功后 ==》 source 磁盘:导入的文件名(加后缀)
通过Map来解决性能问题。首先在分段批量提交的时候,我们不采用事务,这样就保证了合法的数据就自动提交,不合法的数据就自己自动进行回滚,为了避免不合法数据影响后续合法数据的提交,采用定义业务规则字典表,实现对数据的验证,将不合法的数据记录下来,供用户进行后续处理,而合法的数据就全部提交。
dbc批量处理数据是通过PreparedStatement对象的 addbatch(), executebatch() clearbatch()进行和数据库的交互。通常我们使用分段批量处理的方式 这样可以提高程序的性能 ,防止内存溢出。
1.每个sql语句都和数据库交互一次(非批量操作)
2.只和数据库交互一次(批量操作)(内存溢出)
当数据达到一定额度的时候就和数据库进行交互,分多次进行(分段批量操作)
(500或者1000)
pst.addBatch();
if (i > 0 && i%1000 == 0) {
pst.executeBatch();
pst.clearBatch();
}
Oracle的基本数据类型(常用):
1、字符型
Char 固定长度字符串 占2000个字节
Varchar2 可变长度字符串 占4000个字节
Nvarchar2 占2000个字符(最多能存2000个字母/中文)
2、大对象型(lob)
Blob :二进制数据 最大长度4G
Blob 用于存一些图片,视频,文件。
比如:当我们在进行文件上传时,我们一般把上传的文件存在硬盘上,可以不占用 数据库,下载时,如果项目迁移时,文件也要跟着迁移。因此我们可以把用blob把它存在数据库中。但这样也增加了数据库的负担。
Clob :字符数据 最大长度4G,可以存大字符串 varchar2和nvarchar2都具有一定的局限性,它们长度有限,但数据库中无论用varchar2或nvarchar2类型,还是用clob,在java端都使用String接收。
3、数值型
Integer 整数类型,小的整数。
Float 浮点数类型。
Real 实数类型。
Number(p,s)包含小数位的数值类型。P表示精度,s表示小数后的位数。
Eg: number(10,2) 表示小数点之前可有8位数字,小数点后有2位。
4、日期类型
Date 日期(日-月-年) DD-MM-YY(HH-MI-SS)
Timestamp 跟date比 它可以精确到微秒。精确范围0~9 默认为6.
第一范式:数据库表中的所有字段值都是不可分解的原子值。
第二范式:需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)
第三范式:需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关
视图可以视为“虚拟表”或“存储的查询”
创建视图所依据的表称为“基表”
视图的优点:
提供了另外一种级别的表安全性:隐藏了一些关键的字段
简化的用户的SQL命令
隔离基表结构的改变
存储过程(Stored Procedure)
可以包含逻辑判断的sql语句集合。
是经过预编译,存在于数据库中。
通过调用指定存储过程的名字(可有参,可无参)来执行。
优点:
简化了复杂的业务逻辑,根据需要可重复使用
屏蔽了底层细节,不暴露表信息即可完成操作
降低网络的通信量,多条语句可以封装成一个存储过程来执行
设置访问权限来提高安全性
提高执行效率,因为它是预编译以及存储在数据库中
缺点:
可移植性差,相同的存储过程并不能跨多个数据库进行操作
大量使用存储过程后,首先会使服务器压力增大,而且维护难度逐渐增加
存储过程的语法:
--下面是在oracle数据库下最基本的语法
--仅创建一个名为testProcedure 的无参的存储过程
--IS也可以是AS
--如果已经存在名为 testProcedure 的存储过程,下面的语法会出现 名称已被使用的错误
--解决办法:
--第一句可以写成 create or replace procedure testProcedure
--这样会替换原有的存储过程
--NULL表示任何可以正确执行的sql 语句,但至少一句
create procedure testProcedure
IS
BEGIN
NULL
END;
存储过程的参数的分类:
IN
OUT
INOUT
注意:
存储过程之间可相互调用
存储过程一般修改后,立即生效。
1、索引的概念
索引就是加快查询表中数据的方法。
数据库的索引类似于书籍的索引。
在书籍中,索引允许用户不必翻阅完整个书就能迅速地找到所需要的信息。
在数据库中,索引也允许数据库程序迅速地找到表中的数据,
而不必扫描整个数据库.
2、索引的特点
1.索引可以加快数据库的检索速度
2.索引降低了数据库插入、修改、删除等维护任务的速度
3.索引创建在表上,不能创建在视图上
3、索引的优点
1.创建唯一性索引,保证数据库表中每一行数据的唯一性
2.大大加快数据的检索速度,这也是创建索引的最主要的原因
3.减少磁盘IO(向字典一样可以直接定位)
4、索引的缺点
1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
2.索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定 的物理空间
3.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低 了数据的维护速度
5、索引的分类
1.普通索引和唯一性索引
普通索引:CREATE INDEX mycolumn_index ON mytable (myclumn)
唯一性索引:保证在索引列中的全部数据是唯一的
CREATE unique INDEX mycolumn_index ON mytable (myclumn)
2. 单个索引和复合索引
单个索引:即非复合索引
复合索引:又叫组合索引,在索引建立语句中同时包含多个字段名,
最多16个字段
CREATE INDEX name_index ON username(firstname,lastname)
顺序索引,散列索引,位图索引
一:oracle 分页
select * from (select t.*, rownum rn from (select * from menu order by id desc) t where rownum < 10) where rn >=5
二: mysql 分页
select * from music where id limit 5,5
三:oracle中如何快速将一张表的数据复制到另外一张表中(另外一张表不存在,另外一张 表存在,但数据为空)
create table 新表 as select * from 将要复制的表
insert into 新表名 select 字段 from 将要复制的表名
四:音乐专辑
查询出special
Select s.id , min(s.sname),count(m.mid) from special s inner
join ms m on s.id=m.id group by s.id
五:快速删除一张表(不可事物回滚,也就是没有日志记录)
TRUNCATE from 表名
六:inner join
select 查找信息 from 表名 1 inner join 表名2 on 表名1.列名 = 表名2.列名
七:left join
左外连接 select 查找信息 from 表名1 left join 表名2 on 表名1.列名 = 表名2.列名
八:right join
右外连接 select 查找信息 from 表名1 right join 表名2 on 表名1.列名 = 表名2.列名
九:oracle中查询遍历树形结构(start with)
select * from extmenu
start with pid=0
connect by prior id = pid
十:查询出来60-70,80-90,95-100学生的信息
select * from stu where chengji between 60 and 70 or between 80 and 90 or between 95 and 100
select * from stu where chengji > 60 and chengji < 70 or chengji > 80 and chengji < 90 or chengji > 95 and chengji < 100
十一:用exists替换in------进行联表查询
select * from dept where exists(select * from emp where emp.deptno=dept.deptno);
或
select * from dept d inner join emp e on d.deptno = e.deptno(只查询出两表共同拥有的字段数据)
十二:删除表中的重复数据:
delete from xin a where a.rowid != (
select max(b.rowid) from xin b
where a.name = b.name
);
在数据库中,所谓事务是指一组逻辑操作单元即一组sql语句。当这个单元中的一部分操作失败,整个事务回滚,只有全部正确才完成提交。
事务的ACID属性
1. 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,
要么都不发生。
2. 一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏)
3. 隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰.
4. 持久性(Durability)
持久性是指一个事务一旦被提交,
它对数据库中数据的改变就是永久性的.
在JDBC中,
事务默认是自动提交的,
每次执行一个 SQL 语句时,如果执行成功,
就会向数据库自动提交,而不能回滚
为了让多个 SQL 语句作为一个事务执行:
(1)执行语句前调用 Connection 对象的 setAutoCommit(false);
以取消自动提交事务
(2)在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
(3)在出现异常时,调用 rollback(); 方法回滚事务。
MySQL事务隔离级别
事务隔离级别 |
脏读 |
不可重复读 |
幻读 |
读未提交(read-uncommitted) |
是 |
是 |
是 |
不可重复读(read-committed) |
否 |
是 |
是 |
可重复读(repeatable-read) |
否 |
否 |
是 |
串行化(serializable) |
否 |
否 |
否 |
事务的并发问题
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
权限涉及到5张表:
用户表,角色表,权限表(菜单表),用户角色关联表,角色权限关联表
当用户登录时,根据用户名和密码到用户表验证信息是否合法,如果合法
则获取用户信息,之后根据用户id再到用户角色关联表中得到相关连的角色
id集合,之后根据角色id再到角色权限关联表中获取该角色所拥有的权限id集合,
然后再根据权限id集合到权限表(菜单表)中获取具体的菜单,展现给当前
登录用户,从而达到不同用用户看到不同的菜单权限。
我们通过ZTree来给角色赋权并且通过ZTree来展示菜单,以及通过ZTree来管 理菜单即增加和编辑菜单。
我们做的权限控制到url级别,为了防止用户不登录直接输入url访问的这个弊端,通过拦截器进行拦截验证。
我在做项目时有时会遇到session超时问题,如果session超时,平常请求没有什么问题,通过拦截器可以正确跳到登陆页面,可是你如果用ajax请求的话这就出现问题了,因为ajax是异步的,局部刷新,所以登陆界面不会再全页面中显示,他只会显示到页面的一部分当中。所以根据我这几年的经验找到了我认为比较好的一种方法。因为那我用的框架是和struts2集成的,所以就在拦截器中进行设置:
首先判断session是否为空就是判断session是否超时,如果超时就取出请求的head头信息request.getHeader("x-requested-with"),如果不为空就和XMLHttpRequest(Ajax标识)进行比较 (request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest"))) 如果相等说明此请求是ajax请求。
如果是ajax请求就可以用response.setHeader("键","值")来设置一个标识来告诉用户这是ajax请求并且session超时时发出的,这样我就可以在回调函数中取出自己设置的那个唯一标识:XMLHttpRequest.getResponseHeader("");如果取出的值是和自己在后台中设置的值一样的话,就证明session已经超时,这样就可以设置window.location.replace("登陆界面"),来跳转到登陆界面了。
这样做虽然解决了问题,但是,会在每个回调函数中写入那些代码,这样的话代码就会显得特别零散,所以就想能不能定义一个全局的设置所以就找到了jqery的ajaxSetUp方法,通过ajaxSetUp对jqery的ajax进行全局的判断(ajaxSetUp就相当于ajax的拦截器),通过设置ajaxSetUp里的complete,它就相当于回调函数,这样那就弥补了上一方法的不足。
我做项目时还用到$(document).ajaxStart(),这是ajax请求时的事件;$(document).ajaxSuccess(),这是AJAX请求成功后的事件。我一般用他们来显示遮罩层和隐藏遮罩层用的加遮罩层是为了不让用户重复提交,更提高了用户体验度,让用户知道已经提交了。
在我以前做某项目的过程中,其中我们在做产品列表的查询的时候为了提高用户的体验度,我们使用了autocomplete插件来代替select进行品牌的选择,才开始的时候每次都要根据用户输入的信息去查询数据库进行模糊匹配返回结果,后来我们考虑到系统的性能,因此我们采用了oscache缓存,才开始这个功能是交给我们项目组中的另外一个同事来做的,但是他做完后,我们在使用这个工具类的时候,发现有时缓存中明明已经有时我们需要的数据,但是从缓存里面取的时候,发现没有,之后项目经理让我去帮这个同事看看这个问题,我经过阅读他的代码发现,它里面在使用缓存的时候,针对于每次方法的调用都产生一个新的实例,结果导致了上面的问题,这个时候我想起了可以使用设计模式中的单例模式来解决这个问题,才开始我直接采用了普通的单列模式,但是后来在测试的过程中,发现当用户并发量大的时候还是会出现上面的问题,之后我再次考虑了代码,最后发现是因为没有给单列模式加锁的原因,从而导致了大用户并发的时候,线程安全的问题,之后我便在方法上加上了synchronized关键字,解决上述的问题,但是后来测试人员反馈,觉的这段的性能有问题,我考虑之后便采用在方法体内加锁并结合双重判定的方式解决了上面的问题。我们是将数据在tomcat启动的时候加载到缓存中,之后用户进行查询的时候直接从缓存中获取数据,根据前缀匹配进行查询,将结果返回给用户。这样在提高用户体验度的同时也提高性能。
servlet是单列的,对于所有请求都使用一个实例,所以如果有全局变量被多
线程使用的时候,就会出现线程安全问题。
解决这个问题有三种方案:
1.实现singleThreadModel接口,这样对于每次请求都会创建一个新的servlet实例,这样就会消耗服务端内存,降低性能,但是这个接口已经过时,不推荐使用。
2.可以通过加锁(synchroniezd关键字)来避免线程安全问题。这个时候虽然还是单列,但是对于多线程的访问,每次只能有一个请求进行方法体内执行,只有执行完毕后,其他线程才允许访问,降低吞吐量。
3.避免使用全局变量,使用局部变量可以避免线程安全问题,强烈推荐使用此方法来解决servlet线程安全的问题。
JPBM是JBOSS旗下的一个开源的基于hibernate的工作流引擎。工作流就是在日常生活中,我们一些常见的如请假流程、采购流程、入职流程,通俗的来讲就是一些在现实生活中的流程以信息化以程序的方式实现。
一个工作流首先需要进行流程定义,流程定义是由节点和跳转组成的,节点又可以称为环节、活动节点、活动环节,并且节点也可以分为两大类型:人工节点和自动节点,人工节点有start开始节点、end结束节点、task任务节点,自动节点有decision判断节点、fork分支节点、join聚合节点和state状态节点,并且一个流程有且只有一个开始节点,但可以有多个结束节点。
流程定义是静止的,它在运行状态时会转换成流程实例,一个流程定义可以对应多个流程实例。流程运行后,会产生两个文件,*.jdpl.xml文件和*.png图片文件,也会生成18张数据库表,常用且核心的表有JBPM4_LOB 存储表,主要存储xml文件和png图片、JBPM4_TASK 任务表、JBPM4_EXECUTION 流程实例表、JBPM4_VARIABLE变量表。
JBPM有五大核心类:
ProcessEngine:主要获取各种的Service
RepositoryService:主要发布流程定义
ExecutionService:主要操作流程实例
TaskService:主要操作人工服务
HistoryService:主要操作历史服务。
核心方法:
读取jbpm定义的文件生成zip包存到lob表中:createDeployment()
获取流程定义列表:createProcessDefinitionQuery
根据定义的key或id来启动流程实例:startProcessInstanceByKey(id)
获取待办任务列表:findPersonalTasks(userName)
完成指定任务列表:completeTask(*.getActivityId())
获取历史任务列表:createHistoryTaskQuery()
获取流程实例的ID:task.getExecutionId()
(了解的表)
JBPM4_HIST_ACTINST 流程活动(节点) 实例表
JBPM4_HIST_DETAIL 流程历史详细表
JBPM4_HIST_PROCINST 流程实例历史表
JBPM4_HIST_TASK 流程任务实例历史表
JBPM4_HIST_VAR 流程变量( 上下文) 历史表
存储过程就是封装一些sql的集合,也就是一条条的sql语句,过程的优点就是简化了sql命令加上它是预编译的,所以它的执行效率和性能较高,再者,如果不调用过程的话就要和数据库发生多次交互,调用过程只需传一个命令所有的那些执行逻辑都在数据库端执行,所以说它降低了网络的通信量,其次,存储过程大大提高了安全性,这就是优点
缺点呢,就是不同的数据库对过程支持的关键字支持的关键字都是不一样的,所以它的移植性是非常差的,再者,它的维护性难度也比较大,因为它没有专业的调试和维护工具,所以说它维护起来比较麻烦,这就是存储过程的基本概述
当我们tomcat访问量大,线程连接数不够时,我们考虑到了tomcat的负载均衡来分担过多的访问.性能方面负载均衡也能利用多台tomcat来增大内存量,
流程,准备工作apache,Jk_mod,tomcat,在apache的conf/httpd.conf文件中 使用include 标签引入我们自定义的一个mood_jl.conf,在modules中引入下载的k_mod-apache-X.X.XX.so文件,在其中引入我们的.so,及work.properties文件,及指定负载分配控制器controller,在work.properties文件中worker.list=controller,tomcat1,tomcat2指定service,worker.tomcat1.port Ajp端口号,type 是ajp,host为指定ip,lbfactor 指定分配权重值越大分担请求越多,worker.controller.type=lbworker.controller.balanced_workers=tomcat1,tomcat2 指定分担请求的tomcat Session的复制在tomcat中service.xml中Engine标签加入 jvmRoute 值为work,properties中指定的tomcat名称,然后打开
当我们tomcat访问量大,线程连接数不够时,我们考虑到了tomcat的负载均衡来分担过多的访问.性能方面负载均衡也能利用多台tomcat来增大内存量,
流程,准备工作apache,Jk_mod,tomcat,在apache的conf/httpd.conf文件中 使用include 标签引入我们自定义的一个mood_jl.conf,在modules中引入下载的k_mod-apache-X.X.XX.so文件,在其中引入我们的.so,及work.properties文件,及指定负载分配控制器controller,在work.properties文件中worker.list=controller,tomcat1,tomcat2指定service,worker.tomcat1.port Ajp端口号,type 是ajp,host为指定ip,lbfactor 指定分配权重值越大分担请求越多,worker.controller.type=lbworker.controller.balanced_workers=tomcat1,tomcat2 指定分担请求的tomcat Session的复制在tomcat中service.xml中Engine标签加入 jvmRoute 值为work,properties中指定的tomcat名称,然后打开
public class Sort {
public static void sort() {
Scanner input = new Scanner(System.in);
int sort[] = new int[10];
int temp;
System.out.println("请输入10个排序的数据:");
for (int i = 0; i < sort.length; i++) {
sort[i] = input.nextInt();
}
for (int i = 0; i < sort.length - 1; i++) {
for (int j = 0; j < sort.length - i - 1; j++) {
if (sort[j] < sort[j + 1]) {
temp = sort[j];
sort[j] = sort[j + 1];
sort[j + 1] = temp;
}
}
}
System.out.println("排列后的顺序为:");
for(int i=0;i System.out.print(sort[i]+" "); } } public static void main(String[] args) { sort(); } } 单例就是该类只能返回一个实例。 单例所具备的特点: 1.私有化的构造函数 2.私有的静态的全局变量 3.公有的静态的方法 单例分为懒汉式、饿汉式和双层锁式 饿汉式: public class Singleton1 { private Singleton1() {}; private static Singleton1 single = new Singleton1(); public static Singleton1 getInstance() { return single; } } 懒汉式: public class Singleton2 { private Singleton2() {} private static Singleton2 single=null; public tatic Singleton2 getInstance() { if (single == null) { single = new Singleton2(); } return single; } } 线程安全: public class Singleton3 { private Singleton3() {} private static Singleton3 single ; public static Singleton3 getInstance() { if(null == single){ synchronized(Singleton3.class){ if(null == single){ single = new Singleton3(); } } } return single; } }