几款主流 NoSQL 数据库的对比

来源:VaJoy Larn

链接:http://www.cnblogs.com/vajoy/p/5471308.html

最近小组准备启动一个 node 开源项目,从前端亲和力、大数据下的IO性能、可扩展性几点入手挑选了 NoSql 数据库,但具体使用哪一款产品还需要做一次选型。

我们最终把选项范围缩窄在 HBase、Redis、MongoDB、Couchbase、LevelDB 五款较主流的数据库产品中,本文将主要对它们进行分析对比。

鉴于缺乏项目中的实战经验沉淀,本文内容和观点主要还是从各平台资料搜罗汇总,也不会有太多深入或底层原理探讨。

本文所引用的资料来源将示于本文尾部。所汇总的内容仅供参考,若有异议望指正。

HBase

HBase 是 Apache Hadoop 中的一个子项目,属于 bigtable 的开源版本,所实现的语言为Java(故依赖 Java SDK)。HBase 依托于 Hadoop 的 HDFS(分布式文件系统)作为最基本存储基础单元。

HBase在列上实现了 BigTable 论文提到的压缩算法、内存操作和布隆过滤器。HBase的表能够作为 MapReduce任务的输入和输出,可以通过Java API来访问数据,也可以通过REST、Avro或者Thrift的API来访问。
1. 特点

1.1 数据格式

HBash 的数据存储是基于列(ColumnFamily)的,且非常松散—— 不同于传统的关系型数据库(RDBMS),HBase 允许表下某行某列值为空时不做任何存储(也不占位),减少了空间占用也提高了读性能。

不过鉴于其它NoSql数据库也具有同样灵活的数据存储结构,该优势在本次选型中并不出彩。
我们以一个简单的例子来了解使用 RDBMS 和 HBase 各自的解决方式:

⑴ RDBMS方案:

其中Article表格式:

Author表格式:

⑵ 等价的HBase方案:

对于前端而言,这里的 Column Keys 和 Column Family 可以看为这样的关系:

columId1 = { //id=1的行

    article: {  //ColumnFamily-article

        title: XXX,  //ColumnFamily-article下的key之一

        content: XXX,

        tags: XXX

    },

    author: {  //ColumnFamily-author

        name: XXX

        nickname: XXX

    }

}

1.2 性能

HStore存储是HBase存储的核心,它由两部分组成,一部分是MemStore,一部分是StoreFiles。

MemStore 是 Sorted Memory Buffer,用户写入的数据首先会放入MemStore,当MemStore满了以后会Flush成一个StoreFile(底层实现是HFile),当StoreFile文件数量增长到一定阈值,会触发Compact合并操作,将多个StoreFiles合并成一个StoreFile,合并过程中会进行版本合并和数据删除,因此可以看出HBase其实只有增加数据,所有的更新和删除操作都是在后续的compact过程中进行的,这使得用户的写操作只要进入内存中就可以立即返回,保证了HBase I/O的高性能。

1.3 数据版本

Hbase 还能直接检索到往昔版本的数据,这意味着我们更新数据时,旧数据并没有即时被清除,而是保留着:

Hbase 中通过 row+columns 所指定的一个存贮单元称为cell。每个 cell都保存着同一份数据的多个版本——版本通过时间戳来索引。

时间戳的类型是 64位整型。时间戳可以由Hbase(在数据写入时自动 )赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个 cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。

为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,Hbase提供了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。

1.4 CAP类别
属于CP类型。

2. Node下的使用

HBase的相关操作可参考下表:

在node环境下,可通过 node-hbase 来实现相关访问和操作,注意该工具包依赖于 PHYTHON2.X(3.X不支持)和Coffee。

如果是在 window 系统下还需依赖 .NET framwork2.0,64位系统可能无法直接通过安装包安装。

官方示例:

var assert = require(‘assert’);

var hbase = require(‘hbase’);

 

hbase({ host: ‘127.0.0.1’, port: 8080 })

.table(‘my_table’ )

//创建一个Column Family

.create(‘my_column_family’, function(err, success){

  this.row(‘my_row’)   //定位到指定行

  .put(‘my_column_family:my_column’, ‘my value’, function(err, success){

    this.get(‘my_column_family’, function(err, cells){

      this.exists(function(err, exists){

        assert.ok(exists);

      });

    });

  });

});

数据检索:

client

.table(‘node_table’)

.scan({

  startRow: ‘my_row’,  //起始行

  maxVersions: 1  //版本

}, function(err, rows){

  console.log(err, rows);

});

另有 hbase-client 也是一个不错的选择,具体API参照其文档。

3. 优缺点

优势

1. 存储容量大,一个表可以容纳上亿行,上百万列;

2. 可通过版本进行检索,能搜到所需的历史版本数据;

3. 负载高时,可通过简单的添加机器来实现水平切分扩展,跟Hadoop的无缝集成保障了其数据可靠性(HDFS)和海量数据分析的高性能(MapReduce);

4. 在第3点的基础上可有效避免单点故障的发生。

缺点

1. 基于Java语言实现及Hadoop架构意味着其API更适用于Java项目;

2. node开发环境下所需依赖项较多、配置麻烦(或不知如何配置,如持久化配置),缺乏文档;

3. 占用内存很大,且鉴于建立在为批量分析而优化的HDFS上,导致读取性能不高;

4. API相比其它 NoSql 的相对笨拙。

适用场景

1. bigtable类型的数据存储;

2. 对数据有版本查询需求;

3. 应对超大数据量要求扩展简单的需求。

Redis

Redis 是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。目前由VMware主持开发工作。
1. 特点

1.1 数据格式
Redis 通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash/Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)五种类型,操作非常方便。比如,如果你在做好友系统,查看自己的好友关系,如果采用其他的key-value系统,则必须把对应的好友拼接成字符串,然后在提取好友时,再把value进行解析,而redis则相对简单,直接支持list的存储(采用双向链表或者压缩链表的存储方式)。
我们来看下这五种数据类型。

⑴ String

  • string 是 Redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个key对应一个value。
  • string 类型是二进制安全的。意思是 Redis 的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象 。
  • string 类型是 Redis 最基本的数据类型,一个键最大能存储512MB。

实例:

redis 127.0.0.1:6379> SET name zfpx

OK

redis 127.0.0.1:6379> GET name

“zfpx”

在以上实例中我们使用了 Redis 的 SET 和 GET 命令。键为 name,对应的值为”zfpx”。 注意:一个键最大能存储512MB。

⑵ Hash

  • Redis hash 是一个键值对集合。
  • Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

实例:

redis 127.0.0.1:6379> HMSET user:1 username zfpx password 123

OK

redis 127.0.0.1:6379> HGETALL user:1

1) “username”

2) “zfpx”

3) “password”

4) “123”

以上实例中 hash 数据类型存储了包含用户脚本信息的用户对象。 实例中我们使用了 Redis HMSET, HGETALL 命令,user:1 为键值。 每个 hash 可以存储 232 – 1 键值对(40多亿)。

⑶ List

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。

实例:

redis 127.0.0.1:6379> lpush name zfpx1

(integer) 1

redis 127.0.0.1:6379> lpush name zfpx2

(integer) 2

redis 127.0.0.1:6379> lpush name zfpx3

(integer) 3

redis 127.0.0.1:6379> lrange name 01

1) “zfpx3”

2) “zfpx2”

3) “zfpx1”

列表最多可存储 232 – 1 元素 (4294967295, 每个列表可存储40多亿)。

⑷ Sets

Redis的Set是string类型的无序集合。 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

添加一个string元素到 key 对应的 set 集合中,成功返回1,如果元素已经在集合中返回0,key对应的set不存在返回错误,指令格式为

sadd key member

实例:

redis 127.0.0.1:6379> sadd school zfpx1

(integer) 1

redis 127.0.0.1:6379> sadd school zfpx1

(integer) 0

redis 127.0.0.1:6379> sadd school zfpx2

(integer) 1

redis 127.0.0.1:6379> sadd school zfpx2

(integer) 0

redis 127.0.0.1:6379> smembers school

 

1) “zfpx1”

2) “zfpx2”

注意:以上实例中 zfpx1 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。 集合中最大的成员数为 232 – 1 (4294967295, 每个集合可存储40多亿个成员)。

⑸ sorted sets/zset

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。可以通过 zadd 命令(格式如下) 添加元素到集合,若元素在集合中存在则更新对应score

zadd key score member

实例:

redis 127.0.0.1:6379> zadd school 0 zfpx1

(integer) 1

redis 127.0.0.1:6379> zadd school 2 zfpx2

(integer) 1

redis 127.0.0.1:6379> zadd school 0 zfpx3

(integer) 1

redis 127.0.0.1:6379> zadd school 1 zfpx4

(integer) 0

redis 127.0.0.1:6379> ZRANGEBYSCORE school 0 100

 

1) “zfpx1”

2) “zfpx3”

3) “zfpx4”

4) “zfpx2”

1.2 性能

Redis数据库完全在内存中,因此处理速度非常快,每秒能执行约11万集合,每秒约81000+条记录。

Redis的数据能确保一致性——所有Redis操作是原子性(Atomicity,意味着操作的不可再分,要么执行要么不执行)的,这保证了如果两个客户端同时访问的Redis服务器将获得更新后的值。

1.3 持久化

通过定时快照(snapshot)和基于语句的追加(AppendOnlyFile,aof)两种方式,redis可以支持数据持久化——将内存中的数据存储到磁盘上,方便在宕机等突发情况下快速恢复。

1.4 CAP类别

属于CP类型。

