校招java面试题1

1:linux线程和进程的区别

    进程是资源分配的最小单位,线程是CPU调度的最小单位

     进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集。从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。

         线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程由几个线程组成(拥有很多相对独立的执行流的用户程序共享应用程序的大部分数据结构),线程与同属一个进程的其他的线程共享进程所拥有的全部资源。

         进程是资源分配的最小单位,线程是CPU调度的最小单位

         使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。

         使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方

3:TCP和UDP的区别?TCP协议的三次握手 ?tcp的三次握手就是一个建立连接的过程

位码即tcp标志位,有6种标示:SYN(synchronous建立联机)、 ACK(acknowledgement 确认) 、PSH(push传送) FIN(finish结束)、 RST(reset重置) 、 URG(urgent紧急) 、Sequence number(顺序号码)、 Acknowledge number(确认号码)

第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;

第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包

第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

完成三次握手,主机A与主机B开始传送数据

1) 基于连接与无连接;
2) 对系统资源的要求(TCP较多,UDP少);
3) UDP程序结构较简单;
4) 流模式与数据报模式 ;
5) TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

说明情况下使用TCP和UDP呢?

在注重速度的时候使用UDP---》如:视频聊天时,语音聊天
在注重准确性的时候使用TCP---》如:下载文件时

12:ARP(地址解析协议),请用简单语言说明其的工作原理(ip-mac的解析,dns--域名-ip的解析)

         1. 首先,每台主机都会在自己的ARP缓冲区 (ARP Cache)中建立一个 ARP列表,以表示IP地址和MAC地址的对应关系。

2. 当源主机需要将一个数据包要发送到目的主机时,会首先检查自己 ARP列表中是否存在该 IP地址对应的MAC地址,
       如果有﹐就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。

  3. 网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个 ARP响应数据包,告诉对方自己是它需要查找的MAC地址;

  4. 源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。

14:HTTP协议的使用过程

(1)     请求:客户端向服务器索要数据

http协议规定:一个完整的http请求包含'请求行','请求头','请求体'三个部分;

请求行:包含了请求方法,请求资源路径,http协议版本. "GET /resources/images/ HTTP/1.1"

  请求头:包含了对客户端的环境描述,客户端请求的主机地址等信息.

  Accept: text/html ( 客户端所能接收的数据类型 )

  Accept-Language: zh-cn ( 客户端的语言环境 )

  Accept-Encoding: gzip( 客户端支持的数据压缩格式 )

  Host: m.baidu.com( 客户端想访问的服务器主机地址 )

User-Agent: Mozilla/5.0(Macintosh;Intel Mac OS X10.10 rv:37.0) Gecko/20100101Firefox/37.0( 客户端的类型,客户端的软件环境 )

       请求体:客户端发给服务器的具体数据,比如文件/图片等.

(2) 响应:服务器返回客户端想要的数据

http协议规定:一个完整的http响应包含'状态行','响应头','实体内容'三个部分;
状态行:包含了http协议版本,状态吗,状态英文名称."HTTP/1.1 200 OK"
响应头:包含了对服务器的描述,对返回数据的描述.
Content-Encoding: gzip(服务器支持的数据压缩格式) Content-Length: 1528(返回数据的长度)
Content-Type:application/xhtml+xml;charset=utf-8(返回数据的类型)
Date: Mon,15Jun201509:06:46GMT(响应的时间) Server: apache (服务器类型)
实体内容:服务器返回给客户端的具体数据(图片/html/文件...).

15:SQL注入

         SQL Injection:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

如何防止SQL Injection:

1.永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。

2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。

3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。

4.不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。

5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装,把异常信息存放在独立的表中。

22:HashMap底层数据结构和原理

         底层数据结构:

校招java面试题1_第1张图片

         HashMap实际上是一个“链表的数组”的数据结构,每个元素存放链表头结点的数组,即数组和链表的结合体。

       当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上

         从HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。

         总结:HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

15-  HashMap(线程不安全)与HashTable(线程安全)的区别

