温故知新: Java服务端开发笔记

原创 2015年11月18日 21:52:17

Java

Java集合接口/类

基本接口/类层次结构 [I]:接口 [C]:类

java.util.Collection [I]
+--java.util.List [I]
   +--java.util.ArrayList [C]
   +--java.util.LinkedList [C]
   +--java.util.Vector [C]
      +--java.util.Stack [C]
+--java.util.Set [I]
   +--java.util.HashSet [C]
   +--java.util.SortedSet [I]
      +--java.util.TreeSet [C]

java.util.Map [I]
+--java.util.SortedMap [I]
   +--java.util.TreeMap [C]
+--java.util.Hashtable [C]
+--java.util.HashMap [C]
+--java.util.LinkedHashMap [C]
+--java.util.WeakHashMap [C]

ArrayList和LinkedList区别
ArrayList基于数组实现,LinkedList基于链表实现,ArrayList增加和删除比LinkedList慢,但是LinkedList在查找的时需要递归查找,效率比ArrayList慢。
关于多线程方面,如果要求线程安全的,有一个Vector,不过比较多的使用的是CopyOnWriteArrayList替代ArrayList,CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。发生修改时候做copy,新老版本分离,保证读的高性能,适用于以读为主的情况。

对集合操作的工具类

Java提供了java.util.Collections,以及java.util.Arrays类简化对集合的操作
java.util.Collections主要提供一些static方法用来操作或创建Collection,Map等集合。
java.util.Arrays主要提供static方法对数组进行操作。

第三方集合框架

Apache Commons Collections,Google Guava

枚举

在实际编程中,往往存在着这样的“数据集”,它们的数值在程序中是稳定的,而且“数据集”中的元素是有限的。
例如星期一到星期日七个数据元素组成了一周的“数据集”,春夏秋冬四个数据元素组成了四季的“数据集”。
在Java中如何更好的使用这些“数据集”呢?这时枚举便派上了用场。

Java枚举7种常见用法  Java枚举使用详解

泛型

泛型接口、泛型类和泛型方法


Java I/O

Java IO主要主要在java.io包下,分为四大块近80个类:
1、基于字节操作的I/O接口:InputStream和OutputStream
2、基于字符操作的I/O接口:Writer和Reader
3、基于磁盘操作的I/O接口:File
4、基于网络操作的I/O接口:Socket(不在java.io包下)

参考:Java之美[从菜鸟到高手演变]之Java中的IO

HashMap的工作原理

HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,然后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。
HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。
当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。

参考:HashMap的工作原理

ArrayList/HashSet/HashMap都是线程不安全的。ConcurrentHashMap并发优化的HashMap,但JDK没提供ConcurrentHashSet。
在多线程下使用HashMap,有几种方案:
(1) 在外部包装HashMap,实现同步机制
(2) 使用Map m = Collections.synchronizedMap(new HashMap(...));,这里就是对HashMap做了一次包装
(3) 使用java.util.HashTable,效率最低
(4) 使用java.util.concurrent.ConcurrentHashMap,相对安全,效率较高

Java异常处理机制


Java异常类层次结构图

Java中,异常类的根类是java.lang.Throwable类,Throwable有两个子类:Error和Exception。

Error是无法处理的异常,比如OutOfMemoryError,一般发生这种异常,JVM会选择终止程序。因此我们编写程序时不需要关心这类异常。NoClassDefFoundError、StackOverFlowError都属于Error。

Exception就是可以处理的异常,包括checked exception和unchecked exception(unchecked exception也称运行时异常RuntimeException,当然这里的运行时异常并不是前面我所说的运行期间的异常,只是Java中用运行时异常这个术语来表示,Exception类的异常都是在运行期间发生的)。

unchecked exception(非检查异常),也称运行时异常(RuntimeException),比如常见的NullPointerExceptionIndexOutOfBoundsException。对于运行时异常,Java编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。

checked exception(检查异常),也称非运行时异常(运行时异常以外的异常就是非运行时异常),java编译器强制程序员必须进行捕获处理,比如常见的IOExeptionSQLException。对于非运行时异常如果不进行捕获或者抛出声明处理,编译都不会通过

参考:Java异常处理和设计  深入理解Java异常处理机制

对象序列化
反射

