java基础
第一招:java的四大特性:抽象,继承,封装,多态
抽象的概念:
这里我先补充一下对象的概念,在java中世界万物皆对象,对象就是客观存在的事物,比如一个人,一支笔。而抽象就是将对象的某些细节和特征抽取出来,用程序代码表示,抽取出来的东西一般我们称之为类或者接口,因此抽象分为两个方面,数据抽象和过程抽象。
数据抽象:就是将事物的共同的特征用程序代码表示,通过抽象成为对象的属性,比如一个人有年龄,性别,身高,这些代表人的特征通过数据抽象成人这个对象的属性
过程抽象:就是将事物的行为用程序代码表示,通过抽象成为对象的方法,比如一个人,他要吃饭,他要跑步,这类的行为通过过程抽象成为人这个对象的方法。
继承的概念:
继承的单词是extends,但我个人更趋向理解为扩展,所以我认为继承就是从已有的类派生出新的类,新的类吸收已有的类的属性和方法,并且能够扩展的新的能力(新的方法)
比如车这个类,有车轮,车灯这些属性,但是车又可以派生出小轿车和大卡车两个类,这两个类都有车轮,车灯这些属性,并且为小轿车添上一个后备箱,为大卡车添上一个大货箱,
这添加出来的就是扩展后的功能。
继承的意义就是提高代码的复用性,如果两个类存在is-a的关系(比如绵羊属于羊这一类)子类继承父类的方法和属性,并且可以扩展自己的方法,如果需要实现父类中的同名方法必须进行重写。但是继承缺点很明显,第一点它打破了封装的概念,父类向子类暴露了实现细节。并且父类改变了,子类也要进行相应的改变,耦合度太高。所以大多情况下都会选择使用接口。
多态的概念:
在说多态之前,我要说下接口。在Java中接口是一个全部由抽象方法组成的集合,接口需要用interface定义,里面只能有抽象的方法和常量。接口就是体现事物扩展的不同功能,接口的不同实现方式就是多态,打个比方,有一个插座接口,声明了充电这个方法,插座可以用来插充电宝,插手机,插电风扇进行充电,至于怎么充,就是充电宝手机电风扇内部具体的实现。这种不同的实现方式就是接口多态的体现。一个类可以实现多个接口,实现类实现接口就必须重写这个接口里所有的方法,接口只做方法的声明,具体的实现由实现类去做。
接口对比继承就是降低耦合性,就那刚才那个插座接口举例,及时你电风扇内部充电功能改变了,都不会影响到插座充电的功能。
第二招:String类和StringBuffer类
String类为final类型的,不可继承,存储的是字符串常量,是不可改变的。
(每次赋值都是重新创建一个对象)
而StringBuffer类存储的是字符串变量,可以对字符串进行一系列的操作。
比如String str = “abc”,str = str + “de” ,输出的虽然是abcde,但是实际情况是,我们先创建一个String对象str,并把“abc”赋值给str,然后str = str+”de”执行的是,JVM创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了。
StringBuffer类是线程安全的,适合多线程在字符缓冲区进行操作的情况。
第三招:异常
我们知道,在java中,所有异常对象都是throwable类的一个实例,我们不仅可以使用java内置的异常类,还可以自定义自己的异常类。
在异常中分为两种,一种是error,另一种是Exception。
Error:描述了java运行时系统的内部错误和资源耗尽错误。比如我们熟知的stackoverflowError栈溢出,其实就是错误,也不需要捕获。
Exception又可以分为runtimeException 和其他异常
runtimeException指的是在java虚拟机运行正常的情况下,由于程序部分代码错误所产生的异常,而程序本身没有问题,比如我们熟知的数组下标越界异常indexofboundException和空指针nullpointException异常
其他异常就是因I/O错误导致的异常:(也称编译时异常,就是我们写代码时必须要抛出的异常,比如SQLException,IOException,ClassNotFoundException ,FileNotFoundException文件未找到异常。
对于运行时异常,java编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。
非运行时异常(检查异常,编译异常,必须要处理的异常)
java编译器强制程序员必须进行捕获处理,比如常见的IOExeption和SQLException。对于非运行时异常如果不进行捕获或者抛出声明处理,编译都不会通过。
第四招:进程和线程
关于进程和线程的概念,不同角度有不同的方法,我目前认为,进程就是程序在计算机上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位,说起这个资源分配和调度,原本都是由进程完成的,每个进程所能访问的内存都是圈好的,一人一份,互不影响,由于cpu越来越牛逼,因此在进程的基础上,再次细分,线程就是进程的一个实体,就是cpu调度和分配的基本单位,它本身基本上不拥有资源,只拥有一小部分必不可少的资源(如程序计数器),因此一个进程拥有多个线程,同一个进程中的多个线程之间可以并发执行。
就像火车和车厢,进程就是火车,车厢就是线程。
比如火车拥有多个车厢(一个进程拥有多个线程)
不同进程之间的数据很难共享,但是不同线程之间的数据很易共享(比如火车换乘很麻烦,但是从一个车厢到另一个车厢很简单)
进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
第五招:java多线程
Java的线程有五种状态
新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。值得一提的是,就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期
https://img-blog.csdnimg.cn/20181217103521533.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JpenRhbA==,size_16,color_FFFFFF,t_70
线程的创建和启动有两种方式
一种是继承Thread类,一种是实现runable接口,但是在java1.5以后提出了一个叫callable接口,他的不同之处在于有返回值和可以抛出异常,便于我们处理异常信息。
什么是线程安全?Vector是一个线程安全类吗?
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。
如何停止一个线程?
目前来说并没有提供相应的api来停止线程,而是当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程
第六招:Servlet的生命周期
Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
第七招:JDBC
jdbc的基本步骤
(1) 加载JDBC驱动
(2) 建立并获取数据库连接
(3) 创建 JDBC Statements 对象(或者preStatement)
(4) 设置SQL语句的传入参数
(5) 执行SQL语句并获得查询结果
(6) 对查询结果进行转换处理并将处理结果返回
(7) 释放相关资源(关闭Connection,关闭Statement,关闭ResultSet)
这是最基本的jdbc的流程,我们可以对其进行优化,
1) 使用数据库连接池对连接进行管理
(2) SQL语句统一存放到配置文件
(3) SQL语句变量和传入参数的映射以及动态SQL
(4) 动态SQL语句的处理
(5) 对数据库操作结果的映射和结果缓存
(6) SQL语句的重复
第八招:Spring框架
第一式:什么是Spring?
Spring是一个开源框架,是为了解决企业应用开发的复杂性而创建的,并且使用基本的javaBean来完成以前的只有EJB才能完成的事情(EJB是一个重量级的框架,有三种企业级的javabean,分别为Session Bean,Entity Bean,MessageDriven Bean),并且可以替代EJB完成更多的企业应用功能。然而Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心思想是IOC和AOP。
第二式:Spring的好处
1)Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
2)AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
3)声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
4)方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
5)方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
6)降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
第三式:Spring的IOC
Spring的IOC,即控制反转,是一种设计思想。
我们知道,在采用传统的JAVA面向对象思想设计软件系统时,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。
这样就造成了彼此之间互相依赖,导致耦合度过高的问题。而IOC的设计思想是,创建一个“第三方”或者“大管家”来管理这些对象,由一个专门的容器负责来创建这些对象,举个栗子,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。但是引入了IOC容器,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。如图
https://img-blog.csdnimg.cn/20181217103521321.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JpenRhbA,size_16,color_FFFFFF,t_70
https://img-blog.csdnimg.cn/2018121710352116.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JpenRhbA,size_16,color_FFFFFF,t_70
https://img-blog.csdnimg.cn/20181217103519848.png
https://img-blog.csdnimg.cn/20181217103519840.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JpenRhbA,size_16,color_FFFFFF,t_70
https://img-blog.csdnimg.cn/20181217103519850.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JpenRhbA,size_16,color_FFFFFF,t_70
此IOC另一个方面的说法叫做依赖注入,所谓依赖注入,就是IOC容器在运行期间,动态地将某种依赖关系注入到对象之中,对象A依赖于对象B,当对象 A需要用到对象B的时候,IOC容器就会立即创建一个对象B送给对象A。IOC容器就是一个对象制造工厂,你需要什么,它会给你送去,你直接使用就行了,而再也不用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切全部由IOC容器包办。说的简单点就是配置,目前我一开始用过比较多的方式是setter方法注入和构造器注入,比如注入一个Car类,在配置文件Application.xml里添加bean节点,取一个ID为Car,Class为具体的实现类,注入属性,比如价格,名字。另外一个就是构造器注入,使用constructor-arg节点,type表示注入的属性类型,ref表示依赖对象。不过我用的最多的就是自动装配了,使用@autowired和@Resource
通过context-component-scan自动扫描包,用@repository,@Service,@Resource进行注解。
补充:
IOC容器的技术剖析
IOC中最基本的技术就是“反射(Reflection)”编程,有时候也被翻译成“映射”。有关反射的概念和用法,大家应该都很清楚,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象。这种编程方式可以让对象在生成时才决定到底是哪一种对象。反射的应用是很广泛的,很多的成熟的框架,比如象Java中的Hibernate、Spring框架。
我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。
第四式:Spring的AOP
AOP的意思是面向切面编程,就是将某些系统性的代码如权限管理,日志记录等动态地切入到类的指定方法,指定位置上去的编程思想。比如我们做存钱,取钱,转账都要有个验证功能,三个业务都要写一个验证,这显然是十分麻烦的,并且验证的代码和业务逻辑代码写在一起可能造成混淆,不便于以后的维护。使用AOP技术就可以将这个验证的功能独立地提取出来,独立实现,然后通过切面切入到指定的位置。
Spring的AOP实现方式有两种,第一种是使用 aop:config 标签在xml中进行配置,第二种是使用注解以及@Aspect风格的配置。
我用的是第二种,首先在配置文件中用<context:component-scan base-package="net.aazj.aop" />扫描切面,切面就是我们写好的比如权限管理的代码的类,用@Aspect进行注解,然后用@pointcut注解定义一个切点(符合切点表达式的连接点),也就是我们切入的位置,还有通知,就是我们要做的操作,通常使用环绕通知。环绕通知能够全面控制连接点,甚至可以控制是否执行连接点,环绕通知要返回方法的执行结果,所以要执行johnpoint.proceed()方法。
//scope :方法作用域,如public,private,protect
//returnt-type:方法返回值类型
//fully-qualified-class-name:方法所在类的完全限定名称
//parameters 方法参数
execution(
现在基本上都是结合@AspectJ注解进行开发
第五式Spring事务管理
事务:事务是逻辑上的一组操作,要么都执行,要么都不执行.
事务的特性:原子性,一次性,隔离性,持久性
原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要不完全不起作用。
一致性:执行事务前后,数据保持一致
隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
持久性:一个事务被提交之后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
最重要的三个api:TransactionDefinition事务定义信息PlatformTransactionManager事务管理器
TransactionStatus事务运行状态
事务管理的概念:
所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作
Spring并不直接管理事务而是提供了多种事务管理器,通过PlatformTransactionManager接口,Spring为各个平台比如JDBC,Hibernate等提供对应的事务管理器,但是具体的实现就是各个平台的事了,比如在使用mybatis或者JDBC时就是使用DataSourceTransactionManager这个类
如何定义一个事务呢?
TransactionDefinition事务定义信息。
事务管理接口PlatformTransactionManager通过getTransaction()方法来得到一个事务,参数类型就是TransactionDefinition类,定义了事务的一些基本属性。
事务属性包含五个方面:隔离级别,传播行为,回滚规则,是否只读,事务超时。
最常用的方法
getPropagationBehavior()返回事务传播行为
getIsolationLevel()返回事务隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
getName()返回事务名字
getTimeout()返回事务必须在多少秒内完成
isReadOnly()返回是否优化为只读事务
事务隔离级别
事务隔离级别(定义了一个事务可能受其他并发事务影响的程度)
并发事务带来的问题
脏读:当一个事务正在访问数据并且对数据进行修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据,因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据就是脏数据。
丢失修改:指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据,第二个事务中也修改了这个数据,这样第一个事务内的修改结果就被丢失,因此成为丢失修改。
不可重复读:指一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据,那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不一样。
幻读:就是一个事务读取了几行数据,接着另一个并发事务插入了一些数据,然后查询时发现了一些原来没有的多出来的数据,就好像发生了幻觉一样,所以成为幻读。
幻读和不可重复读的区别在于,前者重点在于新增和删除,后者的重点在于修改。
隔离级别五种级别
TransactionDefinition定义了五个表示隔离级别的常量,Isolation_default,
Isolation_read_uncommitted,读取尚未提交的数据变更
Isolation_read_committed允许读取并发事务已经提交的数据
Isolation_repeated_read,对同一字段的多次读取结果是一致的
Isolation_serializable最高隔离级别,所有事务依次执行。
事务传播行为
事务传播行为(为了解决业务层方法之间互相调用的事务问题)
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播
七种传播行为(主要背前两个)
最常见的是Propagation_required如果没有当前事务,就创建一个,如果已经存在一个事务中,就加入到这个事务中
Propagation_supports支持当前事务,如果当前没有事务,就以非事务方式执行
Propagation_mandatory使用当前事务,如果没有,抛出异常。
Propagation_requires_new新建事务,如果当前存在事务,把当前事务挂起。
Propagation_not_supported以非事务的方式执行操作,如果当前存在事务,就把当前事务挂起。
Propagation_never以非事务方式执行,如果当然存在事务,则抛出异常
Propagation_nested如果当前存在事务,则在嵌套事务内执行,如果没有,则执行Propagation_required类似的操作
编程式事务和声明式事务
编程式事务和声明式事务
前者已经没人用了,但是了解一下
编程式事务
第一步:配置事务管理器
JDBC和mybatis的是DataSourceTransactionManager类
第二步:配置管理器模板
第三步:对象及属性注入
https://img-blog.csdnimg.cn/20181217103520677.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JpenRhbA,size_16,color_FFFFFF,t_70
https://img-blog.csdnimg.cn/20181217103520282.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JpenRhbA,size_16,color_FFFFFF,t_70
声明式事务(重点)
基于AspectJ的声明式事务管理
第一步:配置事务管理器
第二步:配置事务增强
使用tx:advice标签进行配置,所谓事务增强我觉得就是更细致地锁定事务处理的位置,即进入目标方法之前开启事务,退出目标方法之后提交或者回滚事务。第四步:注入对象
https://img-blog.csdnimg.cn/2018121710352089.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JpenRhbA==,size_16,color_FFFFFF,t_70
基于注解的方式
第一步配置事务管理器
第二步:开启事务注解
tx:annotation-driven transaction-manager="dataSourceTransactionManager" /
第三步在所在类上添加注解
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false, timeout = -1)
第四步:注入对象及其属性
第九招JVM基本原理
JVM是java虚拟机的简称,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机实现的,正是因为有JVM,使得java程序能够在各个平台运行,所以有了这么一个口号,“一次编译,到处运行”。
它的执行原理是java程序经过一次编译之后,将java代码编译为字节码也就是class文件,然后在不同的操作系统上依靠不同的java虚拟机进行解释,最后再转换为不同平台的机器码,最终得到执行
JVM的内存空间
JVM内存空间包含:方法区、java堆、java栈、本地方法栈。
方法区是各个线程共享的区域,存放类信息、常量、静态变量。
java堆也是线程共享的区域,我们的类的实例就放在这个区域,可以想象你的一个系统会产生很多实例,因此java堆的空间也是最大的。如果java堆空间不足了,程序会抛出OutOfMemoryError异常。
java栈是每个线程私有的区域,它的生命周期与线程相同,一个线程对应一个java栈,每执行一个方法就会往栈中压入一个元素,这个元素叫“栈帧”,而栈帧中包括了方法中的局部变量、用于存放中间状态值的操作栈,这里面有很多细节,我们以后再讲。如果java栈空间不足了,程序会抛出StackOverflowError异常,想一想什么情况下会容易产生这个错误,对,递归,递归如果深度很深,就会执行大量的方法,方法越多java栈的占用空间越大。还有一种是OutOfMemoryError,如果栈内存支持扩展,但是内存空间不够了,就报这个异常。
本地方法栈角色和java栈类似,只不过它是用来表示执行本地方法的,本地方法栈存放的方法调用本地方法接口,最终调用本地方法库,实现与操作系统、硬件交互的目的。
PC寄存器,说到这里我们的类已经加载了,实例对象、方法、静态变量都去了自己改去的地方,那么问题来了,程序该怎么执行,哪个方法先执行,哪个方法后执行,这些指令执行的顺序就是PC寄存器在管,它的作用就是控制程序指令的执行顺序。
执行引擎当然就是根据PC寄存器调配的指令顺序,依次执行程序指令。
第十招:原生ajax的使用步骤
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数,动态的传递参数starName到服务端
ajax.open('get','getStar.php?starName='+name);
//步骤三:发送请求
ajax.send();//
步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState4 &&ajax.status200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText);//输入相应的内容
}
404:找不到资源文件
400:请求的语法可能有错,导致服务器无法识别
500:服务器内部错误,直接崩了,无法完成请求
第十一招:SpringMVC
什么是Spring MVC ?简单介绍下你对springMVC的理解?
Spring MVC是一个基于MVC架构的用来简化web应用程序开发的应用开发框架,它是Spring的一个模块,无需中间整合层来整合 ,它和Struts2一样都属于表现层的框架。在web模型中,MVC是一种很流行的框架,通过把Model,View,Controller分离,把较为复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
SpringMVC的运行原理
用户发送请求到前端控制器DispatcherServlet
DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获得Handle
处理器映射器通过url找到对应的处理器,生成处理器对象以及处理器拦截器(如果有则生成)一起返回给DispatcherServlet
DispatcherServlet通过HandlerAdapter处理器适配器调用处理器,并且执行它返回ModelAndView
DispatcherServlet将返回的modelAndView交给ViewResolver视图解析器进行解析返回具体的View
DispatcherServlet对View进行渲染视图,最后响应用户。
springMVC和struts2的区别有哪些?
(1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。
(2)springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
(3)Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。
SpringMVC实现拦截器的两种方式
一种是实现HandlerInterceptor接口
另一种是继承HandlerInterceptorAdapter类
再在配置文件中用mvc:interceptor节点进行配置
第十二招数据库
第一式:存储过程
SQL语句需要先编译然后执行,而存储过程是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用它。
为什么需要存储过程:
有人说,不需要把复杂过程封装成MySQL存储过程,用程序(C++/JAVA)也能实现复杂逻辑。如果用程序调用API执行,其实效率相对较慢,原因在于你的应用程序要通过引擎把MySQL语句交付
给MySQL引擎来执行,那就不如直接让MySQL负责它最精通最能够完成的工作,所以可以在开发中可以将某些常用的操作封装成存储过程。
第二式:索引
什么是索引:
索引就是一种的数据结构,存储表中特定列的值并对值进行排序,所以是在表的列上面创建的。索引就好比一本书的目录,它会让你更快的找到内容。
索引的优点是:
1)通过创建唯一性索引,可以保证数据库中每一行数据的唯一性。
2)加快数据的检索速度(这是最主要的原因)
可以加速表和表之间的连接,尤其是实现数据库的参照完整性
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
索引的缺点是:
随着数据越来越多,维护起来越麻烦
创建索引需要占用大量的物理空间
所以,一般来说,在经常搜索的列中或者作为主键的列或者经常用到where子句的列