(1)两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全
Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,我们平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,类似的其它Collections.synchronizedXX方法也是类似原理)

(2) HashMap和Hashtable的底层实现都是数组+链表结构实现

(3) HashMap可以使用null作为key,而Hashtable则不允许null作为key
虽说HashMap支持null值作为key,不过建议还是尽量避免这样使用,因为一旦不小心使用了,若因此引发一些问题,排查起来很是费事
    HashMap以null作为key时,总是存储在table数组的第一个节点上

    (4) HashMap是对Map接口的实现,HashTable实现了Map接口和Dictionary抽象类

22: String、StringBuffer(线程安全)、StringBuilder(线程不安全)区别

         StringBuffer、StringBuilder和String一样,也用来代表字符串。String类是不可变类,任何对String的改变都 会引发新的String对象的生成;StringBuffer则是可变类,任何对它所指代的字符串的改变都不会产生新的对象。既然可变和不可变都有了,为何还有一个StringBuilder呢?相信初期的你,在进行append时,一般都会选择StringBuffer吧!

先说一下集合的故事,HashTable是线程安全的,很多方法都是synchronized方法,而HashMap不是线程安全的,但其在单线程程序中的性能比HashTable要高。StringBuffer和StringBuilder类的区别也是如此,他们的原理和操作基本相同,区别在于StringBuffer支持并发操作,线性安全的,适合多线程中使用。StringBuilder不支持并发操作,线性不安全的,不适合多线程中使用。新引入的StringBuilder类不是线程安全的,但其在单线程中的性能比StringBuffer高。

23:java中的四种引用类型

⑷         强引用(StrongReference)、⑵软引用(SoftReference)、⑶弱引用(WeakReference)、

⑷虚引用(PhantomReference)

 

24:java的基础类型和字节

         java四类八种基本数据类型

第一类:整型 byte short int long 
第二类:浮点型 float double

第三类:逻辑型 boolean(它只有两个值可取true false)

第四类:字符型 char

 

引用数据类型:是数据的引用在栈中,但是他的对象在堆中。在栈中可以直接分配内存的数据是基本数据类型。 
  字节:
    boolean 布尔型              1/8 
    byte 字节类型                1
    char 字符型                  2  一个字符能存储一个中文汉字,采用unicode编码
    short 短整型                 2
    int 整数类型                 4
    float 浮点类型(单精度)     4
    long 长整形                  8
    double 双精度类型(双精度)  8

25:调用start()方法和run()的区别

  区别:调用start方法实现多线程,而调用run方法没有实现多线程

Start:

   用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到spu时间片,就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。

Run:

  run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。

27:http中,get  post的区别

         Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。URL全称是资源描述符,我们可以这样认为:一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查,改,增,删4个操作。到这里,大家应该有个大概的了解了,GET一般用于获取/查询资源信息,而POST一般用于更新资源信息

         1.根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的。

     2.根据HTTP规范,POST表示可能修改变服务器上的资源的请求

很多人却没有按照HTTP规范去做,导致这个问题的原因有很多,比如说:

1.很多人贪方便,更新资源时用了GET,因为用POST必须要到FORM(表单),这样会麻烦一点。

  2.对资源的增,删,改,查操作,其实都可以通过GET/POST完成,不需要用到PUT和DELETE。

  3.另外一个是,早期的Web MVC框架设计者们并没有有意识地将URL当作抽象的资源来看待和设计,所以导致一个比较严重的问题是传统的Web MVC框架基本上都只支持GET和POST两种HTTP方法,而不支持PUT和DELETE方法

   

表面现象上面看看GET和POST的区别:

         1.GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。

  POST把提交的数据则放置在是HTTP包的包体中。

2."GET方式提交的数据最多只能是1024字节,理论上POST没有限制,可传较大量的数据

实际解释:

(1).首先是"GET方式提交的数据最多只能是1024字节",因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了。而实际上,URL不存在参数上限的问题,HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。

  注意这是限制是整个URL长度,而不仅仅是你的参数值数据长度。