2. Node下的使用

node 下可使用 node_redis 来实现 redis 客户端操作:

var redis = require(“redis”),

    client = redis.createClient();

 

// if you’d like to select database 3, instead of 0 (default), call

// client.select(3, function() { /* … */ });

 

client.on(“error”, function (err) {

    console.log(“Error “ + err);

});

 

client.set(“string key”, “string val”, redis.print);

client.hset(“hash key”, “hashtest 1”, “some value”, redis.print);

client.hset([“hash key”, “hashtest 2”, “some other value”], redis.print);

client.hkeys(“hash key”, function (err, replies) {

    console.log(replies.length + ” replies:”);

    replies.forEach(function (reply, i) {

        console.log(”    “ + i + “: “ + reply);

    });

    client.quit();

});

3. 优缺点

优势

1. 非常丰富的数据结构;

2. Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断;

3. 数据存在内存中,读写非常的高速,可以达到10w/s的频率。

缺点

1. Redis3.0后才出来官方的集群方案,但仍存在一些架构上的问题(出处);

2. 持久化功能体验不佳——通过快照方法实现的话,需要每隔一段时间将整个数据库的数据写到磁盘上,代价非常高;而aof方法只追踪变化的数据,类似于mysql的binlog方法,但追加log可能过大,同时所有操作均要重新执行一遍,恢复速度慢;

3. 由于是内存数据库,所以,单台机器,存储的数据量,跟机器本身的内存大小。虽然redis本身有key过期策略,但是还是需要提前预估和节约内存。如果内存增长过快,需要定期删除数据。

适用场景

适用于数据变化快且数据库大小可遇见(适合内存容量)的应用程序。更具体的可参照这篇《Redis 的 5 个常见使用场景》译文。

MongoDB

MongoDB 是一个高性能,开源,无模式的文档型数据库,开发语言是C++。它在许多场景下可用于替代传统的关系型数据库或键/值存储方式。

1.特点

1.1 数据格式

在 MongoDB 中,文档是对数据的抽象,它的表现形式就是我们常说的 BSON(Binary JSON )。

BSON 是一个轻量级的二进制数据格式。MongoDB 能够使用 BSON,并将 BSON 作为数据的存储存放在磁盘中。

BSON 是为效率而设计的,它只需要使用很少的空间,同时其编码和解码都是非常快速的。即使在最坏的情况下,BSON格式也比JSON格式再最好的情况下存储效率高。

对于前端开发者来说,一个“文档”就相当于一个对象:

{name“:”mengxiangyue“,”sex“:”nan}

对于文档是有一些限制的:有序、区分大小写的,所以下面的两个文档是与上面不同的:

{sex:“nan”,“name”:“mengxiangyue”}  

{“Name”:“mengxiangyue”,“sex”:“nan”}

另外,对于文档的字段 MongoDB 有如下的限制:

_id必须存在,如果你插入的文档中没有该字段,那么 MongoDB 会为该文档创建一个ObjectId作为其值。_id的值必须在本集合中是唯一的。

多个文档则组合为一个“集合”。在 MongoDB 中的集合是无模式的,也就是说集合中存储的文档的结构可以是不同的,比如下面的两个文档可以同时存入到一个集合中:

{“name”:“mengxiangyue”}  

{“Name”:“mengxiangyue”,“sex”:“nan”}

1.2 性能

MongoDB 目前支持的存储引擎为内存映射引擎。当 MongoDB 启动的时候,会将所有的数据文件映射到内存中,然后操作系统会托管所有的磁盘操作。这种存储引擎有以下几种特点:

* MongoDB 中关于内存管理的代码非常精简,毕竟相关的工作已经有操作系统进行托管。

* MongoDB 服务器使用的虚拟内存将非常巨大,并将超过整个数据文件的大小。不用担心,操作系统会去处理这一切。

在《Mongodb亿级数据量的性能测试》一文中,MongoDB 展现了强劲的大数据处理性能(数据甚至比Redis的漂亮的多)。

另外,MongoDB 提供了全索引支持:包括文档内嵌对象及数组。Mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。通常能够极大的提高查询的效率。

1.3 持久化

MongoDB 在1.8版本之后开始支持 journal,就是我们常说的 redo log,用于故障恢复和持久化。

当系统启动时,MongoDB 会将数据文件映射到一块内存区域,称之为Shared view,在不开启 journal 的系统中,数据直接写入shared view,然后返回,系统每60s刷新这块内存到磁盘,这样,如果断电或down机,就会丢失很多内存中未持久化的数据。

当系统开启了 journal 功能,系统会再映射一块内存区域供 journal 使用,称之为 private view,MongoDB 默认每100ms刷新 privateView 到 journal,也就是说,断电或宕机,有可能丢失这100ms数据,一般都是可以忍受的,如果不能忍受,那就用程序写log吧(但开启journal后使用的虚拟内存是之前的两倍)。

1.4 CAP类别

MongoDB 比较灵活,可以设置成 strong consistent (CP类型)或者 eventual consistent(AP类型)。

但其默认是 CP 类型。

2. Node下的使用

MongoDB 在 node 环境下的驱动引擎是 node-mongodb-native ,作为依赖封装到 mongodb 包里,我们直接安装即可:

npm install mongodb

实例:

var mongodb = require(‘mongodb’);

 

var mongodbServer = new mongodb.Server(‘localhost’, 27017, { auto_reconnect: true, poolSize: 10 });

var db = new mongodb.Db(‘mydb’, mongodbServer);

 

/* open db */

db.open(function() {

    /* Select ‘contact’ collection */

    db.collection(‘contact’, function(err, collection) {

        /* Insert a data */

        collection.insert({

            name: ‘Fred Chien’,

            email: ‘cfsghost@gmail.com’,

            tel: [

                ‘0926xxx5xx’,

                ‘0912xx11xx’

            ]

        }, function(err, data) {

            if (data) {

                console.log(‘Successfully Insert’);

            } else {

                console.log(‘Failed to Insert’);

            }

        });

 

        /* Querying */

        collection.find({ name: ‘Fred Chien’ }, function(err, data) {

            /* Found this People */

            if (data) {

                console.log(‘Name: ‘ + data.name + ‘, email: ‘ + data.email);

            } else {

                console.log(‘Cannot found’);

            }

        });

    });

});

另外我们也可以使用MongoDB的ODM(面向对象数据库管理器) —— mongoose 来做数据库管理,具体参照其API文档。

3. 优缺点

优势

1. 强大的自动化 shading 功能;

2. 全索引支持,查询非常高效;

3. 面向文档(BSON)存储,数据模式简单而强大。

4. 支持动态查询,查询指令也使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。

5. 支持 javascript 表达式查询,可在服务器端执行任意的 javascript函数。

缺点

1. 单个文档大小限制为16M,32位系统上,不支持大于2.5G的数据;

2. 对内存要求比较大,至少要保证热数据(索引,数据及系统其它开销)都能装进内存;

3. 非事务机制,无法保证事件的原子性。
适用场景

1. 适用于实时的插入、更新与查询的需求,并具备应用程序实时数据存储所需的复制及高度伸缩性;

2. 非常适合文档化格式的存储及查询;

3. 高伸缩性的场景:MongoDB 非常适合由数十或者数百台服务器组成的数据库。

4. 对性能的关注超过对功能的要求。

Couchbase 

本文之所以没有介绍 CouchDB 或 Membase,是因为它们合并了。合并之后的公司基于 Membase 与 CouchDB 开发了一款新产品,新产品的名字叫做 Couchbase。

Couchbase 可以说是集合众家之长,目前应该是最先进的Cache系统,其开发语言是 C/C++。

Couchbase Server 是个面向文档的数据库(其所用的技术来自于Apache CouchDB项目),能够实现水平伸缩,并且对于数据的读写来说都能提供低延迟的访问(这要归功于Membase技术)。

1.特点

1.1 数据格式

Couchbase 跟 MongoDB 一样都是面向文档的数据库,不过在往 Couchbase 插入数据前,需要先建立 bucket —— 可以把它理解为“库”或“表”。

因为 Couchbase 数据基于 Bucket 而导致缺乏表结构的逻辑,故如果需要查询数据,得先建立 view(跟RDBMS的视图不同,view是将数据转换为特定格式结构的数据形式如JSON)来执行。

Bucket的意义 —— 在于将数据进行分隔,比如:任何 view 就是基于一个 Bucket 的,仅对 Bucket 内的数据进行处理。一个server上可以有多个Bucket,每个Bucket的存储类型、内容占用、数据复制数量等,都需要分别指定。从这个意义上看,每个Bucket都相当于一个独立的实例。在集群状态下,我们需要对server进行集群设置,Bucket只侧重数据的保管。

每当views建立时, 就会建立indexes, index的更新和以往的数据库索引更新区别很大。 比如现在有1W数据,更新了200条,索引只需要更新200条,而不需要更新所有数据,map/reduce功能基于index的懒更新行为,大大得益。

要留意的是,对于所有文件,couchbase 都会建立一个额外的 56byte 的 metadata,这个 metadata 功能之一就是表明数据状态,是否活动在内存中。同时文件的 key 也作为标识符和 metadata 一起长期活动在内存中。

1.2 性能

couchbase 的精髓就在于依赖内存最大化降低硬盘I/O对吞吐量的负面影响,所以其读写速度非常快,可以达到亚毫秒级的响应。

couchbase在对数据进行增删时会先体现在内存中,而不会立刻体现在硬盘上,从内存的修改到硬盘的修改这一步骤是由 couchbase 自动完成,等待执行的硬盘操作会以write queue的形式排队等待执行,也正是通过这个方法,硬盘的I/O效率在 write queue 满之前是不会影响 couchbase 的吞吐效率的。