Java类加载机制


Java默认提供的三个ClassLoader

Bootstrap ClassLoader:称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等,
Extension ClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
Application ClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。

ClassLoader加载类的原理

ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。
当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

参考:Java ClassLoader原理详细分析Java Classloader机制解析

Java垃圾回收机制

Java的垃圾回收机制用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间。
System.gc()
Runtime.getRuntime().gc()  
上面的方法调用时用于显式通知JVM可以进行一次垃圾回收,但真正垃圾回收机制具体在什么时间点开始发生是不可预料的。


JVM

JVM(Java Virtual Machine,Java虚拟机)是使用实现Java语言平台的无关性的关键。
Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。

操作系统装入JVM通过JDK中的Java.exe来完成,经如下4步来完成JVM环境。
(1) 创建JVM装载环境和配置
(2) 装载JVM.dll
(3) 初始化JVM.dll并挂接到JNIEnv(JNI调用接口)实例
(4) 调用JNIEnv实例装载并处理class类


JVM内存区域模型

方法区和堆由所有线程共享,其他区域都是线程私有的。

(1) 方法区
也称"永久代” 、“非堆”,它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域。默认最小值为16MB,最大值为64MB,可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小。
运行时常量池:是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分内容将在类加载后放到方法区的运行时常量池中。

(2) 虚拟机栈
描述的是Java方法执行的内存模型:每个方法被执行的时候都会创建一个“栈帧”用于存储局部变量表(包括参数)、操作栈、方法出口等信息。每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。声明周期与线程相同,是线程私有的。
局部变量表存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(引用指针,并非对象本身),其中64位长度的long和double类型的数据会占用2个局部变量的空间,其余数据类型只占1个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量是完全确定的,在运行期间栈帧不会改变局部变量表的大小空间。

(3)本地方法栈
与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的Java方法服务,而本地方法栈则是为Native方法服务。

(4)堆 
也叫做java 堆、GC堆是java虚拟机所管理的内存中最大的一块内存区域,也是被各个线程共享的内存区域,在JVM启动时创建。该内存区域存放了对象实例及数组(所有new的对象)。其大小通过-Xms(最小值)和-Xmx(最大值)参数设置,-Xms为JVM启动时申请的最小内存,默认为操作系统物理内存的1/64但小于1G,-Xmx为JVM可申请的最大内存,默认为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列;当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过XX:MaxHeapFreeRation=来指定这个比列,对于运行系统,为避免在运行时频繁调整Heap的大小,通常-Xms与-Xmx的值设成一样。
由于现在收集器都是采用分代收集算法,堆被划分为新生代和老年代。新生代主要存储新创建的对象和尚未进入老年代的对象。老年代存储经过多次新生代GC(Minor GC)任然存活的对象。
新生代
程序新创建的对象都是从新生代分配内存,新生代由Eden Space和两块相同大小的Survivor Space(通常又称S0和S1或From和To)构成,可通过-Xmn参数来指定新生代的大小,也可以通过-XX:SurvivorRation来调整Eden Space及Survivor Space的大小。
老年代
用于存放经过多次新生代GC任然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代,主要有两种情况:①.大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。②.大的数组对象,切数组中无引用外部对象。
老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。


(5)程序计数器 
是最小的一块内存区域,它的作用是当前线程所执行的字节码的行号指示器,在虚拟机的模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖计数器完成。

参考:Java虚拟机学习 - 体系结构 内存模型  JVM虚拟机结构

消息队列

消息队列的通俗解释:

消息队列,顾名思义,首先是个队列。队列的操作有入队和出队,也就是你有一个程序在产生内容然后入队(生产者),另一个程序读取内容,内容出队(消费者)。当你不需要立即获得结果,但是并发量又不能无限大的时候,差不多就是你需要使用消息队列的时候。

消息队列有很多开源实现,ZMQ也好,RabbitMQ也好甚至Redis也好,找一个合适的装上用就行。
消息队列解决的是将突发大量请求转换为后端能承受的队列请求,比如你的服务器一秒能处理100个订单,但秒杀活动1秒进来1000个订单,持续10秒,在后端能力无法增加的情况下,你可以用消息队列将总共10000个请求压在队列里,后台consumer按原有能力处理,100秒后处理完所有请求(而不是直接宕机丢失订单数据)。

