同步操作将从 andy.niu/面试宝典 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
排它锁和共享锁
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。
当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。
数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。
表级锁和行级锁
DML锁的目的在于保证并发情况下的数据完整性,主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。
当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S、X等多种模式,在数据库中用0-6来表示。不同的SQL操作产生不同类型的TM锁。
M:Modle(模型,主要是Service业务逻辑层和Dao和数据库取得连接并发送数据的层) V: view(视图,也就是用户看的界面,通常是我们所熟知的前台页面,jsp等) C: controller(控制层,可以把他看作一个中转,他接收从前台用户发来的请求,并调用service,dao把数据发送到后台,后台经过数据库的操作及业务逻辑分析又将数据返回给controller,最后再返回前台jsp页面)。
说说Mvc的优缺点, 优点:
分区 将数据库分区可提高其性能并易于维护。通过将一个大表拆分成更小的单个表,只访问一小部分数据的查询可以执行得更快,因为需要扫描的数据较少。而且可以更快地执行维护任务(如重建索引或备份表)。 实现分区操作时可以不拆分表,而将表物理地放置在个别的磁盘驱动器上。例如,将表放在某个物理驱动器上并将相关的表放在与之分离的驱动器上可提高查询性能,因为当执行涉及表之间联接的查询时,多个磁头同时读取数据。
硬件分区 硬件分区将数据库设计为利用可用的硬件构架。
水平分区 水平分区将一个表分段为多个表,每个表包含相同数目的列和较少的行。例如,可以将一个包含十亿行的表水平分区成12个表,每个小表代表特定年份内一个月的数据。任何需要特定月份数据的查询只引用相应月份的表。
垂直分区 垂直分区将一个表分段为多个表,每个表包含较少的列。垂直分区的两种类型是规范化和行拆分。
基本的redis的容灾策略为:
哨兵的作用
ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。ConnectionFactory为Connection的制造工厂。
Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。
消息回执(Message acknowledgment)
在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机(或出现其他意外)的情况,这种情况下就可能会导致消息丢失。为了避免这种情况发生,我们可以要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除;如果RabbitMQ没有收到回执并检测到消费者的RabbitMQ连接断开,则RabbitMQ会将该消息发送给其他消费者(如果存在多个消费者)进行处理。这里不存在timeout概念,一个消费者处理消息时间再长也不会导致该消息被发送给其他消费者,除非它的RabbitMQ连接断开
消息持久化(Message durability)
如果我们希望即使在RabbitMQ服务重启的情况下,也不会丢失消息,我们可以将Queue与Message都设置为可持久化的(durable),这样可以保证绝大部分情况下我们的RabbitMQ消息不会丢失。但依然解决不了小概率丢失事件的发生(比如RabbitMQ服务器已经接收到生产者的消息,但还没来得及持久化该消息时RabbitMQ服务器就断电了),如果我们需要对这种小概率事件也要管理起来,那么我们要用到事务。
交换器 Exchange
RabbitMQ中的Exchange有四种类型,不同的类型有着不同的路由策略
routing key
生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。
在Exchange Type与binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪里。
RabbitMQ为routing key设定的长度限制为255 bytes
Exchange Types
RabbitMQ常用的Exchange Type有fanout、direct、topic、headers这四种(AMQP规范里还提到两种Exchange Type,分别为system与自定义,这里不予以描述),下面分别进行介绍。
#
匹配一个或多个词,符号 *
匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。用到GC,命名空间System.GC; 可以强制回收 GC.Collect()
GC并不是实时性的,这会造成系统性能上的瓶颈和不确定性。所以有了IDisposable接口,IDisposable接口定义了Dispose方法,这个方法用来供程序员显式调用以释放非托管资源。使用using语句可以简化资源管理。
C# 语言的异常处理功能有助于处理在程序运行期间发生的任何意外或异常情况。 异常处理功能使用 try、catch 和 finally 关键字来尝试执行可能失败的操作、在你确定合理的情况下处理故障,以及在事后清除资源。 公共语言运行时 (CLR)、.NET Framework/任何第三方库或应用程序代码都可以生成异常。 异常是使用 throw 关键字创建而成。
在C#中定义了关键字sealed,被sealed修饰的类不能够被继承。在Java中同样也有关键字final表示一个类不能被继承。C++11提供final关键字使得类不能够被继承。
我们把内存分为堆空间和栈空间
栈的特征:数据只能从栈的顶端插入和删除把数据放入栈顶称为入栈(push)从栈顶删除数据称为出栈(pop)
堆:堆是一块内存区域,与栈不同,堆里的内存能够以任意顺序存入和移除
栈通常保存着我们代码执行的步骤,而堆上存放的则多是对象,数据等。我们可以把栈想象成一个接着一个叠放在一起的盒子。当我们使用的时候,每次从最顶部取走一个盒子。栈也是如此,当一个方法(或类型)被调用完成的时候,就从栈顶取走,接着下一个。堆则不然,像是一个仓库,储存着我们使用的各种对象等信息,跟栈不同的是他们被调用完毕不会立即被清理掉。
栈存储的是基本值类型,堆存储的是new出来的对象。引用类型在栈中存储一个引用,其实际的存储位置位于托管堆。 当我们程序执行的时候,在栈和堆中分配有四种主要的类型:值类型,引用类型,指针,指令。
栈:所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器会自动接着当前栈区的结尾来分配内存
堆:一般由程序员分配释放(new), 若程序员不释放,程序结束时可能由操作系统回收
单例:可以保证系统中一个类只有一个实例,并且自行实例化向整个系统提供(例如一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务)
最简单的就是写考虑线程安全的单例模式
public class Singleton {
// 定义一个静态变量来保存类的实例
private static Singleton uniqueInstance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private Singleton() {}
// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
public static Singleton GetInstance() {
// 双重锁定只需要一句判断就可以了
if (uniqueInstance == null) {
lock(locker) {
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
删掉索引,然后再重建索引
假设老的Web应用程序运转于IIS7.0的集成形式下, 可能需求对应用程序的web.config文件停止修正,特别是运用了完成IHttpHandler接口的自定义模块的状况。IIS7.0在同一个效劳器上可以同时支持两种形式的应用程序。
使用new Thread()和new Thread(Runnable)形式
装箱是将值类型转换为 object 类型或由此值类型实现的任何接口类型的过程。 当 CLR 对值类型进行装箱时,会将该值包装到 System.Object内部,再将后者存储在托管堆上。 取消装箱将从对象中提取值类型。 装箱是隐式的;取消装箱是显式的。 装箱和取消装箱的概念是类型系统 C#统一视图的基础,其中任一类型的值都被视为一个对象。
数据库索引有
唯一索引
唯一索引不允许两行具有相同的索引值。
如果现有数据中存在重复的键值,则大多数数据库都不允许将新创建的唯一索引与表一起保存。当新数据将使表中的键值重复时,数据库也拒绝接受此数据。例如,如果在 employee 表中的职员姓氏(lname) 列上创建了唯一索引,则所有职员不能同姓。
主键索引
主键索引是唯一索引的特殊类型。
数据库表通常有一列或列组合,其值用来唯一标识表中的每一行。该列称为表的主键。
在数据库关系图中为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型。主键索引要求主键中的每个值是唯一的。当在查询中使用主键索引时,它还允许快速访问数据。
它们的一些比较:
聚集索引
一种索引,该索引中键值的逻辑顺序决定了表中相应行的物理顺序。
非聚集索引
一种索引,该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同。
索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块
聚集索引:可以帮助把很大的范围,迅速减小范围。但是查找该记录,就要从这个小范围中Scan了。
非聚集索引:把一个很大的范围,转换成一个小的地图。你需要在这个小地图中找你要寻找的信息的位置。然后通过这个位置,再去找你所需要的记录。
使用场景
基于上述的两种规则,那么在什么时候适合聚集索引,什么时候适合非聚集索引?
Web API更倾向于基于HTTP协议的服务,直接返回用户的数据请求。MVC是建站的一种框架,倾向于返回用户的页面请求。 ASP.NET Web API 的特性,更能说明Web API是一种数据请求框架:
WebAPI主演提供了一套RestfulAPI的开发框架,提供了较为完整的http语义支持,主要用来做开放API,更抽象,更不注重View的生成。
MVC的主要使用场景在于Web站点的开发,他在后端实现了一套完整的MVC开发框架,能提供方便的页面开发,默认使用Razor视图引擎,提供了后端html构造,用户可以方便地开发出带页面的站点。
同构的对象是指类型相同的对象,若声明为int[]的数组就只能存放整形数据,string[]只能存放字符型数据,但声明为object[]的数组除外。
Web Service
WCF
WCF Rest
Web API
先来了解静态常量和动态常量。
const修饰的常量是上述中的第一种,即静态常量,而readonly是上述中第二种即动态常量。他们的区别可以从静态常量和动态常量的特性来说明:
值类型(ValueType)
值类型包括:数值类型,结构体,bool型,用户定义的结构体,枚举,可空类型。
值类型的变量直接存储数据,分配在托管栈中。变量会在创建它们的方法返回时自动释放,例如在一个方法中声明Char型的变量name=’C’,当实例化它的方法结束时,name变量在栈上占用的内存就会自动释放
C#的所有值类型均隐式派生自System.ValueType。
引用类型(ReferenceType)
引用类型包括:数组,用户定义的类、接口、委托,object,字符串,null类型,类。
引用类型的变量持有的是数据的引用,数据存储在数据堆,分配在托管堆中,变量并不会在创建它们的方法结束时释放内存,它们所占用的内存会被CLR中的垃圾回收机制释放。
装箱就是将一个值类型转换成等值的引用类型
在堆上为新生成的对象(该对象包含数据,对象本身没有名称)分配内存。
将堆栈上值类型变量的值拷贝到堆上的对象中。
将堆上创建的对象的地址返回给引用类型变量(从程序员角度看,这个变量的名称就好像堆上对象的名称一样)。
拆箱就是将一个引用类型转换成等值的值类型
将引用类型变量堆上的值拷贝到栈上面。
ref和out都是按地址传递,使用后都将改变原来参数的数值。
方法定义和调用方法都必须显式使用 out关键字
MSDN中定义为:公共语言运行时运行添加类似关键字的描述声明,叫做Attribute,它对程序中的元素进行标注,如类型、方法、字段和属性等。attribute和Microsoft.Net Framework文件的元数据保存在一起,可以用来在运行时描述你的代码,或者在程序运行时影响应用程序的行为。
我们简单地总结:定制特性attribute,本质上是一个类,其为目标元素提供关联附加信息,并在运行时以反射的方式来获取附件信息。
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
委托是一种特殊的类型(class),用途是来实现对一种方法的封装。在某种事件发生时,自动调用该方法。好处显然易见,它使用户可以自定义自己的方法实现,通过封装,CLR会在相应事件激发时调用你定义的方法,实现你的功能。
C#内置委托 Action、Action、Func、Predicate
CLR环境中给我们内置了几个常用委托Action、 Action、Func、Predicate,一般我们要用到委托的时候,尽量不要自己再定义一 个委托了,就用系统内置的这几个已经能够满足大部分的需求,且让代码符合规范。
这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
AOP面向切面编程链接
首先先上官方Msdn的说法
lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock 关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit。 ThreadInterruptedException 引发,如果 Interrupt 中断等待输入 lock 语句的线程。 通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。
常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。
在 lock 语句的正文不能使用 等待 关键字。
打个比方,有这样一个情景,很多公司所在的大厦的厕所的蹲位都是小单间型的,也就是一次只能进去一个人,那么为了避免每次进去一个人,那怎么做呢?不就是一个人进去之后顺手把门锁上么?这样你在里面干啥事,外边的人也只能等待你解放完了,才能进入。而蹲位的资源(蹲位,手纸等)是共享的。
最常使用的锁是如下格式的代码段:
private static object objlock = new object();
lock (objlock )
{
//要执行的代码逻辑
}
为什么锁的对象是私有的呢?还是以厕所为例子吧,私有就好比,这把锁只有你能访问到,而且最好这把锁不会因为外力而有所改变,别人访问不到,这样才能保证你进去了,别人就进不去了,如果是公有的,就好比你蹲位小单间的锁不是安装在里面而是安装在外边的,别人想不想进就不是你所能控制的了,这样也不安全。
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有 RabbitMQ等。
什么是AMQP 高级消息队列协议使得遵从该规范的客户端应用和消息中间件服务器的全功能互操作成为可能。
//快速排序 递归
function quickSort(arr){
if(arr.length<=1) return arr;
var num = Math.floor(arr.length/2);//找到中间数的索引值,如果是浮点数,则向下取整
var numValue = arr.splice(num,1);//找到中间数的值
var left = [] , right = [];
for(var i = 0; i< arr.length ; i++){
if(arr[i]<numValue ){
left.push(arr[i]);//基准点的左边的数传到左边数组
}else{
right.push(arr[i]);//基准点的右边的数传到右边数组
}
}
return quickSort(left).concat([numValue],quickSort(right));//递归不断重复比较
}
// parseInt 实现
function _parseInt (str, radix) {
let str_type = typeof str
let res = 0
if (str_type !== 'string' && str_type !== 'number') {
// 如果类型不是 string 或 number 类型返回NaN
return NaN
}
// 字符串处理
str = String(str).trim().split('.')[0]
let length = str.length
if (!length) {
// 如果为空则返回 NaN
return NaN
}
if (!radix) {
// 如果 radix 为0 null undefined
// 则转化为 10
radix = 10
}
if (typeof radix !== 'number' || radix < 2 || radix > 36) {
return NaN
}
for (let i = 0; i < length; i++) {
let arr = str.split('').reverse().join('')
res += Math.floor(arr[i]) * Math.pow(radix, i)
}
return res
}
//获取url参数返回object对象
function fn(){
var _array = location.href.split('?'),obj = {};
if(_array.length==1) return obj;
var array = _array[1].split('&');
for(var i = 0 ;i < array.length; i++){
var temp = array[i].split('=')
obj[temp[0]] = temp[1];
}
return obj;
}
function fn2(){
var _array = location.href.match(/([^?&=]+)=([^?&=]*)/g),obj = {};
if(_array){
for(var i = 0 ;i < _array.length; i++){
var temp = _array[i].split('=')
obj[temp[0]] = temp[1];
}
}
return obj;
}
//去除空格
string.replace(/(^\s*)|(\s*$)/gi,'');
//call()方法和apply()
//1. 每个函数都包含两个非继承而来的方法:call()方法和apply()方法。
//2. 相同点:这两个方法的作用是一样的。
//3. 不同点:接收参数的方式不同。
//apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
apply([thisObj [,argArray] ]);
//call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。
call([thisObject[,arg1 [,arg2 [,...,argn]]]]);
//闭包
//定义和用法:当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。
//表现形式:使函数外部能够调用函数内部定义的变量。
//什么是跨域?
//由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域
//porxy代理 通过nginx代理
//CORS 【Cross-Origin Resource Sharing】
res.writeHead(200, {
"Content-Type": "text/html; charset=UTF-8",
"Access-Control-Allow-Origin":'http://localhost',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'X-Requested-With, Content-Type'
});
//jsonp
function testjsonp(data) {
console.log(data.name); // 获取返回的结果
}
var _script = document.createElement('script');
_script.type = "text/javascript";
_script.src = "http://localhost:8888/jsonp?callback=testjsonp";
document.head.appendChild(_script);
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。