鉴于内存资源肯定远远少于硬盘资源,所以如果数据量小,那么全部数据都放在内存上自然是最优选择,这时候couchbase的效率也是异常高。

但是数据量大的时候过多的数据就会被放在硬盘之中。当然,最终所有数据都会写入硬盘,不过有些频繁使用的数据提前放在内存中自然会提高效率。

1.3 持久化

其前身之一 memcached 是完全不支持持久化的,而 Couchbase 添加了对异步持久化的支持:

Couchbase提供两种核心类型的buckets —— Couchbase 类型和 Memcached 类型。其中 Couchbase 类型提供了高可用和动态重配置的分布式数据存储,提供持久化存储和复制服务。

Couchbase bucket 具有持久性 —— 数据单元异步从内存写往磁盘,防范服务重启或较小的故障发生时数据丢失。持久性属性是在 bucket 级设置的。

1.4 CAP类型

Couchbase 群集所有点都是对等的,只是在创建群或者加入集群时需要指定一个主节点,一旦结点成功加入集群,所有的结点对等。

对等网的优点是,集群中的任何节点失效,集群对外提供服务完全不会中断,只是集群的容量受影响。

由于 couchbase 是对等网集群,所有的节点都可以同时对客户端提供服务,这就需要有方法把集群的节点信息暴露给客户端,couchbase 提供了一套机制,客户端可以获取所有节点的状态以及节点的变动,由客户端根据集群的当前状态计算 key 所在的位置。

就上述的介绍,Couchbase 明显属于 CP 类型。

2. Node下的使用

Couchbase 对 Node SDK 提供了官方文档:http://docs.couchbase.com/couchbase-sdk-node-1.2/index.html

实例:

var couchbase = require(“couchbase”);

 

var bucket = new couchbase.Connection({

  ‘bucket’:‘beer-sample’,

  ‘host’:‘127.0.0.1:8091’

}, function(err) {

  if (err) {

    // Failed to make a connection to the Couchbase cluster.

    throw err;

  }

 

  // 获取文档

  bucket.get(‘aass_brewery-juleol’, function(err, result) {

    if (err) {

      // Failed to retrieve key

      throw err;

    }

 

    var doc = result.value;

 

    console.log(doc.name + ‘, ABV: ‘ + doc.abv);

 

    doc.comment = “Random beer from Norway”;

 

    bucket.replace(‘aass_brewery-juleol’, doc, function(err, result) {

      if (err) {

        // Failed to replace key

        throw err;

      }

 

      console.log(result);

 

      // Success!

      process.exit(0);

    });

  });

});

3. 优缺点

优势

1. 高并发性,高灵活性,高拓展性,容错性好;

2. 以 vBucket 的概念实现更理想化的自动分片以及动态扩容;

缺点

1. Couchbase 的存储方式为 Key/Value,但 Value 的类型很为单一,不支持数组。另外也不会自动创建doc id,需要为每一文档指定一个用于存储的 Document Indentifer;

2. 各种组件拼接而成,都是c++实现,导致复杂度过高,遇到奇怪的性能问题排查比较困难,(中文)文档比较欠缺;

3. 采用缓存全部key的策略,需要大量内存。节点宕机时 failover 过程有不可用时间,并且有部分数据丢失的可能,在高负载系统上有假死现象;

4. 逐渐倾向于闭源,社区版本(免费,但不提供官方维护升级)和商业版本之间差距比较大。

适用场景

1. 适合对读写速度要求较高,但服务器负荷和内存花销可遇见的需求;

2. 需要支持 memcached 协议的需求。

LevelDB 

LevelDB 是由谷歌重量级工程师(Jeff Dean 和 Sanjay Ghemawat)开发的开源项目,它是能处理十亿级别规模 key-value 型数据持久性存储的程序库,开发语言是C++。

除了持久性存储,LevelDB 还有一个特点是 —— 写性能远高于读性能(当然读性能也不差)。

1.特点

LevelDB 作为存储系统,数据记录的存储介质包括内存以及磁盘文件,当LevelDB运行了一段时间,此时我们给LevelDb进行透视拍照,那么您会看到如下一番景象:

LevelDB 所写入的数据会先插入到内存的 Mem Table 中,再由 Mem Table 合并到只读且键值有序的 Disk Table(SSTable) 中,再由后台线程不时的对 Disk Table 进行归并。

内存中存在两个 Mem Table —— 一个是可以往里面写数据的table A,另一个是正在合并到硬盘的 table B。

Mem Table 用 skiplist 实现,写数据时,先写日志(.log),再往A插入,因为一次写入操作只涉及一次磁盘顺序写和一次内存写入,所以这是为何说LevelDb写入速度极快的主要原因。如果当B还没完成合并,而A已经写满时,写操作必须等待。

DiskTable(SSTable,格式为.sst)是分层的(leveldb的名称起源),每一个大小不超过2M。最先 dump 到硬盘的 SSTable 的层级为0,层级为0的 SSTable 的键值范围可能有重叠。如果这样的 SSTable 太多,那么每次都需要从多个 SSTable 读取数据,所以LevelDB 会在适当的时候对 SSTable 进行 Compaction,使得新生成的 SSTable 的键值范围互不重叠。

进行对层级为 level 的 SSTable 做 Compaction 的时候,取出层级为 level+1 的且键值空间与之重叠的 Table,以顺序扫描的方式进行合并。level 为0的 SSTable 做 Compaction 有些特殊:会取出 level 0 所有重叠的Table与下一层做 Compaction,这样做保证了对于大于0的层级,每一层里 SSTable 的键值空间是互不重叠的。

SSTable 中的某个文件属于特定层级,而且其存储的记录是 key 有序的,那么必然有文件中的最小 key 和最大 key,这是非常重要的信息,LevelDB 应该记下这些信息 —— Manifest 就是干这个的,它记载了 SSTable 各个文件的管理信息,比如属于哪个Level,文件名称叫啥,最小 key 和最大 key 各自是多少。下图是 Manifest 所存储内容的示意:

图中只显示了两个文件(Manifest 会记载所有 SSTable 文件的这些信息),即 Level0 的 Test1.sst 和 Test2.sst 文件,同时记载了这些文件各自对应的 key 范围,比如 Test1.sstt 的 key 范围是“an”到 “banana”,而文件 Test2.sst 的 key 范围是“baby”到“samecity”,可以看出两者的 key 范围是有重叠的。

那么上方图1中的 Current 文件是干什么的呢?这个文件的内容只有一个信息,就是记载当前的 Manifest 文件名。因为在 LevleDB 的运行过程中,随着 Compaction 的进行,SSTable 文件会发生变化,会有新的文件产生,老的文件被废弃,Manifest 也会跟着反映这种变化,此时往往会新生成 Manifest 文件来记载这种变化,而 Current 则用来指出哪个 Manifest 文件才是我们关心的那个 Manifest 文件。

注意,鉴于 LevelDB 不属于分布式数据库,故CAP法则在此处不适用。

2. Node下的使用

Node 下可以使用 LevelUP 来操作 LevelDB 数据库:

var levelup = require(‘levelup’)

 

// 1) Create our database, supply location and options.

//    This will create or open the underlying LevelDB store.

var db = levelup(‘./mydb’)

 

// 2) put a key & value

db.put(‘name’, ‘LevelUP’, function (err) {

  if (err) return console.log(‘Ooops!’, err) // some kind of I/O error

 

  // 3) fetch by key

  db.get(‘name’, function (err, value) {

    if (err) return console.log(‘Ooops!’, err) // likely the key was not found

 

    // ta da!

    console.log(‘name=’ + value)

  })

})

LevelUp 的API非常简洁实用,具体可参考官方文档。

3. 优缺点

优势

1. 操作接口简单,基本操作包括写记录,读记录和删除记录,也支持针对多条操作的原子批量操作;

2. 写入性能远强于读取性能,

3. 数据量增大后,读写性能下降趋平缓。

缺点

1. 随机读性能一般;

2. 对分布式事务的支持还不成熟。而且机器资源浪费率高。

适应场景

适用于对写入需求远大于读取需求的场景(大部分场景其实都是这样)。

java在处理大数据的时候一些小技巧

来源: xieyu_zy

链接:http://blog.csdn.net/xieyuooo/article/details/7721315

众所周知,Java在处理数据量比较大的时候,加载到内存必然会导致内存溢出,而在一些数据处理中我们不得不去处理海量数据,在做数据处理中,我们常见的手段是分解,压缩,并行,临时文件等方法;

例如,我们要将数据库(不论是什么数据库)的数据导出到一个文件,一般是Excel或文本格式的CSV;对于Excel来讲,对于POI和JXL的接口,你很多时候没有办法去控制内存什么时候向磁盘写入,很恶心,而且这些API在内存构造的对象大小将比数据原有的大小要大很多倍数,所以你不得不去拆分Excel,还好,POI开始意识到这个问题,在3.8.4的版本后,开始提供cache的行数,提供了SXSSFWorkbook的接口,可以设置在内存中的行数,不过可惜的是,他当你超过这个行数,每添加一行,它就将相对行数前面的一行写入磁盘(如你设置2000行的话,当你写第20001行的时候,他会将第一行写入磁盘),其实这个时候他些的临时文件,以至于不消耗内存,不过这样你会发现,刷磁盘的频率会非常高,我们的确不想这样,因为我们想让他达到一个范围一次性将数据刷如磁盘,比如一次刷1M之类的做法,可惜现在还没有这种API,很痛苦,我自己做过测试,通过写小的Excel比使用目前提供刷磁盘的API来写大文件,效率要高一些,而且这样如果访问的人稍微多一些磁盘IO可能会扛不住,因为IO资源是非常有限的,所以还是拆文件才是上策;而当我们写CSV,也就是文本类型的文件,我们很多时候是可以自己控制的,不过你不要用CSV自己提供的API,也是不太可控的,CSV本身就是文本文件,你按照文本格式写入即可被CSV识别出来;如何写入呢?下面来说说。。。