使用消息队列可以模拟生产者 - 消费者模型。在JDK中,可借助阻塞队列BlockingQueue实现生产者 - 消费者模式。

BlockingQueue常用的四个实现类
1)ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的.
2)LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含的对象是以FIFO(先入先出)顺序排序的
3)PriorityBlockingQueue:类似于LinkedBlockQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数的Comparator决定的顺序.
4)SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的.

参考:生产者/消费者问题的多种Java实现方式  Java多线程(五)之BlockingQueue深入分析  Java多线程-并发协作(生产者消费者模型)  BlockingQueue  

单例模式

public class Singleton {
	private static Singleton instance;

	private Singleton() {
	}

	public static synchronized Singleton getInstance() {
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

单例模式的七种写法

Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方。
单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这是多个线程会并发执行该请求多对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对该单列状态的修改(体现为该单列的成员属性),则必须考虑线程同步问题。

同步机制的比较

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。 
在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。 
而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。 

概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

Spring单例与线程安全小结

ReentrantLock的使用

ReentrantLock是一个可重入的互斥锁,重入锁是一种递归无阻塞的同步机制。
ReentrantLock由最近成功获取锁,还没有释放的线程所拥有,当锁被另一个线程拥有时,调用lock的线程可以成功获取锁。如果锁已经被当前线程拥有,当前线程会立即返回。

重入锁的构造方法提供一个可选的公平参数:
公平情况下,操作会排一个队按顺序执行,来保证执行顺序。
不公平情况下,是无序状态允许插队,jvm会自动计算如何处理更快速来调度插队。

(1) 防止重复执行(忽略重复触发)
ReentrantLock lock = new ReentrantLock(); //参数默认false,不公平锁 
if (lock.tryLock()) {  //如果已经被lock,则立即返回false不会等待,达到忽略操作的效果   
    try {  
        //操作  
    } finally {  
        lock.unlock();  
    }
}

(2) 同步执行,类似synchronized
ReentrantLock lock = new ReentrantLock(true); //公平锁  
lock.lock(); //如果被其它资源锁定,会在此等待锁释放,达到暂停的效果  
try {  
    //操作  
} finally {  
    lock.unlock();  
}

(3) 尝试等待执行
ReentrantLock lock = new ReentrantLock(true); //公平锁  
try {  
    if (lock.tryLock(5, TimeUnit.SECONDS)) {      
        //如果已经被lock,尝试等待5s,看是否可以获得锁,如果5s后仍然无法获得锁则返回false继续执行  
        try {  
            //操作  
        } finally {  
            lock.unlock();  
        }  
    }  
} catch (InterruptedException e) {  
    e.printStackTrace(); //当前线程被中断时(interrupt),会抛InterruptedException                   
}  

(4) 可中断锁的同步执行
ReentrantLock lock = new ReentrantLock(true); //公平锁  
lock.lockInterruptibly();  
try {  
    //操作  
} catch (InterruptedException e) {  
    e.printStackTrace();  
} finally {  
    lock.unlock();  
}  

RMI


Java小程序
Java8新特性:接口的默认方法,lamda表达式,函数式编程,方法引用,多重annotation

并发编程 多线程编程
线程安全的 线程池


XML,XSL,XSD
JSON
Web Service

JSP
JSTL

Web容器

解除Tomcat中POST方式上传文件的大小限制

Tomcat服务器中,通过POST上传的文件大小的最大值为2M(2097152)。如果想修改该限制,修改方法如下:
Tomcat目录下的conf文件夹下,server.xml文件中以下的位置中添加maxPostSize参数
<Connector port="8081"  
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"  
               enableLookups="false" redirectPort="8443" acceptCount="100"  
               debug="0" connectionTimeout="20000"   
               disableUploadTimeout="true" URIEncoding="GBK"  
               maxPostSize="0"/>  
当maxPostSize<=0时,POST方式上传的文件大小不会被限制。
注意:maxPostSize参数只有当request的Content-Type为“application/x-www-form-urlencoded”时起作用。

Tomcat中使用线程池配置高并发连接

打开/conf/server.xml文件,进行如下配置:

(1) 配置executor属性
在Connector之前配置线程池:

<Executor name="tomcatThreadPool"   
        namePrefix="tomcatThreadPool-"   
        maxThreads="1000"   
        maxIdleTime="300000"  
        minSpareThreads="200"/>  
重要参数说明:

name:共享线程池的名字。这是Connector为了共享线程池要引用的名字,该名字必须唯一。默认值:None;
namePrefix:在JVM上,每个运行线程都可以有一个name 字符串。这一属性为线程池中每个线程的name字符串设置了一个前缀,Tomcat将把线程号追加到这一前缀的后面。默认值:tomcat-exec-;
maxThreads:该线程池可以容纳的最大线程数。默认值:200;
maxIdleTime:在Tomcat关闭一个空闲线程之前,允许空闲线程持续的时间(以毫秒为单位)。只有当前活跃的线程数大于minSpareThread的值,才会关闭空闲线程。默认值:60000(一分钟)。
minSpareThreads:Tomcat应该始终打开的最小不活跃线程数。默认值:25。

(2) 配置Connector

<Connector executor="tomcatThreadPool"  
           port="8080" protocol="HTTP/1.1"  
               connectionTimeout="20000"  
               redirectPort="8443"   
           minProcessors="5"  
           maxProcessors="75"  
           acceptCount="1000"/>  

重要参数说明:

executor:表示使用该参数值对应的线程池;
minProcessors:服务器启动时创建的处理请求的线程数;
maxProcessors:最大可以创建的处理请求的线程数;
acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。

Tomcat配置与优化(内存、并发、管理)
Tomcat 配置详解/优化方案

Jetty
WebLogic

开发框架

SSH SSM

ORM框架

常见的Java ORM框架有,
Hibernate  
iBatis 
Apache OJB  
Cayenne   
Jaxor
jRelationalFramework  
mirage   
SMYLE   
TopLink
其中TopLink是Oracle的商业产品,其他均为开源项目。

Spring

Spring是一个分层的JavaSE/JavaEE full-stack(一站式)轻量级开源框架。Spring是企业应用开发的“一站式”选择,贯穿表现层、业务层及持久层。Spring并不想取代那些已有的框架,而是与它们无缝地整合。


IoC原理

IoC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IOC容器进行组装。在Spring中BeanFactory是IOC容器的实际代表者。参考资料:谈谈对Spring IOC的理解

利用反射完成依赖注入,实现控制反转。

AOP原理

Spring MVC 中 HandlerInterceptorAdapter的使用

对Spring中的Controller做拦截

Log4j 实现运行时的日志级别更改

Spring的普通类中如何取session和request对像

RESTful编程

SOAP Web Serivce和RESTful Web Service的对比及区别

Spring MVC

Spring Batch

Socket框架:Mina,Netty
消息框架:RabbitMQ,ActiveMQ
工作流引擎:Shark,osworkflow,jbpm
OSGI
Lucene
Groovy

分布式缓存 MemCached
亚马逊云计算服务 AWS
Docker

杂记

Controller中获取访问者IP

/**
	 * 获取访问者IP
	 * 
	 * 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。
	 * 
	 * 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割),
	 * 如果还不存在则调用Request .getRemoteAddr()。
	 * 
	 * @param request
	 * @return
	 */
	private static String getIpAddr(HttpServletRequest request) throws Exception {
		String ip = request.getHeader("X-Real-IP");
		if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
			return ip;
		}
		ip = request.getHeader("X-Forwarded-For");
		if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
			// 多次反向代理后会有多个IP值,第一个为真实IP。
			int index = ip.indexOf(',');
			if (index != -1) {
				return ip.substring(0, index);
			} else {
				return ip;
			}
		} else {
			return request.getRemoteAddr();
		}
	}