(2).理论上讲,POST是没有大小限制的,HTTP协议规范也没有进行大小限制,说“POST数据量存在80K/100K的大小限制”是不准确的,POST数据是没有限制的,起限制作用的是服务器的处理程序的处理能力。

 

里外一种答案方式:

GET方法:

使用GET方法时,查询字符串(键值对)被附加在URL地址后面一起发送到服务器:

/test/demo_form.jsp?name1=value1&name2=value2

特点:      

GET请求能够被缓存

GET请求会保存在浏览器的浏览记录中

以GET请求的URL能够保存为浏览器书签

GET请求有长度限制

GET请求主要用以获取数据

POST方法:

使用POST方法时,查询字符串在POST信息中单独存在,和HTTP请求一起发送到服务器:

POST /test/demo_form.jsp HTTP/1.1

Host: w3schools.com

name1=value1&name2=value2    

特点:

POST请求不能被缓存下来

POST请求不会保存在浏览器浏览记录中

以POST请求的URL无法保存为浏览器书签

POST请求没有长度限制

28:访问一个网站的过程

         首先是查找浏览器缓存,浏览器会保存一段时间你之前访问过的一些网址的DNS信息,不同浏览器保存的时常不等。如果没有找到对应的记录,这个时候浏览器会尝试调用系统缓存来继续查找这个网址的对应DNS信息。如果还是没找到对应的IP,那么接着会发送一个请求到路由器上,然后路由器在自己的路由器缓存上查找记录,路由器一般也存有DNS信息。如果还是没有,这个请求就会被发送到ISP((注:Internet Service Provider,互联网服务提供商) ,ISP也会有相应的ISP DNS服务器,如果还是没有的话, 你的ISP的DNS服务器会将请求发向根域名服务器进行搜索。根域名服务器就是面向全球的顶级DNS服务器,共有13台逻辑上的服务器,从A到M命名,真正的实体服务器则有几百台,分布于全球各大洲。所以这些服务器有真正完整的DNS数据库。如果到了这里还是找不到域名的对应信息,那只能说明一个问题:这个域名本来就不存在,它没有在网上正式注册过。

         这也就是为什么打开一个新页面会有点慢,因为本地没什么缓存,要这样递归地查询下去。

多说一句,例如"mp3.baidu.com",域名先是解析出这是个.com的域名,然后跑到管理.com域名的服务器上进行进一步查询,然后是.baidu,最后是mp3,

所以域名结构为:三级域名.二级域名.一级域名。

浏览器终于得到了IP以后,浏览器接着给这个IP的服务器发送了一个http请求,方式为get

         这个get请求包含了主机(host)、用户代理(User-Agent),用户代理就是自己的浏览器,它是你的"代理人",Connection(连接属性)中的keep-alive表示浏览器告诉对方服务器在传输完现在请求的内容后不要断开连接,不断开的话下次继续连接速度就很快了。其他的顾名思义就行了。还有一个重点是Cookies,Cookies保存了用户的登陆信息,在每次向服务器发送请求的时候会重复发送给服务器, 服务器收到浏览器的请求以后(其实是WEB服务器接收到了这个请求,WEB服务器有iis、apache等),它会解析这个请求(读请求头),然后生成一个响应头和具体响应内容。接着服务器会传回来一个响应头和一个响应,响应头告诉了浏览器一些必要的信息,例如重要的Status Code,2开头如200表示一切正常,3开头表示重定向,4开头,如404,呵呵。响应就是具体的页面编码,就是那个......,浏览器先读了关于这个响应的说明书(响应头),然后开始解析这个响应并在页面上显示出来。

简化过后就是下面这个过程:

1.DNS域名解析:浏览器缓存、系统缓存、路由器、ISPDNS服务器、根域名服务器。把域名转化成IP地址。

2.IP地址对应的服务器建立TCP连接,经历三次握手:SYNACKSYNACK

3.getpost方式发送HTTP请求,get方式发送主机,用户代理,connection属性,cookie

4.获得服务器的响应,显示页面

 

30: Cookie和Session的区别

         Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器

         Session机制采用的是一种在服务器端保持状态的解决方案,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的。而session提供了方便管理全局变量的方式 。session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分是哪个用户session变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用cookie时,这个值也可能设置为由get来返回给服务器。

         1 .存取方式的不同

         Cookie中只能保管ASCII字符串,假如需求存取Unicode字符或者二进制数据,需求先进行编码。Cookie中也不能直接存取Java对象。

         Session中能够存取任何类型的数据,包括而不限于String、Integer、List、Map等。Session中也能够直接保管Java Bean乃至任何Java类,对象等,运用起来十分便当。能够把Session看做是一个Java容器类。

         2 .隐私策略的不同

         Cookie存储在客户端阅读器中,对客户端是可见的,客户端的一些程序可能会窥探、复制以至修正Cookie中的内容。而Session存储在服务器上,对客户端是透明的,不存在敏感信息泄露的风险。

         3.服务器压力的不同

         Session是保管在服务器端的,每个用户都会产生一个Session。假如并发访问的用户十分多,会产生十分多的Session,耗费大量的内存。因而像Google、Baidu、Sina这样并发访问量极高的网站,是不太可能运用Session来追踪客户会话的。

而Cookie保管在客户端,不占用服务器资源。假如并发阅读的用户十分多,Cookie是很好的选择。关于Google、Baidu、Sina来说,Cookie或许是唯一的选择

32:数据库连接池

  常用的几种连接池:DBCP、c3p0、proxool

  原理:数据库连接池实际上就是在程序加载时就按照设置的数量先和数据库建立一定量的连接,当需要数据库连接时就直接从最开始建立的连接中取得所需要的连接就行。当不需要时,只需要将连接还给连接池;当建立的连接被取用完后,并且还存在后续的请求,也就是说现在的连接数量已经超过了系统设置的最大连接数。那么,后面的请求只有等待!

34:设计模式

总体来说设计模式分为三大类:

创建型模式  共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式  共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式  共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

单例模式:始终是一个对象实例.它对外不提供构造函数,因此我们不能够同时产生多个对象.        

单例模式有以下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

  1. //懒汉式单例类.在第一次调用的时候实例化自己   
  2. public class Singleton {  
  3.     private Singleton() {}  
  4.     private static Singleton single=null;  
  5.     //静态工厂方法   
  6.     public static Singleton getInstance() {  
  7.          if (single == null) {    
  8.              single = new Singleton();  
  9.          }    
  10. 10.         return single;  
  11. 11.     }  

12. }  

以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,可以在getInstance()上加同步

  1. public static synchronized Singleton getInstance() {  
  2.          if (single == null) {    
  3.              single = new Singleton();  
  4.          }    
  5.         return single;  
  6. }  

饿汉式单例模式

  1. //饿汉式单例类.在类初始化时,已经自行实例化   
  2. public class Singleton1 {  
  3.     private Singleton1() {}  
  4.     private static final Singleton1 single = new Singleton1();  
  5.     //静态工厂方法   
  6.     public static Singleton1 getInstance() {  
  7.         return single;  
  8.     }  
  9. }  

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的

35:数据库 存储过程 触发器 函数(存储过程是已经编译好了的)

         mysql 执行语句是要先编译,然后再执行的。这样如果查询并发大的时候。会浪费很多资源和时间。造成mysql进程占用资源过多,症状就是慢。但存储过程可以把一些特别的语句封装成一个方法 ,再编译好成一个可以执行的方法,对外只要接收参数就可以了。这样就不用再编译。执行就快了
    什么时候会用到?你觉得你数据库因为同时出现太多读写操作而变得慢 ,那么就要用了。

       存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。 

         触发器是特殊的存储过程,存储过程需要程序调用,而触发器会自动执行;你所说的函数是自定义函数吧,函数是根据输入产生输出,自定义只不过输入输出的关系由用户来定义。在什么时候用触发器?要求系统根据某些操作自动完成相关任务,比如,根据买掉的产品的输入数量自动扣除该产品的库存量。什么时候用存储过程?存储过程就是程序,它是经过语法检查和编译的SQL语句,所以运行特别快。

36:数据库优化

(1)  sql语句优化

不要在数据库中做运算

避免负向查询和%前缀模糊查询

       不在索引列做运算或者使用函数

       不要在生产环境程序中使用select * from 的形式查询数据。只查询需要使用的列

       查询尽可能使用limit减少返回的行数,减少数据传输时间和带宽浪费

       where子句尽可能对查询列使用函数,因为对查询列使用函数用不到索引

       应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描--索引失效

 

(2) 添加适当的索引,索引对查询速度影响很大,必须添加索引。主键索引,唯一索引,普通索引,全文索引选择适当的字段类型,特别是主键

(3) 文件、图片等大文件用文件系统存储,不用数据库

(4) 使用数据缓存

(5) 读写分离(主从数据库)

(6) 分表分区     分表:把一张大表分成多张表。分区:把一张表里面的分配到不同的区域存储,

(7) 添加适当存储过程,触发器,事务等

38:sql 视图和表的区别

         数据库中的数据都是存储在表中的,而视图只是一个或多个表依照某个条件组合而成的结果集,一般来说你可以用update,insert,delete等sql语句修改表中的数据,而对视图只能进行select操作

是物理存在的,你可以理解成计算机中的文件!
视图是虚拟的内存表,你可以理解成Windows的快捷方式!

 

区别:1、视图是已经编译好的sql语句。而表不是  
        2、视图没有实际的物理记录。而表有。
        3、表是内容,视图是窗口
        4、表只用物理空间而视图不占用物理空间,视图只是逻辑概念的存在,表可以及时对它进行修改,但视图只能有创建的语句来修改
        5、表是内模式,视图是外模式
        6、视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些SQL语句的集合。从安全的角度说,视图可以不给用户接触数据表,从而不知道表结构。
        7、表属于全局模式中的表,是实表;视图属于局部模式的表,是虚表。 
        8、视图的建立和删除只影响视图本身,不影响对应的基本表。

使用视图的好处:

 第一点:使用视图,可以定制用户数据,聚焦特定的数据。

第二点:使用视图,可以简化数据操作。

第三点:使用视图,基表中的数据就有了一定的安全性

第四点:可以合并分离的数据,创建分区视图

40:服务器端开发需要的知识点

多进程、多线程:

进程优点:编程、调试简单,可靠性较高。
进程缺点:创建、销毁、切换速度慢,内存、资源占用大。
线程优点:创建、销毁、切换速度快,内存、资源占用小。
线程缺点:编程、调试复杂,可靠性较差。

 

socket开发模型

socket通信在客户端和服务器端进行,主要包括

服务器端行为:

1:服务器端创建套接字,s = socket.socket() ;  2:绑定套接字到本地ip和端口号, s.bind(ip_port);   3:监听连接, s.listen(n);4:接受客户端建立连接的请求,conn,addr = s.accept();  5:接受客户端的消息,并做出相应处理 recv_data = conn.recv(1024);  6 : 给客户端回消息,conn.send(send_data);  7:关闭连接;

 

客户端行为:

1:创建套接字; 2:连接服务器; 3:给服务器发消息; 4:接受服务器消息; 5:关闭连接;

SocketServer实现支持多客户端

SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求

 

        

42:乐观锁/悲观锁

    悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

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

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

乐观锁----操作之前不上锁

悲观所----操作之前上锁

43:java中实现同步的几种方法

1:同步方法

即有synchronized关键字修饰的方法。 

    由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 

     内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

例子:public synchronized void save(){}

 

2:同步代码块

         即有synchronized关键字修饰的语句块。 

     被该关键字修饰的语句块会自动被加上内置锁,从而实现同步

例子:synchronized(object){ 

    }

3:Lock接口

  1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

 2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

 3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

 4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

 5)Lock可以提高多个线程进行读操作的效率。

 

你可能感兴趣的:(校招面经)