在处理数据层面,如从数据库中读取数据,生成本地文件,写代码为了方便,我们未必要1M怎么来处理,这个交给底层的驱动程序去拆分,对于我们的程序来讲我们认为它是连续写即可;我们比如想将一个1000W数据的数据库表,导出到文件;此时,你要么进行分页,oracle当然用三层包装即可,MySQL用limit,不过分页每次都会新的查询,而且随着翻页,会越来越慢,其实我们想拿到一个句柄,然后向下游动,编译一部分数据(如10000行)将写文件一次(写文件细节不多说了,这个是最基本的),需要注意的时候每次buffer的数据,在用outputstream写入的时候,最好flush一下,将缓冲区清空下;接下来,执行一个没有where条件的SQL,会不会将内存撑爆?是的,这个问题我们值得去思考下,通过API发现可以对SQL进行一些操作,例如,通过:

PreparedStatement statement = connection.prepareStatement(sql),

这是默认得到的预编译,还可以通过设置:

PreparedStatement statement = connection.prepareStatement(sql , ResultSet.TYPE_FORWARD_ONLY , ResultSet.CONCUR_READ_ONLY);

来设置游标的方式,以至于游标不是将数据直接cache到本地内存,然后通过设置statement.setFetchSize(200);设置游标每次遍历的大小;OK,这个其实我用过,oracle用了和没用没区别,因为oracle的jdbc API默认就是不会将数据cache到java的内存中的,而mysql里头设置根本无效,我上面说了一堆废话,呵呵,我只是想说,java提供的标准API也未必有效,很多时候要看厂商的实现机制,还有这个设置是很多网上说有效的,但是这纯属抄袭;对于oracle上面说了不用关心,他本身就不是cache到内存,所以java内存不会导致什么问题,如果是mysql,首先必须使用5以上的版本,然后在连接参数上加上useCursorFetch=true这个参数,至于游标大小可以通过连接参数上加上:defaultFetchSize=1000来设置,例如:

jdbc:mysql://xxx.xxx.xxx.xxx:3306/abc?zeroDateTimeBehavior=convertToNull&useCursorFetch=true&defaultFetchSize=1000

上次被这个问题纠结了很久(mysql的数据老导致程序内存膨胀,并行2个直接系统就宕了),还去看了很多源码才发现奇迹竟然在这里,最后经过mysql文档的确认,然后进行测试,并行多个,而且数据量都是500W以上的,都不会导致内存膨胀,GC一切正常,这个问题终于完结了。

我们再聊聊其他的,数据拆分和合并,当数据文件多的时候我们想合并,当文件太大想要拆分,合并和拆分的过程也会遇到类似的问题,还好,这个在我们可控制的范围内,如果文件中的数据最终是可以组织的,那么在拆分和合并的时候,此时就不要按照数据逻辑行数来做了,因为行数最终你需要解释数据本身来判定,但是只是做拆分是没有必要的,你需要的是做二进制处理,在这个二进制处理过程,你要注意了,和平时read文件不要使用一样的方式,平时大多对一个文件读取只是用一次read操作,如果对于大文件内存肯定直接挂掉了,不用多说,你此时因该每次读取一个可控范围的数据,read方法提供了重载的offset和length的范围,这个在循环过程中自己可以计算出来,写入大文件和上面一样,不要读取到一定程序就要通过写入流flush到磁盘;其实对于小数据量的处理在现代的NIO技术的中也有用到,例如多个终端同时请求一个大文件下载,例如视频下载吧,在常规的情况下,如果用java的容器来处理,一般会发生两种情况:

  • 其一为内存溢出,因为每个请求都要加载一个文件大小的内存甚至于更多,因为java包装的时候会产生很多其他的内存开销,如果使用二进制会产生得少一些,而且在经过输入输出流的过程中还会经历几次内存拷贝,当然如果有你类似nginx之类的中间件,那么你可以通过send_file模式发送出去,但是如果你要用程序来处理的时候,内存除非你足够大,但是java内存再大也会有GC的时候,如果你内存真的很大,GC的时候死定了,当然这个地方也可以考虑自己通过直接内存的调用和释放来实现,不过要求剩余的物理内存也足够大才行,那么足够大是多大呢?这个不好说,要看文件本身的大小和访问的频率;
  • 其二为假如内存足够大,无限制大,那么此时的限制就是线程,传统的IO模型是线程是一个请求一个线程,这个线程从主线程从线程池中分配后,就开始工作,经过你的Context包装、Filter、拦截器、业务代码各个层次和业务逻辑、访问数据库、访问文件、渲染结果等等,其实整个过程线程都是被挂住的,所以这部分资源非常有限,而且如果是大文件操作是属于IO密集型的操作,大量的CPU时间是空余的,方法最直接当然是增加线程数来控制,当然内存足够大也有足够的空间来申请线程池,不过一般来讲一个进程的线程池一般会受到限制也不建议太多的,而在有限的系统资源下,要提高性能,我们开始有了new IO技术,也就是NIO技术,新版的里面又有了AIO技术,NIO只能算是异步IO,但是在中间读写过程仍然是阻塞的(也就是在真正的读写过程,但是不会去关心中途的响应),还未做到真正的异步IO,在监听connect的时候他是不需要很多线程参与的,有单独的线程去处理,连接也又传统的socket变成了selector,对于不需要进行数据处理的是无需分配线程处理的;而AIO通过了一种所谓的回调注册来完成,当然还需要OS的支持,当会掉的时候会去分配线程,目前还不是很成熟,性能最多和NIO吃平,不过随着技术发展,AIO必然会超越NIO,目前谷歌V8虚拟机引擎所驱动的node.js就是类似的模式,有关这种技术不是本文的说明重点;

将上面两者结合起来就是要解决大文件,还要并行度,最土的方法是将文件每次请求的大小降低到一定程度,如8K(这个大小是经过测试后网络传输较为适宜的大小,本地读取文件并不需要这么小),如果再做深入一些,可以做一定程度的cache,将多个请求的一样的文件,cache在内存或分布式缓存中,你不用将整个文件cache在内存中,将近期使用的cache几秒左右即可,或你可以采用一些热点的算法来配合;类似迅雷下载的断点传送中(不过迅雷的网络协议不太一样),它在处理下载数据的时候未必是连续的,只要最终能合并即可,在服务器端可以反过来,谁正好需要这块的数据,就给它就可以;才用NIO后,可以支持很大的连接和并发,本地通过NIO做socket连接测试,100个终端同时请求一个线程的服务器,正常的WEB应用是第一个文件没有发送完成,第二个请求要么等待,要么超时,要么直接拒绝得不到连接,改成NIO后此时100个请求都能连接上服务器端,服务端只需要1个线程来处理数据就可以,将很多数据传递给这些连接请求资源,每次读取一部分数据传递出去,不过可以计算的是,在总体长连接传输过程中总体效率并不会提升,只是相对相应和所开销的内存得到量化控制,这就是技术的魅力,也许不要太多的算法,不过你得懂他。

类似的数据处理还有很多,有些时候还会将就效率问题,比如在HBase的文件拆分和合并过程中,要不影响线上业务是比较难的事情,很多问题值得我们去研究场景,因为不同的场景有不同的方法去解决,但是大同小异,明白思想和方法,明白内存和体系架构,明白你所面临的是沈阳的场景,只是细节上改变可以带来惊人的效果。

How to Learn JavaScript Properly

Source: http://javascriptissexy.com/how-to-learn-JavaScript-properly/

Learn JavaScript Properly (For Beginners and Experienced Programmers)

This study guide, which I also refer to as a course outline and a road map, gives you a structured and instructive outline for learning JavaScript properly. In fact, you will find two study guides below, one for absolute beginners and the other for experienced programmers and web developers.

Our Career Paths and Courses Website Is Now Live

Learn.Modern Developer Launched

Our first cohort is in session: 97% of our first cohort on target to graduate. Enroll in the second cohort. Career Path 1: JavaScript Developer and Career Path 3: Modern Frontend Developer usually fill up quickly.

https://learn.moderndeveloper.com

You do want to learn JavaScript. I presume you are here for that reason, and you have made a wise decision. For if you want to develop modern websites and web applications (including an internet startup), or if you want a high-paying developer job ($75K to $250K+), JavaScript is undoubtedly the best web-development language to learn today, unless you want to develop native iOS or Android apps exclusively. And while there exist ample online resources to teach you JavaScript, finding the most efficient and beneficial method to learn the “language of the web” can be a frustrating endeavor. This study guide streamlines and simplifies the process; it has proven successful in helping thousands, and thousands more read and follow it each day.

Study Groups
People have started study groups for this study guide. You can find such groups on Reddit here and here, and other places, including Code Crew Meetup.

What You will Learn

You will learn the JavaScript language (up to advanced-intermediate, if you follow the “Beginners” study guide; or up to advanced, if you follow the “Experienced Programmers” study guide). You will also learn HTML, CSS, jQuery, and Git. And you will build a simple HTML/CSS website, an interactive HTML/CSS/JavaScript website, and a moderately sophisticated JavaScript quiz application.

  • Receive Updates