获取web项目绝对路径

/**
	 *  
	 * @param request
	 * @return
	 */
	private static String getAppPath(HttpServletRequest request){
		return request.getServletContext().getRealPath("/");
	}
HttpClient中处理Post方式传递的JSON数据

PostMethod method = new PostMethod(url);
RequestEntity entity;
// JSONObject jsonParams
entity = new StringRequestEntity(jsonParams.toString(), "application/json", "utf-8");
method.setRequestEntity(entity);

Hadoop

实现分布式文件系统,核心:HDFS, MapReduce

Apache Hadoop Ecosystem

关系型数据库

Oracle

MySQL

SQLite

大表处理(分库分表)

提高大表查询速度:查询优化,索引,分区

索引原理

数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。
为表设置索引要付出代价的:一是增加了数据库的存储空间,二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。

NoSQL数据库

NoSQL概述

NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL"。

NoSQL,指的是非关系型的数据库,是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL用于超大规模数据的存储。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

NoSQL
- 代表着不仅仅是SQL
- 没有声明性查询语言
- 没有预定义的模式
- 键 - 值对存储,列存储,文档存储,图形数据库
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- CAP定理
- 高性能,高可用性和可伸缩性

CAP定理(CAP theorem)
在计算机科学中, CAP定理(CAP theorem), 又被称作 布鲁尔定理(Brewer's theorem), 它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
  • 一致性(Consistency) (所有节点在同一时间具有相同的数据)
  • 可用性(Availability) (保证每个请求不管成功或者失败都有响应)
  • 分隔容忍(Partition tolerance) (系统中任意信息的丢失或失败不会影响系统的继续运作)
CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。
因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:
  • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
  • CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。
  • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。

NoSQL数据库分类

类型 部分代表

特点
列存储

Hbase

Cassandra

Hypertable

顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。

文档存储

MongoDB

CouchDB

文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有有机会对某些字段建立索引,实现关系数据库的某些功能。

key-value存储

Tokyo Cabinet / Tyrant

Berkeley DB

MemcacheDB

Redis

可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能)