How Will Your Life Change After You Learn JavaScript Properly?

Maybe you will look more lovely and have a kinder, more pleasant personality after you learn JavaScript properly. Who knows? I don’t know.

But I do know that you will emerge more confident, more assured in your ability, and amply trained with a highly valued skill—a skill more valuable than most college degrees. For as a JavaScript developer, you will have the capacity not only to create whatever startup or web app you imagine, but also to work, making a handsome salary, as a front-end or full-stack developer, developing modern and futuristic applications. In fact, if you have never developed any kind of application before, you will experience ecstasy, so exultant and euphoric that you will want to enthusiastically practice more and build something—anything, like a hungry chef discovering a furnished kitchen with every tool, every utensil, and a stocked refrigerator.

It is worth noting that unlike just a couple of years ago—when you needed to know a true server-side language (such as PHP, Rails, Java, Python, or Perl) to develop scalable, dynamic, and database-driven web applications—today you can do as much and more with JavaScript alone.

This is the flourishing and glorious age of the JavaScript developer.

Be Empowered

This course outline transcends an entire semester of college coursework. If you complete the study guide, you will have learned enough programming to develop modern web applications, and with a bit of experience and a couple of completed projects, you will have become a sought-after programmer. Indeed, JavaScript developers are in high demand today. But you must prove your worth by developing a few impressive (interesting and non-trivial, though not necessarily complex) web applications.

How NOT To Learn JavaScript

  • Do not try to learn JavaScript the first time from bits of unrelated or related JavaScript tutorials online; this is the worst way to learn a programming language. It could work for some after countless such tutorials, but it is an inefficient process that lacks the proper hierarchical structure needed for learning a subject matter thoroughly. And this could lead to your being stuck quite frequently, when you start to build websites and web applications with the language. In short, you will not have the know-how—the comprehensive knowledge—you need to use that language as a tool—as your tool.
  • In addition, some will recommend you learn JavaScript from “JavaScript: The Good Parts,” by the venerable Douglas Crockford. While many regard Mr. Crockford as a JavaScript godfather, his book, The Good Parts, is not the best JavaScript book for beginners. It does not explain JavaScript’s core concepts in a detailed, clear, and easily digestible form. I do recommend you follow Crockford’s advanced videos, however, as part of the Learn Advanced JavaScript road map.
  • And do not try to learn the language by using only Codecademy; while you will learn how to program bits of small JavaScript tasks, you will not have learned enough to build complex web applications. Nonetheless, below I do recommend Codecademy as a supplemental learning resource.

Resources for the Two Study Guides

I have outlined two different study guides below, one for beginners and one for experienced web developers.

  1. Beginners should follow the Learn JavaScript Properly Study Guide for Beginners and get this book:
    Beginning JavaScript.Experienced programmers and web developers should follow the Learn JavaScript Properly Study Guide for Experienced Programmers and get this book:
    — The paperback Version: Professional JavaScript for Web Developers (3rd Edition)
    — The Kindle Version: Professional JavaScript for Web Developers (3rd Edition)
  2. Sign up for an account on Stack Overflow (a FREE service). It is a forum for asking and answering programming questions. This website will be considerably more useful than Codecademy for answering your programming questions, even very basic, seemingly stupid (remember, there is never a stupid question) questions.
  3. Sign up for an account on Codecademy. We will complete 4 Codecademy tracks. Codecademy is an online platform to learn programming: you can write code on their website, right in your browser. (It is also a FREE service.)
  4. JavaScriptIsSexy.com (this blog :) ): We will read 4 articles
  5. CodeSchool.com: We will complete 1 free course

Resources:
Beginning JavaScript (4th Edition)
— JavaScriptIsSexy.com (4 articles)
— Codecademy.com (4 tracks)
— CodeSchool.com (1 short course)
Notice for Visual Learners: If you are a visual learner, that is, if you prefer to see lots of images, schematics, and the like when learning a topic, you may find JavaScript and jQuery: Interactive Front-End Web Development more appealing than the Beginning JavaScript book. If you do get the JavaScript and jQuery book, note that the chapters are similar enough that you can use it (instead of Beginning JavaScript) to follow this study guide, though you will have to modify the sections a bit.

Learn JavaScript Properly Study Guide for Beginners

Prerequisite: Completed at least some high school (no programming experience necessary)

The Level of JavaScript Covered in this Study Guide: Absolute Beginner to Intermediate

How to Get the Best Out of This Study Guide

Type out and test every example code you encounter in the book. You can type the code and tweak it (experiment with it) in Firefox’s or Chrome’s console. The browser console is an area of the browser where you can write and run JavaScript code. Or use JSFiddle. JSFiddle is a web application that allows you to write and test your code online, right in your browser. You can test all sorts of code, including a combination of HTML, CSS, and JavaScript (and jQuery).

Don’t use Safari. I recommend Chrome, but if you use Firefox, get the Firebug Add on for Firefox; use it for testing and debugging your code.

Watch this Firefox’s and Chrome’s Console Tutorial on YouTube.

And watch this Chrome Dev Tools Tutorial (also on YouTube) to learn how to use Chrome Dev Tools.

Also, work all the end-of-chapter exercises.

Let’s get to work.

Weeks 1 and 2

Week 1: Making a Website with HTML and CSS; Learn JavaScript Data Types, Functions, Control Flow, and Loops

  1. Codecademy.com: If you do not already know HTML and CSS, complete the Web Fundamentals Track on Codecademy.
  2. Codecademy.com: Then follow the Make a Website track to make your first little website, using what you learned above.
  3. Beginning JavaScript: Read Chapter 1 (Introduction to JavaScript and the Web) and Chapter 2 (Data Types and Variables).
  4. Beginning JavaScript: Read Chapter 3 (Decisions, Loops, and Functions).
  5. Codecademy.com: Work through the JavaScript Track on Codecademy. Specifically, work through these sections: “Introduction to JavaScript,” “Functions,” “‘For’ Loops in JavaScript,” “‘While’ Loops in JavaScript,” and “Control Flow.”
  6. Beginning JavaScript: Read Chapter 4 (Common Mistakes, Debugging, and Error Handling).

Week 2: Learn JavaScript Objects, the Browser Object Model (BOM), and Events; Learn jQuery

  1. Beginning JavaScript: Read Chapter 5 (JavaScript — An Object- Based Language).
  2. JavaScriptIsSexy.com: Read my article, JavaScript Objects in Detail
  3. Codecademy.com: Work through the last three sections of the Codecademy JavaScript track: “Data Structures,” “Objects 1,” and “Objects 2.”
  4. Beginning JavaScript: Read Chapter 6 (Programming the Browser).
  5. Beginning JavaScript: Read Chapter 15 (JavaScript Frameworks), and stop just after you complete this section: “Digging Deeper Into jQuery”.
  6. Codecademy.com: Work through the entire jQuery Track on Codecademy.

Weeks 3 and 4

Week 3: HTML Forms and Frames; JavaScript Strings; Build Your First Interactive Website

  1. Beginning JavaScript: Read Chapter 7 (HTML Forms: Interacting with the User).
  2. Beginning JavaScript: Read Chapter 8 (Windows and Frames).
  3. Beginning JavaScript: Read Chapter 9 (String Manipulation).
  4. Codecademy.com: Now, make your first cool website. Work through the entire Make an Interactive Website track on Codecademy.

Week 4: JavaScript Date, Timers, and Cookies

  1. Beginning JavaScript: Read Chapter 10 (Date, Time, and Timers).
  2. Beginning JavaScript: Read Chapter 11 (Storing Information: Cookies).

Weeks 5 and 6

Week 5: JavaScript “this,” Variable Scope, and Hoisting, the DOM, JavaScript XML, and AJAX

  1. JavaScriptIsSexy.com: Read my post JavaScript Variable Scope and Hoisting Explained
  2. JavaScriptIsSexy.com: Read my post Understand JavaScript’s “this” With Clarity, and Master It
  3. Beginning JavaScript: Read Chapter 12 (Dynamic HTML and the W3C Document Object Model).
  4. Beginning JavaScript: Read Chapter 14 (Ajax).

Week 6: Build a Real-World JavaScript Quiz Application

At this juncture, you have learned enough to build a solid JavaScript web application. Don’t proceed any further until you can successfully build this application I describe below. Don’t be afraid to ask questions on Stack Overflow, and do reread sections of the book to properly understand the concepts.

You are building a JavaScript quiz web application (you will use HTML and CSS as well) that will function as follows:

  • It is a simple quiz that has radio button choices, and it will show the quiz taker his or her score upon completion.
  • The quiz can show any number of questions and any number of choices.
  • Tally the user’s score and display the final score on the last page. The last page will only show the score, so remove the last question.
  • Use an array to store all the questions. Each question, along with its choices and correct answer, should be stored in an object. The array of questions should look similar to this (Notice that only one question is in this example array; you will add many questions):
    var allQuestions = [{question: “Who is Prime Minister of the United Kingdom?”, choices: [“David Cameron”, “Gordon Brown”, “Winston Churchill”, “Tony Blair”], correctAnswer:0}];
  • Dynamically (with document.getElementById or jQuery) remove the current question and add the next question, when the user clicks the “Next” button. The Next button will be the only button to navigate this version of the quiz.
  • You can ask for help in the comments below or preferably on Stack Overflow. You will likely to get a prompt and accurate answer on Stack Overflow.

Improve Your Quiz

You should be very comfortable with JavaScript, probably feeling like a Jedi. No, you are not. Not yet. You must keep using your newly acquired knowledge and skills as often as possible to keep learning and improving.

Improve Your Quiz Application From Earlier:

  • Add client-side data validation: make sure the user answers each question before proceeding to the next question.
  • Add a “Back” button to allow the user to go back and change her answer. The user can go back up to the first question. For the questions that the user has answered already, be sure to show the radio button selected, so that the user is not forced to answer the questions again, which she has completed.
  • Use jQuery to add animation (fade out the current question and fade in the next question).
  • Test the quiz on IE 9, and fix any bugs. This will give you a good workout 😉
  • Store the quiz questions in an external JSON file.
  • Add user authentication: allow users to log in, and save their login credentials to local storage (HTML5 browser storage).
  • Use cookies to remember the user, and show a “Welcome, ‘First Name’” message when the user returns to the quiz.

Week 7 (Extra Credit)

Getting Started with Git; Objective Oriented JavaScript; Improve Your Quiz Even More

  1. CodeSchool.com: Take the FREE Try Git course.
  2. JavaScriptIsSexy.com: Read my post, OOP In JavaScript: What You NEED to Know.
  3. Improve Your Quiz Application Even Further:
    — Use Twitter Bootstrap for the entire page layout, including the quiz elements to make it look more polished. As an added bonus, use the tabs user interface component from Twitter Bootstrap and show 4 different quizzes, one on each tab.
    Learn Handlebars.js and add Handlebars.js templating to the quiz. You should no longer have any HTML in your JavaScript code. Your quiz is getting more advanced, bit by bit.
    — Keep a record of all the users who take the quiz and show each user how his or her score ranks among the scores from other quiz takers.
  4. Later (after you have learned Backbone.js and Node.js or Meteor.js), you can use these technologies to refactor your quiz code and turn the same quiz into a sophisticated, single-page, modern web application built with the latest JavaScript frameworks. And you will store the users’ authentication credentials and scores in a MongoDB database.
  5. Next: Decide on a personal project to build, and start building your project promptly (while everything remains fresh in your memory). Use the book as a reference. And of course be an active member on Stack Overflow: ask questions and answer other programmers’ questions. I am confident you will be able to answer a number of questions.

Continue Improving

    1. Learn Backbone.js Completely, if you want to be a front-end developer or learn how to develop web applications with a JavaScript front-end framework.

Alternatively, if you want to develop complete applications, that is, the front-end and the backend, learn Meteor.js properly.

  1. At this point, you will definitely need my book, MongoDB for JavaScript Applications, to help you build your own jQuery, Backbone.js, Node.js, or Meteor.js applications, since none of the noted resources, or any other book for that matter, cover MongoDB in depth for JavaScript applications.
  2. Learn Intermediate and Advanced JavaScript
  3. Learn Node.js Completely and With Confidence

Words of Encouragement

I wish you success with your studies and in your JavaScript career. Never give up! When you are struggling and feeling incompetent (you may from time to time), always remember that most (probably all) programmers, new and experienced alike, feel this way sometimes, or have felt this way at some point during their programming career.

Remember to dig deep and don’t get frustrated; just carry on and stick with the task until you figure it out, for a worthwhile reward awaits you when you triumph in the end: programming is fun, liberating, and lucrative. The ecstasy one gets from building an application is a powerful feeling that you must experience to understand. Even more satisfying, however, is the empowerment you experience when you realize you have attained the skill and knowledge to build applications from scratch, to change the world with any idea you dream up.

The moment will come when you realize that all the difficulties you endured were worth while. Just as the millions before you have triumphed, so too, you will vanquish the toughest bugs, master the incomprehensible topics, and overcome the seemingly impossible tasks.

Feel free to share your links with us below when you build something, even if it is a tiny, itsy-bitsy project. :)

旧金山大学数据结构和算法的可视化学习工具

来源:伯乐在线 – 资源频道

链接:http://hao.jobbole.com/visualizing-algorithms-and-data-structure/

 

简介

理解复杂数据结构的最佳方法就是看它们的实际操作。旧金山大学计算机系的助理教授  David Galles  在 2011 年开发了一套用于学习数据结构和算法的交互工具。这个可视化工具是用 JavaScript 编写,用上了 HTML5 画布元素,兼容所有现代浏览器。iPhone 和 iPad 等 iOS 设备和 Kindle 上的浏览器都支持。

(编注:建议在非手机设备上使用,这个工具并不是自适应的,屏幕过小不利于操作和查看。)

 

如何使用

以链表队列为例,进入网页后,上方有一个操作按钮的工具栏。最左侧可输入队列元素,然后进行入队(Enqueue)和出队(Dequeue)操作。

下方是另外一个操作按钮的工具栏,用于设置动画参数等操作。

其他

这个工具的源码已公开,感兴趣的计算机课程教师,请参阅这个网页,然后可基于 David 的代码编写自己的教程动画。

官方网站:http://www.cs.usfca.edu/~galles/visualization/Algorithms.html

有图有案例!125个提升网页可用性的优化小技巧(三)

英文:nickkolenda

译者:企业官网设计精选

链接:http://www.uisdc.com/125-website-usability-optimize-3#

编者按:这个系列的教程有125个实用的网页优化技巧,每一个技巧都有案例阐述,保证简单易懂。今天企业官网设计精选 翻译了第三部分 —— 在网页设计中如何少让用户费脑筋,保持操作流畅。一起来收!

往期回顾:

  1. 《有图有案例!125个提升网页可用性的优化小技巧(一)》
  2. 《有图有对比!125个提升网页可用性的优化小技巧(二)》

除了引导用户,还要减少他们的认知流程,以保持流畅状态。

尽可能少让用户做计算

千万别把计算这种事情丢给用户,让计算机来处理。

△ 显示剩余数量

在界面内体现用户当前所处位置

界面就像机场,如果没有“你在这里”的标记,用户会迷路,因此记得提供标记。

△ 在导航菜单上突出当前所选

△ 在复杂的界面中提供面包屑导航或步骤图示

△ 在页面标题前面部分放置描述性或有用的信息

 

简化选择类任务

做选择需要费脑筋,简化这类任务让用户少费神

△ 指明多数用户选择的选项

△ 提供常见搜索关键词列表

△ 下拉分类菜单置于相应导航菜单内

 

使用常规的网页设计界面

创新很好,但不要跟常规的设计方式偏离太远。用户习惯于某些布局、结构。常规设计之所以流行,是因为他们确实可行。

△ 使用常规的导航菜单

△ 把实用功能放在右上角

 

每次交互动作后提供反馈

用户跟界面进行互动后,需获得实时反馈。操作成功还是失败了?发生了什么变化?

△ 重要的交互动作后反馈提示成功消息

△ 显示当前鼠标停留在哪个项目上

 

最小化等待的负面效果

消灭所有不必要的等待。如果确实要用户等,则最小化该负面效果。

△ 加载动画效果使用冷色调减少对用户刺激

蓝色减少刺激(提高放松程度),蓝色加载元素可让用户觉得加载更快(Gorn et al., 2004)。

△ 长时间等待时保持用户活跃度(别人他们干等)

△ 防止用户上传不支持的文件

△ 实时统计显示任务进展

 

尽可能减少用户对记忆的依赖

别让用户去记住任何东西,将相关信息显示出来

△ 让表单标签保持一直可见

△ 避免用户点击后就消失的行内标签

△ 占位文本放到表单元素的外边

△ 为可移动输入添加复制按钮△ (△ Add Copy Buttons to Movable Input△ )

 

尽量少用锯齿状视图模式

减少用户眼睛来回移动的次数,让各项补充数据保持接近。

△ 合并相同的数据字段帮助用户进行对比

△ 让表单标签紧贴相应元素并对齐

 

反馈显示哪些项目是可点击或交互的

用户需要识别哪些元素是可交互的(并且知道如何交互)。

△ 使用3D特性设计按钮

△ 为可拖拽元素添加点状纹理

△ 使用图标和符号传达一个交互动作的意图

你可以通过PowerPoint 或 Keynote的各种形状制作大部分图标

 

用常见的文字和符合来沟通

大多数情况下,清晰明确胜过创意和术语

△ 讲用户懂的语言,不讲程序语言

△ 出现外语时,提供翻译按钮

△ 颜色的选择要与语义保持一致

当颜色跟语义不一致时,会增加用户处理信息的困扰。如meetup.com上使用红色确认出席,准确应该是用绿色。

 

尽可能提高界面的可浏览性

多数用户采用浏览扫读的方式处理内容,我们需要接受这种行为。

设计界面时尽量适应这种泛读浏览方式。

△ 保持段落简短,高亮关键词组

△ 把重要信息放在列表的开头

△ 给表格添加交替的行条纹背景

△ 编写独立副标题(不要一篇文章就一个大标题)

△ 用视觉变化拆分文本

 

尽可能提高文本的可读性

很明显,文本需要让人易懂,有些技巧能让文本更具可读性。

△ 让文本和背景具有鲜明对比

背景上显示文本需要注意,可能需要做一些叠加或模糊处理。(以作者照片为例…)

△ 正文的主要部分采用左对齐

 

界面设计风格保持一致

风格不统一的话用户需要花更多时间学习界面。保持统一的布局和外观可以简化学习过程。

△ 制定一份前端风格指引

制定一份稳定,总结界面各元素的设计规格说明

其他元素包括:

  • 颜色
  • 网格和布局
  • 位置和定位
  • 大小和形状
  • 标签和语言
  • 导航
  • 表格
  • 列表
  • 链接
  • 声音和腔调