图存储

Neo4J

FlockDB

图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。

对象存储

db4o

Versant

通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。

xml数据库

Berkeley DB XML

BaseX

高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。

MongoDB

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
MongoDB中基本的概念是文档、集合、数据库
SQL术语/概念 MongoDB术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins   表连接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键
MongoDB适用于以下场景:
a.网站数据:MongoDB非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
b.缓存:由于性能很高,MongoDB也适合作为信息基础设施的缓存层。在系统重启之后,由MongoDB搭建的持久化缓存可以避免下层的数据源过载。
c.大尺寸、低价值的数据:使用传统的关系数据库存储一些数据时可能会比较贵,在此之前,很多程序员往往会选择传统的文件进行存储。
d.高伸缩性的场景:MongoDB非常适合由数十或者数百台服务器组成的数据库。
e.用于对象及JSON数据的存储:MongoDB的BSON数据格式非常适合文档格式化的存储及查询。

Redis

Redis

Redis是一个高性能的key-value数据库,可以用作数据库、缓存和消息中间件。
Redis支持的value类型包括string(字符串)、list(链表)、set(集合)、zset(sorted set,有序集合)和hash(哈希类型)。
Redis数据库完全在内存中,使用磁盘仅用于持久性。
Redis默认端口:6379


版权声明:本文为博主原创文章,未经博主允许不得转载。

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Java TCP/IP学习笔记之TCP服务端

TCP服务端     服务端的工作就是一个通信终端,并被动等待客户端的链接。 package network; import java.io.IOException; import ...

[mnt-base] Java服务端开发工具包

  • 2013年07月11日 11:07
  • 636KB
  • 下载

服务端开发笔记二:基于pomelo的分布式手游架构

经过了一个周的时间,新项目的基本结构已经大体确定,拿来给大家分享。 一 基础概念 在说明手游服务器架构之前,一下几点须知。 1 我们的服务器集群分为前端服务器和后端服务器。 前端服务器:负责接收前...

ejabberd服务端开发笔记

网上一搜一大陀ejabberd安装配置的,扩展开发的资料少之又少,写个笔记记录一下。 xmpp protocal: http://xmpp.org/xmpp-protocols/xmpp-ext...

游戏开发笔记(六)——服务端架构设计

上回写了写服务端的分层结构,分层是比较宏观上的东西,至于层次间具体的交互方式还得通过各个模块的交互方式来体现,姑且把这种模块划分以及其间的交互关系称之为架构吧,下面就来谈谈MMORPG的服务端架构, ...
  • mooke
  • mooke
  • 2013年05月11日 01:43
  • 13944
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:温故知新: Java服务端开发笔记
举报原因:
原因补充:

(最多只允许输入30个字)