需要灵感参考?看看Mailchimp的风格指引(http://ux.mailchimp.com/patterns)

△ 导航菜单保持在相同位置

 

通过视觉平衡实现设计美感

美观的设计更加好用 – 即美即好用效应原则(Kurosu & Kashimura, 1995)。

△ 使用数学原理构造设计

△ 使用对比性字体

挑选搭配字体时,有人喜欢使用相似的字体,但这种方式是错的,很多时候相似的看上去并不对。

相反,应该精心挑选对比鲜明的字体,新手设计师可以选择serif vs sans-serif(英文字体),如上图

未完待续…

有图有对比!125个提升网页可用性的优化小技巧(二)

英文:nickkolenda

译者:企业官网设计精选

链接:http://www.uisdc.com/125-website-usability-optimize-2

这个系列的教程有125个实用的网页优化技巧,每一个技巧都有案例对比,保证简单易懂。今天翻译了第二部分 —— 在网页设计中帮助用户实现目标,一起来涨姿势!

第一期回顾:《有图有案例!125个提升网页可用性的优化小技巧(一)

让常用功能和重要数据信息更接近用户

预测用户的意图,让他们尽可能接近目标。

△ 筛选出或跳至用户正在搜索的条目

△ 将用户常选项目列为默认选项

△ 产品列表页上把重要数据信息展示出来

很多时候用户需要像踩弹簧高跷杖一样,点击一个产品,查看信息,返回上一页,再反复操作以查看其他产品。这种设计的可用性差。应把重要信息直接放在主要页面,减少用户反复操作的次数。

如果你怕这样页面会杂乱,也可以设计成鼠标悬停时显示(如下面这样)

△ 鼠标悬停时显示有用信息

△ 常用功能直接展示出来

△ 用仪表面板方式展现主要数据和状态

△ 把常见答案放在下拉列表的头部

交互状态的及时反馈呈现

通过传达所有相关信息减少不确定性。

△ 在机器驱动的任务中显示当前进度和剩余时间

如上传文件是系统在处理,用户不知道内部运作情况,通过显示进度条可以让用户知道进展。

△ 复杂或冗长的交互状态要及时反馈呈现

△ 按次序显示操作步骤总数

△ 显示类目下的条目数

同一任务,可为客户提供多种完成方式

用户喜欢的操作方式不一样。为同一目标提供不同路径,让用户选择最符合他们自己的方式。

△ 用户可通过用户名或电子邮件登录系统

△ 为重复操作类功能提供键盘快捷键

△ 让用户可以拖拽元素

△ 让用户直接编辑数据信息

反馈呈现交互动作的限制条件或参数要求

为每一个交互动作做好准备。用户需要什么?他们如何继续?

△ 描述清楚你需要用户输入什么

△ 实时显示密码要求并反馈输入状态

△ 为表单元素预填通用参数

△ 显示表单的必填和选填信息

反馈显示交互动作的预期结果

在用户进行交互操作之前,他们应该了解预期结果是什么

△ 使用描述性按钮标签

△ 根据当前的输入,显示结果预览

△ 按次序显示或预览下一个项目

△ 使用智能菜单项明确操作内容

当用户取得进展时,给予奖励或肯定

用户取得进展了吗?他们的交互成功了吗?让用户知道,同时引导他们继续。

△ 保证链接与目标页面的一致性

△ 为新加入用户提供速效指引环节(如迅速建立人脉)

△ 进度条从大于0%的地方开始

解决用户的核心需求

很多时候,我们只解决了用户的表层需求。深入下去,探究为何用户需要某些功能或信息,然后解决他们的底层需求

△ 显示当前时间办公室处于开放还是关闭状态

△ 显示事件的新近状态

如最近发表的评论,显示为几天之前而不是具体日期,用户可明确感知是新评论。

未完待续…

有图有案例!125个提升网页可用性的优化小技巧(一)

英文:nickkolenda

译者:企业官网设计精选

链接:http://www.uisdc.com/125-website-usability-optimize-1#

编者按:这个系列的教程到目前为止有5个章节,共125个实用技巧,每一个技巧都有案例对比,保证简单易懂。今天翻译了第一部分 —— 在网页设计中如何引导用户的注意力。学会一个就能受用无穷,更别说这一章整整有17个具体的方法了。

在界面中突出强调一个聚焦点

每个界面都应该有一个清晰的起点。用户应该从哪里看起?要设计清楚。

△ UX策略1 – 在页面标题部分添加视觉对比

通过视觉的层次引导用户

通过界面引导控制用户体验。他们应该从哪里先看起,第二和第三步又看哪里?设计要建立层次结构。

△ UX策略2 – 避免在构图中补漏留白

△ UX策略3 – 使用单列布局

△ UX策略4 – 重叠设计元素,强调连续性

使用格式塔原则进行布局设计

根据格式塔心理学,人会通过简化感知克服混乱。所以我们将事物分组,将元素分类,我们看“整体”。

这些原则包括:相似,接近,闭合,连接,连续和图形/背景。

△ UX策略5 – 按照接近性将相似功能或菜单项分组显示

△ UX策略6 – 标题位置与对应章节内容更靠近

△ UX策略7 – 限制标题与章节内容在同一界限内

在不干扰用户的前提下呈现界面变化

有一些界面变化会发生在用户使用期间,这些变化要做到明显但不干扰用户。

△ UX策略8 – 用明显的动画呈现界面变化

△ UX策略9 – 将出错的元素区分显示出来,错误提醒信息放置在表单顶部

删除或弱化不必要的信息

人的注意力是有限的。不必要的元素会消耗这些注意力。因此,保持用户专注在重要信息和功能上。

△ UX策略10 – 弹出或模态窗口背景模糊处理

△ UX策略11 – 在所有图像中最大限度地提高数据墨水比率(让数据更凸显)

△ UX策略12 – 去掉不必要的边框

△ UX策略13 – 删除冗余或不言自明的说明

△ UX策略14 – 隐藏不常用但必要的设置、功能和信息

提示首屏以下是否还有内容

现在大多数浏览器在页面处于非活动状态时隐藏滚动条,你需要“滚动提示”告知用户首屏以下是否还有内容

△ UX策略15 – 通过首屏延伸页面下方信息元素

△ UX策略16 – 添加阴影以指示深度

△ UX策略17 – 用文字或图形表示有更多内容

响应式网页设计排版需要注意什么?

出处:前端资源网

链接:http://www.58img.com/design/2495

斯坦佛大学的一份研究报告证实,75%的用户承认自己会通过一个公司的网站来评价该公司的声誉。由此可见,优秀的网页排版对于公司的形象和转换率有重要作用。毫无疑问,网页必须以有吸引力的,高效的方式方式呈现信息。问题是,目前有很多不同类型的移动设备,而网页排版必须符合所有这些平台的规范。

那么,我们究竟该如何实现最佳的网页排版效果呢?

1. 精心挑选字体将为你赢得灵活而高效的排版

自从客户端字体(Font Face)被引入网页设计中之后,网页设计师们便拥有了将不同字体用于自己设计中的自由。此前,他们只能使用特定的,与网页安全兼容的字体。

但面对这些可以自由使用的字体,设计师们还需要知道如何正确地使用它们。响应式网页设计已经成为多数网站的标准设计模式,不过由于要顾及不同尺寸的设备屏幕,它对网页排版也提出了一些限制。所以网页设计师在一个响应式网页系统中使用多种字体时,必须十分审慎。在同一个网站中不要使用太多种字体,最好不要超过三种。同时也不要使用极为流行的字体,这并不能让你的网页看起来比别的网页更有优势。

案例分析

这个站点使用了两种无衬线字体。所有的标题使用的都是Balto 字体,正文采用的是Alright Sans 字体。介于这两者之间的是Harriet 字体。整个页面外观显得十分简洁优雅。

http://www.vox.com/

与之形成对比的是angelfire 网站,这个站点使用了多种不同的字体,看起来混乱,不专业。

2. 突出显示标题

网页排版的一个特点就是标题在版式中占据突出位置。别致的标题能吸引用户在你的网站停留更久。为了实现这一点,你可以利用字形(glyphs)和连字(ligatures)技巧创造外观更独特的标题。

连字指的是看起来似乎是连接在一起的字母。例如,单词“fish”中的f和i在某种字体里可能联成一体(fi)。通过浏览器的字体设置功能或借助“文本渲染——优化清晰度”(Text Rendering- OptimiseLegibility)特性, 你可以轻松地实现连字效果。火狐浏览器已经设置了默认的连字符。在某些字体中使用特定的连字组合效果能为你的网页版式增加美感和风格。在网页排版软件的Text, Type 或Open Type目录中,一般都可以开启或关闭连字效果。当合适的字母相邻出现时,这些软件会自动为它们设置连字效果。

案例分析

请注意这个网站中优雅的连字。这些优美的字体如果用于网页标题中的话,无疑会为访客带来更为卓越的用户体验。

http://iloveligatures.tumblr.com/

3. 合理搭配不同大小和颜色的字体

正如上面的图片所传递的信息一样,我们在网页设计中必须选择能在桌面端和移动设备屏幕上都清晰显示的字体。一款字体在印刷品中与在数码设备中显示的效果是不同的。因此我们必须理解font family属性,风格和效果。根据W3C对于CSS字体的规定,Serif, Sans-Serif, Monospace, Fantasy 和Cursive等字体都具有font family属性。

第二,应根据网站的主题或分类来选择字体。这样才能确保你的网页能引起目标受众的共鸣,达到想要的效果。衬线字体同样能用于提升文本的阅读效果,强化要传达的信息。这里的问题是,衬线字体的特性决定了它只能在高解析度的屏幕上正常显示,在低解析度的屏幕上可能会导致糟糕的结果。因此建议你在短标题中使用艺术字体,在正文中采用更简洁的字体。

4. 在响应式排版中,调节行宽十分重要

必须对网页中的行宽(line length )进行调节,因为字体的行宽与排版的响应程度息息相关。响应式设计也包括在不同尺寸的屏幕上字体所发生的自适应式改变。所以调整字体的行宽是必须的。

理想的行宽为每行文本中字符数量在45-47之间,包含空格和标点。最长的限度我45-85个字符。这是对人们的阅读习惯和眼动规律做出研究后得出的结论。根据这一结论,有专家建议网页内容采用左对齐的排版方式,因为人的视线在阅读时一般会按照从左至右的方式在水平方向上运动。

案例分析

网站suite 将没行文本的字符数限定为75个。正如你能看到的,页面中的文本看起来十分优美,能让用户怀着兴趣一直读下去。

https://suite.io/

5.当用户与屏幕的距离不同时,使用不同大小的字体能改善可读性。在响应式排版设计中,必须考虑这一点。

字体的大小要能保证字体在设备上可见,可读。而要做到这一点,可能会与前面所说的保持“理想行宽”发生冲突。因为“理想行宽”意味着要调小或调大字体尺寸,而这两者都可能导致文本不可读。这里的底线是要保证浏览者能舒服地阅读网页内容。响应式设计非常关键的一点就在于,根据用户与设备屏幕距离的不同,应用于设备屏幕的字体大小也应该不同。对于字体大小与阅读距离的关系,已经有计算的方法。

案例分析

请查看 moonbase 网站。这是一个帮助其他公司设计网站的网站。网页中央的文本十分显眼,它传达了这个站点的功能。我们只需看一眼就能明白。突出的字体能紧紧地抓住用户的注意力,并促使他们继续阅读网站的其余部分。

http://moonbase.co/

6. 响应式排版要求浏览器支持不同大小的字体

如果你设计的网页中需要用到某些自定义字体,你必须确保浏览器支持加载和显示这些字体。即便你的字体本身清晰,没有错误,但浏览器兼容问题可能会使你前功尽弃。你还必须检查你保存的字体文件格式与你想应用于网页中的字体是否兼容。不兼容的字体无法正常加载,最终会影响网页的显示。

案例分析:从上面的示例中我们可以发现,我们需要使用标准字体或“字体库”。第一步是通过“字体测试”来确定一款字体是否适用于网页中。浏览器对于每个系列的字体都有“第一选项”,“第二选项”,“第三选项”……的区分。如果浏览器在这个系列中赵爱不到任何合适的字体,它会自动选择默认的无衬线字体,衬线字体或Monospace字体。

举例来说,很多浏览器都自带 Century Gothic字体。你可以创建一个字体库,将Century Gothic字体视为你的第一选项,之后是Arial, Helvetica,最后是一款无衬线类的字体。注意,在CSS中,标题中含有多个单词的字体需要加上引号。例如: font-family:“Century Gothic”, Arial, Helvetica, Sans-Serif.

这样一来,浏览器会首先采用Century Gothic字体。由于很多浏览器都自带这款字体,多数用户在浏览网页时看到的也会是Century Gothic字体。对于没有配置 Century Gothic的浏览器,浏览器会按照Arial, Helvetica,事前设置的无衬线字体的顺序寻找替代。

7.与字体的物理属性相关的因素会影响字体在设计中的灵活度

响应式排版可能会受制于影响字形的因素。这些因素包括字重,字宽,笔画对比,字体高度,光学尺寸等等。这些因素的些微变化都会影响站点的观感。当然,现在已经有了不少的工具可以让设计师部分地修正这些限制。

Superpolator 和FlowType.js就是此类工具中有代表性的两款。当屏幕尺寸减小时,不同比例的网页间的差异就会更为凸显。因此就需要在网页尺寸与缩放比例间找到平衡点。例如,用于标题的字体比用于正文的字体大/小多少倍,这就涉及比例问题。这也就是我们为何需要响应式排版的理由。我们需要在断点中能自行缩小的字体,因为设计师们无法为网页内的所有字体元素一一调整基线风格。

案例分析

请查看flowtype网站。借助 Superpolator 和FlowType.js之类的工具,只需拖动滑块,你便能清楚地看到响应式排版的作用。

http://simplefocus.com/flowtype/

响应式排版的操作需要在实践中不断完善。通过对媒介查询(media queries)知识的学习和对不同屏幕尺寸的设备进行测试,你将会逐步掌握响应式排版的要点。现在你已经知道了要达到最好的响应式排版效果需遵循哪些原则,今后便可以将这些原则贯彻到自己的设计中。

Java中文乱码解决之道(4): java编码转换过程

来源:chenssy

链接:http://www.cnblogs.com/chenssy/p/4207554.html

前面三篇博客侧重介绍字符、编码问题,通过这三篇博客各位博友对各种字符编码有了一个初步的了解,要了解java的中文问题这是必须要了解的。但是了解这些仅仅只是一个开始,以下博客将侧重介绍java乱码是如何产生的、存在哪些乱码的情况、该如何从根本上解决乱码问题。各位随博主一起征服令人厌烦的java乱码问题吧!!!

java编码转换过程

我们总是用一个java类文件和用户进行最直接的交互(输入、输出),这些交互内容包含的文字可能会包含中文。无论这些java类是与数据库交互,还是与前端页面交互,他们的生命周期总是这样的:

1、程序员在操作系统上通过编辑器编写程序代码并且以.java的格式保存操作系统中,这些文件我们称之为源文件。

2、通过JDK中的javac.exe编译这些源文件形成.class类。

3、直接运行这些类或者部署在WEB容器中运行,得到输出结果。

这些过程是从宏观上面来观察的,了解这个肯定是不行的,我们需要真正来了解java是如何来编码和被解码的:

第一步:当我们用编辑器编写java源文件,程序文件在保存时会采用操作系统默认的编码格式(一般我们中文的操作系统采用的是GBK编码格式)形成一个.java文件。java源文件是采用操作系统默认支持的file.encoding编码格式保存的。下面代码可以查看系统的file.encoding参数值。

System.out.println(System.getProperty(“file.encoding”));

第二步:当我们使用javac.exe编译我们的java文件时,JDK首先会确认它的编译参数encoding来确定源代码字符集,如果我们不指定该编译参数,JDK首先会获取操作系统默认的file.encoding参数,然后JDK就会把我们编写的java源程序从file.encoding编码格式转化为JAVA内部默认的UNICODE格式放入内存中。

第三步:JDK将上面编译好的且保存在内存中信息写入class文件中,形成.class文件。此时.class文件是Unicode编码的,也就是说我们常见的.class文件中的内容无论是中文字符还是英文字符,他们都已经转换为Unicode编码格式了。

在这一步中对对JSP源文件的处理方式有点儿不同:WEB容器调用JSP编译器,JSP编译器首先会查看JSP文件是否设置了文件编码格式,如果没有设置则JSP编译器会调用调用JDK采用默认的编码方式将JSP文件转化为临时的servlet类,然后再编译为.class文件并保持到临时文件夹中。

第四步:运行编译的类:在这里会存在一下几种情况

1、直接在console上运行。

2、JSP/Servlet类。

3、java类与数据库之间。

这三种情况每种情况的方式都会不同,

1.Console上运行的类

这种情况下,JVM首先会把保存在操作系统中的class文件读入到内存中,这个时候内存中class文件编码格式为Unicode,然后JVM运行它。如果需要用户输入信息,则会采用file.encoding编码格式对用户输入的信息进行编码同时转换为Unicode编码格式保存到内存中。程序运行后,将产生的结果再转化为file.encoding格式返回给操作系统并输出到界面去。整个流程如下:

在上面整个流程中,凡是涉及的编码转换都不能出现错误,否则将会产生乱码。

2.Servlet类

由于JSP文件最终也会转换为servlet文件(只不过存储的位置不同而已),所以这里我们也将JSP文件纳入其中。

当用户请求Servlet时,WEB容器会调用它的JVM来运行Servlet。首先JVM会把servlet的class加载到内存中去,内存中的servlet代码是Unicode编码格式的。然后JVM在内存中运行该Servlet,在运行过程中如果需要接受从客户端传递过来的数据(如表单和URL传递的数据),则WEB容器会接受传入的数据,在接收过程中如果程序设定了传入参数的的编码则采用设定的编码格式,如果没有设置则采用默认的ISO-8859-1编码格式,接收的数据后JVM会将这些数据进行编码格式转换为Unicode并且存入到内存中。运行Servlet后产生输出结果,同时这些输出结果的编码格式仍然为Unicode。紧接着WEB容器会将产生的Unicode编码格式的字符串直接发送置客户端,如果程序指定了输出时的编码格式,则按照指定的编码格式输出到浏览器,否则采用默认的ISO-8859-1编码格式。整个过程流程图如下:

3.数据库部分

我们知道java程序与数据库的连接都是通过JDBC驱动程序来连接的,而JDBC驱动程序默认的是ISO-8859-1编码格式的,也就是说我们通过java程序向数据库传递数据时,JDBC首先会将Unicode编码格式的数据转换为ISO-8859-1的编码格式,然后在存储在数据库中,即在数据库保存数据时,默认格式为ISO-8859-1。