Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15843 articles
Browse latest View live

Redis在新浪微博中的应用

$
0
0

Redis

感觉国内对Redis玩的最转的就是新浪微博了,最近也在研究和使用Redis,准备把某些数据放到redis中。

看了几篇新浪微博的文章,挺受启发的,特别是对Redis集群扩容、内存容量配置等经验的介绍。

这里也分享一下。

Redis计数在新浪微博的应用

微博关系服务与Redis的故事

Redis 在新浪微博中的应用

真的挺受启发的。

Redis 3.0新加入了Cluster模块,期待stable版本发布。

您可能也喜欢:

微博和weibo.com

你有没有感觉到国内的各大微博正在悄悄“变化”?

中文微博的春天貌似已经来临

[牛博阅读] 一个微博的时代来临了,未来?

开源微博程序 StatusNet 0.9.0 发布
无觅

Oracle SQL建立有效索引减少回表

$
0
0


回表:在数据中,当查询数据的时候,在索引中查找索引后,获得该行的rowid,根据rowid再查询表中数据,就是回表。

在数据库中,数据的存储都是以块为单位的,称为数据块,表中每一行数据都有唯一的地址标志ROWID。每次使用SQL进行查询的时候,都要扫描数据块,找到行所在的ROWID,再扫描该表的数据块。回表将会导致扫描更多的数据块。

例如:SELECT a,b,cFROM TEST_DB WHERE b=1

在该查询语句执行的时候,可分为两种情况:

A. 在b上没有建立索引

如果在b上没有建立索引,那么该条SQL语句执行时,要进行全表扫描,扫描所有该表中的数据块。从该数据块中找到记录,并进行过滤。在没有索引时,查找数据会导致扫描表中所有数据块,性能较低。

B. 在b上建立索引

如果在b上建立索引,那么在执行该条SQL语句时,先进行索引扫描,在索引中找到b=1所在的位置(一般只需要扫描3个块数据即可),获得改行的ROWID,根据其ROWID再查询数据(回表),如果所查找的数据量较少,则回表次数就少。如上面的例子,要查询的数据只有b在索引中,a并不在索引中,那么就要回表一次查询a;如果a也在索引中,那么就不需要回表。

在数据库查询中,需要用到回表的地方很多,如分页查询。一般要竟量在索引上分页,然后返回ROWID,在通过ROWID进行回表查询。

如分页语句: SELECT *  FROM  ( SELECT ROW_NUMBER OVER (ORDER BY A ) RN,T.* FROM  TABLE  T  WHERE B=?  AND C=? ) WHERE  RN>=1 AND  RN <=20

在该分页查询语句中,我们建立B,C,A的索引,那么查询时,步骤如下:

1.先查询内层语句 SELECT *  FROM  TABLE T  WHERE  B=?  AND  C=?,假设返回1000行数据。

2.通过索引找到这1000行数据的ROWID,由于索引时连续的,所以假设这1000行数据的索引分布在3个数据块中,一般需要读取6个数据块。再根据ROWID取回表查询数据,最差的情况是这1000行数据分布在1000个数据块中,则需要读取1000块。那么总共需要读取的数据块区为1006块。

如果我们换另外一种写法:

SELECT  * FROM  TABLE  T, (SELECT  RID  FROM (SELECT ROWID  RID, ROW_NUMBER  OVER(ORDER BY  A)  RN FROM  TABLE  WHERE B=?  AND  C=?) WHERE  RN >1 AND  RN<=20 )  TMP WHERE  TMP.RID = T.ROWID

在例子中,最里层的SELECT RID  FROM (SELECT  ROWID RID, ROW_NUMBER  OVER(ORDER  BY A)  RN  FROM TABLE  WHERE  B=? AND  C=?) WHERE  RN >1 AND  RN<=20,可以全部在索引中获取到数据,和上面一样,也差不多为6数据块。分页之后,只有20行数据,在更具这20行的ROWID回表查询数据,最坏的情况是20行都在20个不同块中,那么总共也只扫描26块数据块。

因此,有效的利用索引,可以减少回表的次数,大大提升SQL性能。

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



MongoDB MapReduce 性能提升20倍的优化宝典

$
0
0

自从MongoDB被越来越多的大型关键项目采用后,数据分析也成为了越来越重要的话题。人们似乎已经厌倦了使用不同的软件来进行分析(这都利用到了Hadoop),因为这些方法往往需要大规模的数据传输,而这些成本相当昂贵。 

MongoDB提供了2种方式来对数据进行分析: Map Reduce(以下简称MR)和聚合框架(Aggregation Framework)。MR非常灵活且易于使用,它可以很好地与分片(sharding)结合使用,并允许大规模输出。尽管在MongoDB v2.4版本中,由于JavaScript引擎从Spider切换到了V8,使得MR的性能有了大幅改进,但是与Agg Framework(使用C++)相比,MR的速度还是显得比较慢。本文就来看看,有哪些方法可以让MR的速度有所提升。 

测试 

首先我们来做个测试,插入1000万文档,这些文档中包含了介于0和100万之间的单一整数值,这意味着,平均每10个文档具有相同的值。 

代码 
  1. > for (var i = 0; i < 10000000; ++i){ db.uniques.insert({ dim0: Math.floor(Math.random()*1000000) });}  
  2. > db.uniques.findOne()  
  3. { "_id" : ObjectId("51d3c386acd412e22c188dec"), "dim0" : 570859 }  
  4. > db.uniques.ensureIndex({dim0: 1})  
  5. > db.uniques.stats()  
  6. {  
  7.         "ns" : "test.uniques",  
  8.         "count" : 10000000,  
  9.         "size" : 360000052,  
  10.         "avgObjSize" : 36.0000052,  
  11.         "storageSize" : 582864896,  
  12.         "numExtents" : 18,  
  13.         "nindexes" : 2,  
  14.         "lastExtentSize" : 153874432,  
  15.         "paddingFactor" : 1,  
  16.         "systemFlags" : 1,  
  17.         "userFlags" : 0,  
  18.         "totalIndexSize" : 576040080,  
  19.         "indexSizes" : {  
  20.                 "_id_" : 324456384,  
  21.                 "dim0_1" : 251583696  
  22.         },  
  23.         "ok" : 1  
  24. }  



这里我们想要得到文档中唯一值的计数,可以通过下面的MR任务来轻松完成: 

代码 
  1. > db.runCommand(  
  2. { mapreduce: "uniques",  
  3. map: function () { emit(this.dim0, 1); },  
  4. reduce: function (key, values) { return Array.sum(values); },  
  5. out: "mrout" })  
  6. {  
  7.         "result" : "mrout",  
  8.         "timeMillis" : 1161960,  
  9.         "counts" : {  
  10.                 "input" : 10000000,  
  11.                 "emit" : 10000000,  
  12.                 "reduce" : 1059138,  
  13.                 "output" : 999961  
  14.         },  
  15.         "ok" : 1  
  16. }  



正如你看到的,输出结果大约需要1200秒(在EC2 M3实例上测试),共输出了1千万maps、100万reduces、999961个文档。结果类似于: 

代码 
  1. > db.mrout.find()  
  2. { "_id" : 1, "value" : 10 }  
  3. { "_id" : 2, "value" : 5 }  
  4. { "_id" : 3, "value" : 6 }  
  5. { "_id" : 4, "value" : 10 }  
  6. { "_id" : 5, "value" : 9 }  
  7. { "_id" : 6, "value" : 12 }  
  8. { "_id" : 7, "value" : 5 }  
  9. { "_id" : 8, "value" : 16 }  
  10. { "_id" : 9, "value" : 10 }  
  11. { "_id" : 10, "value" : 13 }  
  12. ...  



下面就来看看如何进行优化。 

使用排序 

我在之前的这篇 文章中简要说明了使用排序对于MR的好处,这是一个鲜为人知的特性。在这种情况下,如果处理未排序的输入,意味着MR引擎将得到随机排序的值,基本上没有机会在RAM中进行reduce,相反,它将不得不通过一个临时collection来将数据写回磁盘,然后按顺序读取并进行reduce。 

下面来看看如果使用排序,会有什么帮助: 

代码 
  1. > db.runCommand(  
  2. { mapreduce: "uniques",  
  3. map: function () { emit(this.dim0, 1); },  
  4. reduce: function (key, values) { return Array.sum(values); },  
  5. out: "mrout",  
  6. sort: {dim0: 1} })  
  7. {  
  8.         "result" : "mrout",  
  9.         "timeMillis" : 192589,  
  10.         "counts" : {  
  11.                 "input" : 10000000,  
  12.                 "emit" : 10000000,  
  13.                 "reduce" : 1000372,  
  14.                 "output" : 999961  
  15.         },  
  16.         "ok" : 1  
  17. }  



现在时间降到了192秒,速度提升了6倍。其实reduces的数量是差不多的,但是它们在被写入磁盘之前已经在RAM中完成了。 

使用多线程 

在MongoDB中,一个单一的MR任务并不能使用多线程——只有在多个任务中才能使用多线程。但是目前的多核CPU非常有利于在单一服务器上进行并行化工作,就像Hadoop。我们需要做的是,将输入数据分割成若干块,并为每个块分配一个MR任务。splitVector命令可以帮助你非常迅速地找到分割点,如果你有更简单的分割方法更好。 

代码 
  1. > db.runCommand({splitVector: "test.uniques", keyPattern: {dim0: 1}, maxChunkSizeBytes: 32000000})  
  2. {  
  3.     "timeMillis" : 6006,  
  4.     "splitKeys" : [  
  5.         {  
  6.             "dim0" : 18171  
  7.         },  
  8.         {  
  9.             "dim0" : 36378  
  10.         },  
  11.         {  
  12.             "dim0" : 54528  
  13.         },  
  14.         {  
  15.             "dim0" : 72717  
  16.         },  
  17. …  
  18.         {  
  19.             "dim0" : 963598  
  20.         },  
  21.         {  
  22.             "dim0" : 981805  
  23.         }  
  24.     ],  
  25.     "ok" : 1  
  26. }  



从1千万文档中找出分割点,使用splitVector命令只需要大约5秒,这已经相当快了。所以,下面我们需要做的是找到一种方式来创建多个MR任务。从应用服务器方面来说,使用多线程和$gt / $lt查询命令会非常方便。从shell方面来说,可以使用ScopedThread对象,它的工作原理如下: 

代码 
  1. > var t = new ScopedThread(mapred, 963598, 981805)  
  2. > t.start()  
  3. > t.join()  



现在我们可以放入一些JS代码,这些代码可以产生4个线程,下面来等待结果显示: 

代码 
  1. > var res = db.runCommand({splitVector: "test.uniques", keyPattern: {dim0: 1}, maxChunkSizeBytes: 32 *1024 * 1024 })  
  2. > var keys = res.splitKeys  
  3. > keys.length  
  4. 39  
  5. > var mapred = function(min, max) {  
  6. return db.runCommand({ mapreduce: "uniques",  
  7. map: function () { emit(this.dim0, 1); },  
  8. reduce: function (key, values) { return Array.sum(values); },  
  9. out: "mrout" + min,  
  10. sort: {dim0: 1},  
  11. query: { dim0: { $gte: min, $lt: max } } }) }  
  12. > var numThreads = 4  
  13. > var inc = Math.floor(keys.length / numThreads) + 1  
  14. > threads = []; for (var i = 0; i < numThreads; ++i) { var min = (i == 0) ? 0 : keys[i * inc].dim0; var max = (i * inc + inc >= keys.length) ? MaxKey : keys[i * inc + inc].dim0 ; print("min:" + min + " max:" + max); var t = new ScopedThread(mapred, min, max); threads.push(t); t.start() }  
  15. min:0 max:274736  
  16. min:274736 max:524997  
  17. min:524997 max:775025  
  18. min:775025 max:{ "$maxKey" : 1 }  
  19. connecting to: test  
  20. connecting to: test  
  21. connecting to: test  
  22. connecting to: test  
  23. > for (var i in threads) { var t = threads[i]; t.join(); printjson(t.returnData()); }  
  24. {  
  25.         "result" : "mrout0",  
  26.         "timeMillis" : 205790,  
  27.         "counts" : {  
  28.                 "input" : 2750002,  
  29.                 "emit" : 2750002,  
  30.                 "reduce" : 274828,  
  31.                 "output" : 274723  
  32.         },  
  33.         "ok" : 1  
  34. }  
  35. {  
  36.         "result" : "mrout274736",  
  37.         "timeMillis" : 189868,  
  38.         "counts" : {  
  39.                 "input" : 2500013,  
  40.                 "emit" : 2500013,  
  41.                 "reduce" : 250364,  
  42.                 "output" : 250255  
  43.         },  
  44.         "ok" : 1  
  45. }  
  46. {  
  47.         "result" : "mrout524997",  
  48.         "timeMillis" : 191449,  
  49.         "counts" : {  
  50.                 "input" : 2500014,  
  51.                 "emit" : 2500014,  
  52.                 "reduce" : 250120,  
  53.                 "output" : 250019  
  54.         },  
  55.         "ok" : 1  
  56. }  
  57. {  
  58.         "result" : "mrout775025",  
  59.         "timeMillis" : 184945,  
  60.         "counts" : {  
  61.                 "input" : 2249971,  
  62.                 "emit" : 2249971,  
  63.                 "reduce" : 225057,  
  64.                 "output" : 224964  
  65.         },  
  66.         "ok" : 1  
  67. }  



第1个线程所做的工作比其他的要多一点,但时间仍达到了190秒,这意味着多线程并没有比单线程快! 

使用多个数据库 

这里的问题是,线程之间存在太多锁争用。当锁时,MR不是非常无私(每1000次读取会进行yield)。由于MR任务做了大量写操作,线程之间结束时会等待彼此。由于MongoDB的每个数据库都有独立的锁,那么让我们来尝试为每个线程使用不同的输出数据库: 

代码 
  1. > var mapred = function(min, max) {  
  2. return db.runCommand({ mapreduce: "uniques",  
  3. map: function () { emit(this.dim0, 1); },  
  4. reduce: function (key, values) { return Array.sum(values); },  
  5. out: { replace: "mrout" + min, db: "mrdb" + min },  
  6. sort: {dim0: 1},  
  7. query: { dim0: { $gte: min, $lt: max } } }) }  
  8. > threads = []; for (var i = 0; i < numThreads; ++i) { var min = (i == 0) ? 0 : keys[i * inc].dim0; var max = (i * inc + inc >= keys.length) ? MaxKey : keys[i * inc + inc].dim0 ; print("min:" + min + " max:" + max); var t = new ScopedThread(mapred, min, max); threads.push(t); t.start() }  
  9. min:0 max:274736  
  10. min:274736 max:524997  
  11. min:524997 max:775025  
  12. min:775025 max:{ "$maxKey" : 1 }  
  13. connecting to: test  
  14. connecting to: test  
  15. connecting to: test  
  16. connecting to: test  
  17. > for (var i in threads) { var t = threads[i]; t.join(); printjson(t.returnData()); }  
  18. ...  
  19. {  
  20.         "result" : {  
  21.                 "db" : "mrdb274736",  
  22.                 "collection" : "mrout274736"  
  23.         },  
  24.         "timeMillis" : 105821,  
  25.         "counts" : {  
  26.                 "input" : 2500013,  
  27.                 "emit" : 2500013,  
  28.                 "reduce" : 250364,  
  29.                 "output" : 250255  
  30.         },  
  31.         "ok" : 1  
  32. }  
  33. ...  



所需时间减少到了100秒,这意味着与一个单独的线程相比,速度约提高2倍。尽管不如预期,但已经很不错了。在这里,我使用了4个核心,只提升了2倍,如果使用8核CPU,大约会提升4倍。 

使用纯JavaScript模式 

在线程之间分割输入数据时,有一些非常有趣的东西:每个线程只拥有约25万主键来输出,而不是100万。这意味着我们可以使用“纯JS模式”——通过jsMode:true来启用。开启后,MongoDB不会在JS和BSON之间反复转换,相反,它会从内部的一个50万主键的JS字典来reduces所有对象。下面来看看该操作是否对速度提升有帮助。

代码 
  1. > var mapred = function(min, max) {  
  2. return db.runCommand({ mapreduce: "uniques",  
  3. map: function () { emit(this.dim0, 1); },  
  4. reduce: function (key, values) { return Array.sum(values); },  
  5. out: { replace: "mrout" + min, db: "mrdb" + min },  
  6. sort: {dim0: 1},  
  7. query: { dim0: { $gte: min, $lt: max } },  
  8. jsMode: true }) }  
  9. > threads = []; for (var i = 0; i < numThreads; ++i) { var min = (i == 0) ? 0 : keys[i * inc].dim0; var max = (i * inc + inc >= keys.length) ? MaxKey : keys[i * inc + inc].dim0 ; print("min:" + min + " max:" + max); var t = new ScopedThread(mapred, min, max); threads.push(t); t.start() }  
  10. min:0 max:274736  
  11. min:274736 max:524997  
  12. min:524997 max:775025  
  13. min:775025 max:{ "$maxKey" : 1 }  
  14. connecting to: test  
  15. connecting to: test  
  16. connecting to: test  
  17. connecting to: test  
  18. > for (var i in threads) { var t = threads[i]; t.join(); printjson(t.returnData()); }  
  19. ...  
  20. {  
  21.         "result" : {  
  22.                 "db" : "mrdb274736",  
  23.                 "collection" : "mrout274736"  
  24.         },  
  25.         "timeMillis" : 70507,  
  26.         "counts" : {  
  27.                 "input" : 2500013,  
  28.                 "emit" : 2500013,  
  29.                 "reduce" : 250156,  
  30.                 "output" : 250255  
  31.         },  
  32.         "ok" : 1  
  33. }  
  34. ...  



现在时间降低到70秒。看来jsMode确实有帮助,尤其是当对象有很多字段时。该示例中是一个单一的数字字段,不过仍然提升了30%。 

MongoDB v2.6版本中的改进 

在MongoDB v2.6版本的开发中,移除了一段关于在JS函数调用时的一个可选“args”参数的代码。该参数是不标准的,也不建议使用,它由于历史原因遗留了下来(见 SERVER-4654)。让我们从Git库中pull最新的MongoDB并编译,然后再次运行测试用例: 

代码 
  1. ...  
  2. {  
  3.         "result" : {  
  4.                 "db" : "mrdb274736",  
  5.                 "collection" : "mrout274736"  
  6.         },  
  7.         "timeMillis" : 62785,  
  8.         "counts" : {  
  9.                 "input" : 2500013,  
  10.                 "emit" : 2500013,  
  11.                 "reduce" : 250156,  
  12.                 "output" : 250255  
  13.         },  
  14.         "ok" : 1  
  15. }  
  16. ...  



从结果来看,时间降低到了60秒,速度大约提升了10-15%。同时,这种更改也改善了JS引擎的整体堆消耗量。

结论 

回头来看,对于同样的MR任务,与最开始时的1200秒相比,速度已经提升了20倍。这种优化应该适用于大多数情况,即使一些技巧效果不那么理想(比如使用多个输出dbs /集合)。但是这些技巧可以帮助人们来提升MR任务的速度,未来这些特性也许会更加易用——比如,这个 ticket 将会使splitVector命令更加可用,这个 ticket将会改进同一数据库中的多个MR任务。 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



XSS 前端防火墙 —— 内联事件拦截

$
0
0
作者:zjcqoo

关于 XSS 怎样形成、如何注入、能做什么、如何防范,前人已有无数的探讨,这里就不再累述了。本文介绍的则是另一种预防思路。

几乎每篇谈论 XSS 的文章,结尾多少都会提到如何防止,然而大多万变不离其宗。要转义什么,要过滤什么,不要忘了什么之类的。尽管都是众所周知的道理,但 XSS 漏洞十几年来几乎从未中断过,不乏一些大网站也时常爆出,小网站更是家常便饭。

预警系统

事实上,至今仍未有一劳永逸的解决方案,要避免它依旧使用最古老的土办法,逐个的过滤。然而人总有疏忽的时候,每当产品迭代更新时,难免会遗漏一些新字段,导致漏洞被引入。

即使圣人千虑也有一失,程序出 BUG 完全可以理解,及时修复就行。但令人费解的是,问题出现到被发现,却要经过相当长的时间。例如不久前贴吧 XSS 蠕虫脚本,直到大规模爆发后经用户举报,最终才得知。其他网站大多也类似,直到白帽子们挖掘出漏洞,提交到安全平台上,最终厂商才被告知。若遇到黑客私下留着这些漏洞慢慢利用,那只能听天由命了。

因此,要是能有一套实时的预警系统,那就更好了。即使无法阻止漏洞的发生,但能在漏洞触发的第一时间里,通知开发人员,即可在最短的时间里修复,将损失降到最低。各式各样的应用层防火墙,也由此产生。

不过,和传统的系统漏洞不同,XSS 最终是在用户页面中触发的。因此,我们不妨尝试使用前端的思路,进行在线防御。

DOM 储存型 XSS

先来假设一个有 BUG 的后台,没有很好处理用户输入的数据,导致 XSS 能被注入到页面:

<img src="{路径}" /><img src="{路径" onload="alert(/xss/)}" />

只转义尖括号,却忘了引号,是 XSS 里最为常见的。攻击者们可以提前关闭属性,并添加一个极易触发的内联事件,跨站脚本就这样被轻易执行了。

那么,我们能否使用前端脚本来捕获,甚至拦截呢?

被动扫描

最简单的办法,就是把页面里所有元素都扫描一遍,检测那些 on 开头的内联属性,看看是不是存在异常:

例如字符数非常多,正常情况下这是很少出现的,但 XSS 为了躲避转义有时会编码的很长;例如出现一些 XSS 经常使用的关键字,但在实际产品里几乎不会用到的。这些都可以作为漏洞出现的征兆,通知给开发人员。

不过,土办法终究存在很大的局限性。在如今清一色的 AJAX 时代,页面元素从来都不是固定的。伴随着用户各种交互,新内容随时都可能动态添加进来。即使换成定期扫描一次,XSS 也可能在定时器的间隔中触发,并销毁自己,那样永远都无法跟踪到了。况且,频繁的扫描对性能影响也是巨大的。

如同早期的安全软件一样,每隔几秒扫描一次注册表启动项,不仅费性能,而且对恶意软件几乎不起作用;但之后的主动防御系统就不同了,只有在真正调用 API 时才进行分析,不通过则直接拦截,完全避免了定时器的间隔遗漏。

因此,我们需要这种类似的延时策略 —— 仅在 XSS 即将触发时对其分析,对不符合策略的元素,进行拦截或者放行,同时发送报警到后台日志。

主动防御

『主动防御』,这概念放在前端脚本里似乎有些玄乎。但不难发现,这仅仅是执行优先级的事而已 —— 只要防御程序能运行在其他程序之前,我们就有了可进可退的主动权。对于无比强大的 HTML5 和灵活多变的 JavaScript,这些概念都可以被玩转出来。

继续回到刚才讨论的内联事件 XSS 上来。浏览器虽然没提供可操控内联事件的接口,但内联事件的本质仍是一个事件,无论怎样变化都离不开 DOM 事件模型。

扯到模型上面,一切即将迎刃而解。模型是解决问题的最靠谱的办法,尤其是像 DOM-3-Event这种早已制定的模型,其稳定性毋庸置疑。

即便没仔细阅读官方文档,但凡做过网页的都知道,有个 addEventListener 的接口,并取代了曾经一个古老的叫 attachEvent 的东西。尽管只是新增了一个参数而已,但正是这个差别成了人们津津乐道的话题。每当面试谈到事件时,总少不了考察下这个新参数的用途。尽管在日常开发中很少用到它。

关于事件捕获和冒泡的细节,就不多讨论了。下面的这段代码,或许能激发你对『主动防御』的遐想。

<button onclick="console.log('target')">CLICK ME</button><script>
    document.addEventListener('click', function(e) {
        console.log('bubble');
    });

    document.addEventListener('click', function(e) {
        console.log('capture');
        //e.stopImmediatePropagation();
    }, true);</script>

Run

尽管按钮上直接绑了一个内联的事件,但事件模型并不买账,仍然得按标准的流程走一遍。capture,target,bubble,模型就是那样固执。

不过,把那行注释的代码恢复,结果就只剩 capture 了。这个简单的道理大家都明白,也没什么好解释的。

但仔细揣摩下,这不就是『主动防御』的概念吗?捕获程序运行在内联事件触发之前,并且完全有能力拦截之后的调用。

上面的 Demo 只是不假思索拦截了所有的事件。如果我们再加一些策略判断,或许就更明朗了:

<button onclick="console.log('xss')">CLICK ME</button><script>
    document.addEventListener('click', function(e) {
        console.log('bubble');
    });

    document.addEventListener('click', function(e) {
        var element = e.target;
        var code = element.getAttribute('onclick');

        if (/xss/.test(code)) {
            e.stopImmediatePropagation();
            console.log('拦截可疑事件:', code);
        }
    }, true);</script>

Run

我们先在捕获阶段扫描内联事件字符,若是出现了『xss』这个关键字,后续的事件就被拦截了;换成其他字符,仍然继续执行。同理,我们还可以判断字符长度是否过多,以及更详细的黑白名单正则。

怎么样,一个主动防御的原型诞生了吧。

不过,上面的片段还有个小问题,就是把事件的冒泡过程也给屏蔽了,而我们仅仅想拦截内联事件而已。解决办法也很简单,把 e.stopImmediatePropagation() 换成 element.onclick = null 就可以了。

当然,目前这只能防护 onclick,而现实中有太多的内联事件。鼠标、键盘、触屏、网络状态等等,不同浏览器支持的事件也不一样,甚至还有私有事件,难道都要事先逐一列出并且都捕获吗?是的,可以都捕获,但不必事先都列出来。

因为我们监听的是 document 对象,浏览器所有内联事件都对应着 document.onxxx 的属性,因此只需运行时遍历一下 document 对象,即可获得所有的事件名。

<img src="*" onerror="console.log('xss')" /><script>
    function hookEvent(onevent) {
        document.addEventListener(onevent.substr(2), function(e) {
            var element = e.target;
            if (element.nodeType != Node.ELEMENT_NODE) {
                return;
            }
            var code = element.getAttribute(onevent);
            if (code && /xss/.test(code)) {
                element[onevent] = null;
                console.log('拦截可疑事件:', code);
            }
        }, true);
    }

    console.time('耗时');
    for (var k in document) {
        if (/^on/.test(k)) {
            //console.log('监控:', k);
            hookEvent(k);
        }
    }
    console.timeEnd('耗时');</script>

Run

现在,无论页面中哪个元素触发哪个内联事件,都能预先被我们捕获,并根据策略可进可退了。

性能优化

或许有些事件没有必要捕获,例如视频播放、音量调节等,但就算全都捕捉也耗不了多少时间,基本都在 1ms 左右。

当然,注册事件本来就花不了多少时间,真正的耗费都算在回调上了。尽管大多数事件触发都不频繁,额外的扫描可以忽律不计。但和鼠标移动相关的事件那就不容忽视了,因此得考虑性能优化。

显然,内联事件代码在运行过程中几乎不可能发生变化。使用内联事件大多为了简单,如果还要在运行时 setAttribute 去改变内联代码,完全就是不可理喻的。因此,我们只需对某个元素的特定事件,扫描一次就可以了。之后根据标志,即可直接跳过。

<div style="width:100%; height:100%; position:absolute" onmouseover="console.log('xss')"></div><script>
    function hookEvent(onevent) {
        document.addEventListener(onevent.substr(2), function(e) {
            var element = e.target;

            // 跳过已扫描的事件
            var flags = element['_flag'];
            if (!flags) {
                flags = element['_flag'] = {};
            }
            if (typeof flags[onevent] != 'undefined') {
                return;
            }
            flags[onevent] = true;

            if (element.nodeType != Node.ELEMENT_NODE) {
                return;
            }
            var code = element.getAttribute(onevent);
            if (code && /xss/.test(code)) {
                element[onevent] = null;
                console.log('拦截可疑代码:', code);
            }
        }, true);
    }

    for (var k in document) {
        if (/^on/.test(k)) {
            hookEvent(k);
        }
    }
</script>

Run

这样,之后的扫描仅仅是判断一下目标对象中的标记而已。即使疯狂晃动鼠标,CPU 使用率也都忽略不计了。

到此,在 XSS 内联事件这块,我们已实现主动防御。

对于有着大量字符,或者出现类似 String.fromCharCode,$.getScript 这类典型 XSS 代码的,完全可以将其拦截;发现有 alert(/xss/),alert(123) 这些测试代码,可以暂时放行,并将日志发送到后台,确定是否能够复现。

如果复现,说明已有人发现 XSS 并成功注入了,但还没大规模开始利用。程序猿们赶紧第一时间修 BUG 吧,让黑客忙活一阵子后发现漏洞已经修复了:)

字符策略的缺陷

但是,光靠代码字符串来判断,还是会有疏漏的。尤其是黑客们知道有这么个玩意存在,会更加小心了。把代码转义用以躲避关键字,并将字符存储在其他地方,以躲过长度检测,即可完全绕过我们的监控了:

<img src="*" onerror="window['ev'+'al'](this.align)" align="alert('a mass of code...')">

因此,我们不仅需要分析关键字。在回调执行时,还需监控 eval、setTimeout('...') 等这类能解析代码的函数被调用。

不过,通常不会注入太多的代码,而是直接引入一个外部脚本,既简单又靠谱,并且能实时修改攻击内容:

<img src="*" onerror="$['get'+'Script'](...)">

明天将继续讨论,如何拦截可疑的外部模块。

Oracle异常处理概念

$
0
0

5.1 异常处理概念

5.1.1 预定义的异常处理

5.1.2 非预定义的异常处理

5.1.3 用户自定义的异常处理

5.1.4  用户定义的异常处理

5.2 异常错误传播

5.2.1 在执行部分引发异常错误

5.2.2 在声明部分引发异常错误

5.3 异常错误处理编程

5.4  在 PL/SQL 中使用 SQLCODE, SQLERRM异常处理函数

 


 

 

即使是写得最好的PL/SQL程序也会遇到错误或未预料到的事件。一个优秀的程序都应该能够正确处理各种出错情况,并尽可能从错误中恢复。任何ORACLE错误(报告为ORA-xxxxx形式的Oracle错误号)、PL/SQL运行错误或用户定义条件(不一写是错误),都可以。当然了,PL/SQL编译错误不能通过PL/SQL异常处理来处理,因为这些错误发生在PL/SQL程序执行之前。

ORACLE 提供异常情况(EXCEPTION)和异常处理(EXCEPTION HANDLER)来实现错误处理。

5.1 异常处理概念

异常情况处理(EXCEPTION)是用来处理正常执行过程中未预料的事件,程序块的异常处理预定义的错误和自定义错误,由于PL/SQL程序块一旦产生异常而没有指出如何处理时,程序就会自动终止整个程序运行.

有三种类型的异常错误:

    1. 预定义 ( Predefined )错误

  ORACLE预定义的异常情况大约有24个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发。

    2. 非预定义 ( Predefined )错误

   即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发。

    3. 用户定义(User_define) 错误

程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其引发。

异常处理部分一般放在 PL/SQL 程序体的后半部,结构为:

EXCEPTION
   WHEN first_exception THEN  <code to handle first exception >
   WHEN second_exception THEN  <code to handle second exception >
   WHEN OTHERS THEN  <code to handle others exception >
END;
 

异常处理可以按任意次序排列,但 OTHERS 必须放在最后.

5.1.1 预定义的异常处理

   预定义说明的部分 ORACLE 异常错误

错误号

异常错误信息名称

说明

ORA-0001

Dup_val_on_index

违反了唯一性限制

ORA-0051

Timeout-on-resource

在等待资源时发生超时

ORA-0061

Transaction-backed-out

由于发生死锁事务被撤消

ORA-1001

Invalid-CURSOR

试图使用一个无效的游标

ORA-1012

Not-logged-on

没有连接到ORACLE

ORA-1017

Login-denied

无效的用户名/口令

ORA-1403

No_data_found

SELECT INTO没有找到数据

ORA-1422

Too_many_rows

SELECT INTO 返回多行

ORA-1476

Zero-divide

试图被零除

ORA-1722

Invalid-NUMBER

转换一个数字失败

ORA-6500

Storage-error

内存不够引发的内部错误

ORA-6501

Program-error

内部错误

ORA-6502

Value-error

转换或截断错误

ORA-6504

Rowtype-mismatch

宿主游标变量与 PL/SQL变量有不兼容行类型

ORA-6511

CURSOR-already-OPEN

试图打开一个已处于打开状态的游标

ORA-6530

Access-INTO-null

试图为null 对象的属性赋值

ORA-6531

Collection-is-null

试图将Exists 以外的集合( collection)方法应用于一个null pl/sql 表上或varray上

ORA-6532

Subscript-outside-limit

对嵌套或varray索引得引用超出声明范围以外

ORA-6533

Subscript-beyond-count

对嵌套或varray 索引得引用大于集合中元素的个数.

对这种异常情况的处理,只需在PL/SQL块的异常处理部分,直接引用相应的异常情况名,并对其完成相应的异常错误处理即可。

例1:更新指定员工工资,如工资小于1500,则加100;

 

DECLARE
   v_empno employees.employee_id%TYPE := &empno;
   v_sal   employees.salary%TYPE;
BEGIN
   SELECT salary INTO v_sal FROM employees WHERE employee_id = v_empno;
   IF v_sal<=1500 THEN 
        UPDATE employees SET salary = salary + 100 WHERE employee_id=v_empno; 
        DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已更新!');     
   ELSE
        DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已经超过规定值!');
   END IF;
EXCEPTION
   WHEN NO_DATA_FOUND THEN  
      DBMS_OUTPUT.PUT_LINE('数据库中没有编码为'||v_empno||'的员工');
   WHEN TOO_MANY_ROWS THEN
      DBMS_OUTPUT.PUT_LINE('程序运行错误!请使用游标');
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
 

5.1.2 非预定义的异常处理

对于这类异常情况的处理,首先必须对非定义的ORACLE错误进行定义。步骤如下:

1. 在PL/SQL 块的定义部分定义异常情况:

<异常情况>  EXCEPTION;

2. 将其定义好的异常情况,与标准的ORACLE错误联系起来,使用EXCEPTION_INIT语句:

PRAGMA EXCEPTION_INIT(<异常情况>, <错误代码>);

3. 在PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。

例2:删除指定部门的记录信息,以确保该部门没有员工。

INSERT INTO departments VALUES(50, 'FINANCE', 'CHICAGO');

DECLARE
   v_deptno departments.department_id%TYPE := &deptno;
   deptno_remaining EXCEPTION;
   PRAGMA EXCEPTION_INIT(deptno_remaining, -2292);
   /* -2292 是违反一致性约束的错误代码 */
BEGIN
   DELETE FROM departments WHERE department_id = v_deptno;
EXCEPTION
   WHEN deptno_remaining THEN 
      DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
 

5.1.3 用户自定义的异常处理

当与一个异常错误相关的错误出现时,就会隐含触发该异常错误。用户定义的异常错误是通过显式使用 RAISE 语句来触发。当引发一个异常错误时,控制就转向到 EXCEPTION块异常错误部分,执行错误处理代码。

对于这类异常情况的处理,步骤如下:

1. 在PL/SQL 块的定义部分定义异常情况:

<异常情况>  EXCEPTION;

2. RAISE <异常情况>;

3. 在PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。

例3:更新指定员工工资,增加100;

DECLARE
   v_empno employees.employee_id%TYPE :=&empno;
   no_result  EXCEPTION;
BEGIN
   UPDATE employees SET salary = salary+100 WHERE employee_id = v_empno;
   IF SQL%NOTFOUND THEN
      RAISE no_result;
   END IF;
EXCEPTION
   WHEN no_result THEN 
      DBMS_OUTPUT.PUT_LINE('你的数据更新语句失败了!');
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
 

5.1.4  用户定义的异常处理

调用DBMS_STANDARD(ORACLE提供的包)包所定义的RAISE_APPLICATION_ERROR过程,可以重新定义异常错误消息,它为应用程序提供了一种与ORACLE交互的方法。

RAISE_APPLICATION_ERROR 的语法如下:

    RAISE_APPLICATION_ERROR(error_number,error_message,[keep_errors] );

    这里的error_number 是从 –20,000 到 –20,999 之间的参数,

    error_message 是相应的提示信息(< 2048 字节),

keep_errors 为可选,如果keep_errors =TRUE ,则新错误将被添加到已经引发的错误列表中。如果keep_errors=FALSE(缺省),则新错误将替换当前的错误列表。

例4:创建一个函数get_salary, 该函数检索指定部门的工资总和,其中定义了-20991和-20992号错误,分别处理参数为空和非法部门代码两种错误:

CREATE TABLE errlog(
  Errcode NUMBER,
  Errtext CHAR(40));

CREATE OR REPLACE FUNCTION get_salary(p_deptno NUMBER)
RETURN NUMBER 
AS
  v_sal NUMBER;
BEGIN
  IF p_deptno IS NULL THEN
    RAISE_APPLICATION_ERROR(-20991, ’部门代码为空’);
  ELSIF p_deptno<0 THEN
    RAISE_APPLICATION_ERROR(-20992, ’无效的部门代码’);
  ELSE
    SELECT SUM(employees.salary) INTO v_sal FROM employees 
    WHERE employees.department_id=p_deptno;
    RETURN v_sal;
  END IF;
END;

DECLARE 
  V_salary NUMBER(7,2);
  V_sqlcode NUMBER;
  V_sqlerr VARCHAR2(512);
  Null_deptno EXCEPTION;
  Invalid_deptno EXCEPTION;
  PRAGMA EXCEPTION_INIT(null_deptno,-20991);
  PRAGMA EXCEPTION_INIT(invalid_deptno, -20992);
BEGIN
  V_salary :=get_salary(10);
  DBMS_OUTPUT.PUT_LINE('10号部门工资:' || TO_CHAR(V_salary));

  BEGIN
    V_salary :=get_salary(-10);
  EXCEPTION
    WHEN invalid_deptno THEN
      V_sqlcode :=SQLCODE;
      V_sqlerr  :=SQLERRM;
      INSERT INTO errlog(errcode, errtext) 
      VALUES(v_sqlcode, v_sqlerr);
      COMMIT;
  END inner1;

  V_salary :=get_salary(20);
  DBMS_OUTPUT.PUT_LINE('部门号为20的工资为:'||TO_CHAR(V_salary));

  BEGIN
    V_salary :=get_salary(NULL);
  END inner2;

  V_salary := get_salary(30);
  DBMS_OUTPUT.PUT_LINE('部门号为30的工资为:'||TO_CHAR(V_salary));

  EXCEPTION
    WHEN null_deptno THEN
      V_sqlcode :=SQLCODE;
      V_sqlerr  :=SQLERRM;
      INSERT INTO errlog(errcode, errtext) VALUES(v_sqlcode, v_sqlerr);
      COMMIT;
    WHEN OTHERS THEN
         DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END outer;
 

例5:定义触发器,使用RAISE_APPLICATION_ERROR阻止没有员工姓名的新员式记录插入:

CREATE OR REPLACE TRIGGER tr_insert_emp
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
  IF :new.first_name IS NULL OR :new.last_name is null THEN
    RAISE_APPLICATION_ERROR(-20000,'Employee must have a name.');
  END IF;
END;
 

5.2 异常错误传播

    由于异常错误可以在声明部分和执行部分以及异常错误部分出现,因而在不同部分引发的异常错误也不一样。

5.2.1 在执行部分引发异常错误

    当一个异常错误在执行部分引发时,有下列情况:

l 如果当前块对该异常错误设置了处理,则执行它并成功完成该块的执行,然后控制转给包含块。

l 如果没有对当前块异常错误设置定义处理器,则通过在包含块中引发它来传播异常错误。然后对该包含块执行步骤1)。

5.2.2 在声明部分引发异常错误

    如果在声明部分引起异常情况,即在声明部分出现错误,那么该错误就能影响到其它的块。比如在有如下的PL/SQL程序:

DECLARE
    name varchar2(12):='EricHu';
    其它语句
BEGIN
    其它语句
EXCEPTION
    WHEN OTHERS THEN 
    其它语句
END;
 

     例子中,由于Abc number(3)=’abc’; 出错,尽管在EXCEPTION中说明了WHEN OTHERS THEN语句,但WHEN OTHERS THEN也不会被执行。 但是如果在该错误语句块的外部有一个异常错误,则该错误能被抓住,如:

BEGIN
    DECLARE
    name varchar2(12):='EricHu';
    其它语句
   BEGIN
    其它语句
   EXCEPTION
    WHEN OTHERS THEN 
    其它语句
    END;
EXCEPTION
WHEN OTHERS THEN 
    其它语句
END;
 

5.3 异常错误处理编程

    在一般的应用处理中,建议程序人员要用异常处理,因为如果程序中不声明任何异常处理,则在程序运行出错时,程序就被终止,并且也不提示任何信息。下面是使用系统提供的异常来编程的例子。

5.4  在 PL/SQL 中使用 SQLCODE, SQLERRM异常处理函数

    由于ORACLE 的错信息最大长度是512字节,为了得到完整的错误提示信息,我们可用 SQLERRM和 SUBSTR 函数一起得到错误提示信息,方便进行错误,特别是如果WHEN OTHERS异常处理器时更为方便。

SQLCODE  返回遇到的Oracle错误号,

SQLERRM  返回遇到的Oracle错误信息.

如:  SQLCODE=-100   è SQLERRM=’no_data_found ‘

SQLCODE=0      è SQLERRM=’normal, successfual completion’

例6. 将ORACLE错误代码及其信息存入错误代码表

CREATE TABLE errors (errnum NUMBER(4), errmsg VARCHAR2(100));

DECLARE
   err_msg  VARCHAR2(100);
BEGIN
   /*  得到所有 ORACLE 错误信息  */
   FOR err_num IN -100 .. 0 LOOP
      err_msg := SQLERRM(err_num);
      INSERT INTO errors VALUES(err_num, err_msg);
   END LOOP;
END;
DROP TABLE errors;
 

例7. 查询ORACLE错误代码;

BEGIN
   INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)
   VALUES(2222, 'Eric','Hu', SYSDATE, 20);
   DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');
   
   INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)
   VALUES(2222, '胡','勇', SYSDATE, 20);
   DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');
EXCEPTION
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;

例8. 利用ORACLE错误代码,编写异常错误处理代码;

DECLARE
   empno_remaining EXCEPTION;
   PRAGMA EXCEPTION_INIT(empno_remaining, -1);
   /* -1 是违反唯一约束条件的错误代码 */
BEGIN
   INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)
   VALUES(3333, 'Eric','Hu', SYSDATE, 20);
   DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');
   
   INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)
   VALUES(3333, '胡','勇',SYSDATE, 20);
   DBMS_OUTPUT.PUT_LINE('插入数据记录成功!');
EXCEPTION
   WHEN empno_remaining THEN 
      DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
 

1、异常的优点 
   
  如果没有异常,在程序中,应当检查每个命令的成功还是失败,如 
  BEGIN 
  SELECT ... 
  -- check for ’no data found’ error 
  SELECT ... 
  -- check for ’no data found’ error 
  SELECT ... 
  -- check for ’no data found’ error 
  这种实现的方法缺点在于错误处理没有与正常处理分开,可读性差,使用异常,可以方便处理错误,而且异常处理程序与正常的事务逻辑分开,提高了可读性,如 
  BEGIN 
  SELECT ... 
  SELECT ... 
  SELECT ... 
  ... 
  EXCEPTION 
  WHEN NO_DATA_FOUND THEN -- catches all ’no data found’ errors 
   
  2、异常的分类 
   
  有两种类型的异常,一种为内部异常,一种为用户自定义异常,内部异常是执行期间返回到PL/SQL块的ORACLE错误或由PL/SQL代码的某操作引起的错误,如除数为零或内存溢出的情况。用户自定义异常由开发者显示定义,在PL/SQL块中传递信息以控制对于应用的错误处理。 
   
  每当PL/SQL违背了ORACLE原则或超越了系统依赖的原则就会隐式的产生内部异常。因为每个ORACLE错误都有一个号码并且在PL/SQL中异常通过名字处理,ORACLE提供了预定义的内部异常。如SELECT INTO 语句不返回行时产生的ORACLE异常NO_DATA_FOUND。对于预定义异常,现将最常用的异常列举如下: 
  exception  oracle error  sqlcode value  condition 
  no_data_found              ora-01403  +100  select into 语句没有符合条件的记录返回 
  too_many_rows  ora-01422  -1422  select into 语句符合条件的记录有多条返回 
  dup_val_on_index  ora-00001  -1  对于数据库表中的某一列,该列已经被限制为唯一索引,程序试图存储两个重复的值 
  value_error  ora-06502  -6502  在转换字符类型,截取或长度受限时,会发生该异常,如一个字符分配给一个变量,而该变量声明的长度比该字符短,就会引发该异常 
  storage_error  ora-06500  -6500  内存溢出 
  zero_divide  ora-01476  -1476  除数为零 
  case_not_found  ora-06592  -6530  对于选择case语句,没有与之相匹配的条件,同时,也没有else语句捕获其他的条件 
  cursor_already_open  ora-06511  -6511  程序试图打开一个已经打开的游标 
  timeout_on_resource  ora-00051  -51  系统在等待某一资源,时间超时 
   
  如果要处理未命名的内部异常,必须使用OTHERS异常处理器或PRAGMA EXCEPTION_INIT 。PRAGMA由编译器控制,或者是对于编译器的注释。PRAGMA在编译时处理,而不是在运行时处理。EXCEPTION_INIT告诉编译器将异常名与ORACLE错误码结合起来,这样可以通过名字引用任意的内部异常,并且可以通过名字为异常编写一适当的异常处理器。 
   
  在子程序中使用EXCEPTION_INIT的语法如下: 
  PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number); 
   
  在该语法中,异常名是声明的异常,下例是其用法: 
  DECLARE 
  deadlock_detected EXCEPTION; 
  PRAGMA EXCEPTION_INIT(deadlock_detected, -60); 
  BEGIN 
  ... -- Some operation that causes an ORA-00060 error 
  EXCEPTION 
  WHEN deadlock_detected THEN 
  -- handle the error 
  END; 
   
  对于用户自定义异常,只能在PL/SQL块中的声明部分声明异常,异常的名字由EXCEPTION关键字引入: 
  reserved_loaned Exception 
   
  产生异常后,控制传给了子程序的异常部分,将异常转向各自异常控制块,必须在代码中使用如下的结构处理错误: 
  Exception 
  When exception1 then 
  Sequence of statements; 
  When exception2 then 
  Sequence of statements; 
  When others then 
   
  3、异常的抛出 
   
  由三种方式抛出异常 
   
  1. 通过PL/SQL运行时引擎 
   
  2. 使用RAISE语句 
   
  3. 调用RAISE_APPLICATION_ERROR存储过程 
   
  当数据库或PL/SQL在运行时发生错误时,一个异常被PL/SQL运行时引擎自动抛出。异常也可以通过RAISE语句抛出 
  RAISE exception_name; 
   
  显式抛出异常是程序员处理声明的异常的习惯用法,但RAISE不限于声明了的异常,它可以抛出任何任何异常。例如,你希望用TIMEOUT_ON_RESOURCE错误检测新的运行时异常处理器,你只需简单的在程序中使用下面的语句: 
  RAISE TIMEOUT_ON_RESOUCE; 
   
  比如下面一个订单输入的例子,若当订单小于库存数量,则抛出异常,并且捕获该异常,处理异常 
  DECLARE 
  inventory_too_low EXCEPTION; 
   
  ---其他声明语句 
  BEGIN 
  IF order_rec.qty>inventory_rec.qty THEN 
  RAISE inventory_too_low; 
  END IF 
  EXCEPTION 
  WHEN inventory_too_low THEN 
  order_rec.staus:='backordered'; 
  END; 
   
  RAISE_APPLICATION_ERROR内建函数用于抛出一个异常并给异常赋予一个错误号以及错误信息。自定义异常的缺省错误号是+1,缺省信息是User_Defined_Exception。RAISE_APPLICATION_ERROR函数能够在pl/sql程序块的执行部分和异常部分调用,显式抛出带特殊错误号的命名异常。  Raise_application_error(error_number,message[,true,false])) 
   
  错误号的范围是-20,000到-20,999。错误信息是文本字符串,最多为2048字节。TRUE和FALSE表示是添加(TRUE)进错误堆(ERROR STACK)还是覆盖(overwrite)错误堆(FALSE)。缺省情况下是FALSE。 
   
  如下代码所示: 
  IF product_not_found THEN 
  RAISE_APPLICATION_ERROR(-20123,'Invald product code' TRUE); 
  END IF; 
   
  4、异常的处理 
   
  PL/SQL程序块的异常部分包含了程序处理错误的代码,当异常被抛出时,一个异常陷阱就自动发生,程序控制离开执行部分转入异常部分,一旦程序进入异常部分就不能再回到同一块的执行部分。下面是异常部分的一般语法: 
  EXCEPTION 
  WHEN exception_name THEN 
  Code for handing exception_name 
  [WHEN another_exception THEN 
  Code for handing another_exception] 
  [WHEN others THEN 
  code for handing any other exception.] 
   
  用户必须在独立的WHEN子串中为每个异常设计异常处理代码,WHEN OTHERS子串必须放置在最后面作为缺省处理器处理没有显式处理的异常。当异常发生时,控制转到异常部分,ORACLE查找当前异常相应的WHEN..THEN语句,捕捉异常,THEN之后的代码被执行,如果错误陷阱代码只是退出相应的嵌套块,那么程序将继续执行内部块END后面的语句。如果没有找到相应的异常陷阱,那么将执行WHEN OTHERS。在异常部分WHEN 子串没有数量限制。 
  EXCEPTION 
  WHEN inventory_too_low THEN 
  order_rec.staus:='backordered'; 
  replenish_inventory(inventory_nbr=> 
  inventory_rec.sku,min_amount=>order_rec.qty-inventory_rec.qty); 
  WHEN discontinued_item THEN 
  --code for discontinued_item processing 
  WHEN zero_divide THEN 
  --code for zero_divide 
  WHEN OTHERS THEN 
  --code for any other exception 
  END; 
   
  当异常抛出后,控制无条件转到异常部分,这就意味着控制不能回到异常发生的位置,当异常被处理和解决后,控制返回到上一层执行部分的下一条语句。 
  BEGIN 
  DECLARE 
  bad_credit exception; 
  BEGIN 
  RAISE bad_credit; 
  --发生异常,控制转向; 
  EXCEPTION 
  WHEN bad_credit THEN 
  dbms_output.put_line('bad_credit'); 
  END; 
  --bad_credit异常处理后,控制转到这里 
  EXCEPTION 
  WHEN OTHERS THEN 
   
  --控制不会从bad_credit异常转到这里 
   
  --因为bad_credit已被处理 
   
  END; 
   
  当异常发生时,在块的内部没有该异常处理器时,控制将转到或传播到上一层块的异常处理部分。 
   
  BEGIN 
  DECLARE ---内部块开始 
   
  bad_credit exception; 
  BEGIN 
  RAISE bad_credit; 
   
  --发生异常,控制转向; 
  EXCEPTION 
  WHEN ZERO_DIVIDE THEN --不能处理bad_credite异常 
  dbms_output.put_line('divide by zero error'); 
   
  END --结束内部块 
   
  --控制不能到达这里,因为异常没有解决; 
   
  --异常部分 
   
  EXCEPTION 
  WHEN OTHERS THEN 
  --由于bad_credit没有解决,控制将转到这里 
  END; 
   
  5、异常的传播 
   
  没有处理的异常将沿检测异常调用程序传播到外面,当异常被处理并解决或到达程序最外层传播停止。在声明部分抛出的异常将控制转到上一层的异常部分。 
   
  BEGIN 
  executable statements 
  BEGIN 
  today DATE:='SYADATE'; --ERRROR 
   
  BEGIN --内部块开始 
  dbms_output.put_line('this line will not execute'); 
  EXCEPTION 
  WHEN OTHERS THEN 
   
  --异常不会在这里处理 
   
  END;--内部块结束 
  EXCEPTION 
  WHEN OTHERS THEN 
   
  处理异常 
   
  END 

 

-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------

 

处理 oracle 系统自动生成系统异常外,可以使用 raise 来手动生成错误。

l         Raise exception;

l         Raise package.exception;

l         Raise;

以上是 raise 的三种使用方法。第一种用于生成当前程序中定义的异常或在 standard 中的系统异常。

       Declare

              Invalid_id exception;

              Id_values varchar(2);

       Begin

              Id_value:=id_for(‘smith’);

              If substr(id_value,1,1)!=’x’

              Then

                     Raise invalid_id;

              End if;

       Exception

              When invalid_id

              Then

                     Dbms_output.put_line(‘this is an invalid id!’);

       End;

这是一个生成自定义异常的例子,当然也可以生成系统异常:

       declare

              employee_id_in number;

       Begin

Select employee_id into employee_id_in from employ_list where employee_name=&n;

If employee_id_in=0

Then

       Raise zero_devided;

End if;

       Exception

              When zero_devided

              Then

                     Dbms_output.put_line(‘wrong!’);

       End;

有一些异常是定义在非标准包中的,如 UTL_FILE , DBMS_SQL 以及程序员创建的包中异常。可以使用 raise 的第二种用法来生成异常。

       If day_overdue(isbn_in, browser_in) > 365

       Then

              Raise overdue_pkg.book_is_lost

       End if;

在最后一种 raise 的形式中,不带任何参数。这种情况只出现在希望将当前的异常传到外部程序时。

       Exception

              When no_data_found

              Then

                     Raise;

       End;

 

Pl.sql 使用 raise_application_error 过程来生成一个有具体描述的异常。当使用这个过程时,当前程序被中止,输入输出参数被置为原先的值,但任何 DML 对数据库所做的改动将被保留,可以在之后用 rollback 命令回滚。下面是该过程的原型:

       Procedure raise_application_error(

       Num binary_integer;

       Msg varchar2;

       Keeperrorstack Boolean default false

)

其中 num 是在 -20999 到 -20000 之间的任何数字(但事实上, DBMS_OUPUT 和 DBMS_DESCRIBLE 包使用了 -20005 到 -20000 的数字); msg 是小于 2K 个字符的描述语,任何大于 2K 的字符都将被自动丢弃; keeperrorstack 默认为 false ,是指清空异常栈,再将当前异常入栈,如果指定 true 的话就直接将当前异常压入栈中。

    CREATE OR REPLACE PROCEDURE raise_by_language (code_in IN PLS_INTEGER)

    IS

       l_message error_table.error_string%TYPE;

    BEGIN

       SELECT error_string

         INTO l_message

         FROM error_table, v$nls_parameters v

        WHERE error_number = code_in

          AND string_language = v.VALUE

          AND v.parameter = 'NLS_LANGUAGE';

 

       RAISE_APPLICATION_ERROR (code_in, l_message);

    END;

 

 

ORACL内部异常:

 

1:预定义异常 

用于处理常见的Oracle错误 

2:非预定义异常 

用于处理预定义异常所不能处理的Oracle错误 

3:自定义异常 

用于处理于Oracle错误无关的其他情况 

异常处理部分是以关键字EXCEPTION开始的,语法如下: 

  EXCEPTION 

    WHEN  exception_Name THEN  --exception_Name为异常的名字 

      statement1; 

    WHEN OTHERS THEN 

  statement1; 

异常处理部分从关键字EXCEPTION开始,在异常处理部分使用WHEN字句捕捉各种异常,如果有其他未预定义到的异常,使用WHEN OTHERS THEN字句进行捕捉和处理。 

 

  • 1、 处理预定义异常,这是系统预定的21种类型 
  •   错误代码是负整数,如-51 
  •       
  •  
  •     
  •   Access_info_null(ora-06530) 
  •      当访问没有初始化的对象时触发。 
  •     
  •   Case_not_found(ora-06592) 
  •      case过程中when后没有包含必要的条件分支并且没有else子句,则会触发本异常。 
  •     
  •   Collection_is_null(06531) 
  • 访问未初始化的集合元素(嵌套表或者varray)。
  •     
  •   Cursor_already_open(ora-06511) 
  •      重新打开已经打开的游标。 
  •     
  •   Dup_val_on_index(ora-00001) 
  •      当中唯一索引所对应的列上键入重复值时。 
  •     
  •   Invalid_cursor(ora-01001) 
  • 试图在不合法的游标上执行操作时,譬如没打开游标就提取内容
  •     
  •   Invalid_number(ora-01722) 
  •      当试图将非法的字符串转换为数字类型时。 
  •     
  •   No_data_found(ora-01403) 
  •      执行select into未返回行,或者引用了索引表未初始化的元素时。 
  •     
  •   Too_many_rows(ora-01422) 
  •      执行select into返回超过一行数据时。 
  •     
  •   Zero_divide(ora-01476) 
  •      0作为被除数时。 
  •     
  •   Subscript_beyond_count(ora-06533) 
  •      使用嵌套表或者varray集合时,如果引用下标超过last。 
  •     
  • Subscript_outside_limit(ora-06532)
  •      使用嵌套表或varray集合时,如果引用下标小于first。 
  •     
  •   Value_error(ora-06502) 
  •      在执行赋值操作时,如果变量长度不足以容纳实际数据。 
  •     
  •   Login_denied(ora-01017) 
  •      连接数据库时提供了不正确的用户名或口令。 
  •     
  •   Not_logged_on(ora-01012) 
  • 在程序没有连接到oracle数据库时执行plsql代码则会触发。
  •     
  •   Program_error(ora-06501) 
  •      plsql内部问题。 
  •     
  •   Rowtype_mismatch(ora-06504) 
  •      执行赋值操作时,如果宿主游标变量和PLSQL游标变量返回类型不兼容时。 
  •     
  •   Self_is_null(ora-30625) 
  •      使用对象类型时,如果在null实例上调用成员方法。 
  •     
  •   Storage_error(ora-06500) 
  •      超出内存空间或者内存被损坏。 
  •     
  •   Sys_invalid_rowid(ora-01410) 
  •      无效字符串企图转换为rowid类型时。 
  •     
  •   Timeout_on_resource(ora-00051) 
  •      等待资源时出现超时错误。 
  •     
  •  
  •  
  • 2、处理非预定义异常 
  • 使用非预定义异常包括三步: 
  • 一:在定义部分定义异常名, 
  • 二:在异常和Oracle错误之间建立关联, 
  • 三:在异常处理部分捕捉并处理异常。 
  •  
  •  
  • 当定义Oracle错误和异常之间的关联关系时,需要使用伪过程EXCEPTION_INIT。 
  •  
  •  
  • 一:首先的定义部分定义异常; 
  • 二:使用progmaexception_init(exception_name,exception_number) 在异常和oracle错误之间建立关联, 
  •     这时要求用户知道可能出现的错误号(异常函数sqlcode、sqlerrm和raise_application_error); 
  • 三:最终在异常处理部分捕捉并处理异常。 
  •  
  •   
  •  
  •  
  • 下面以更新特定雇员的部门号,并处理ORA-02291错误为例,说明使用非预定义异常的方法。示例如下: 
  •  
  •  
  •   DECLARE 
  •     e_integrity EXCEPTION;  --1、定义部分 
  •     PRAGMA EXCEPTION_INIT (e_integrity, -2291);  --2、建立关联关系 
  •   BEGIN 
  •     UPDATE  emp SET deptno=  &dno WHERE  empno = &eno; 
  •   EXCEPTION 
  •     WHEN  e_integrity THEN  --3、捕捉处理 
  •       DBMS_OUTPUT.PUT_LINE(‘该部门不存在’); 
  •   END; 
  •    
  •  
  •     
  • --3、处理自定义异常 
  • 预定义异常和非预定义异常都与Oracle错误有关,并且当出现Oracle错误时会隐含触发相应异常; 
  • 而自定义异常与Oracle错误没有任何关联,它是由开发人员为特定情况所定义的异常。 
  •  
  •  
  • 当使用自定义异常时, 
  • 一:需要在定义部分(DECLARE)定义异常, 
  • 二:再执行部分(BEGIN)触发异常(使用RAISE语句), 
  • 三:在异常处理部分(EXCEPTION)捕捉并处理异常。 
  •  
  •  
  •   declare 
  •    myexception exception; 
  •   begin 
  •    
  • if 
  • 1=0 
  • then 
  •    
  • raise myexception; 
  •    
  • endif;  
  •   exception 
  •    
  • when 
  •  
  • myexception  
  • then 
  •        dbms_output.put_line('asdf'); 
  •   end; 
  •     
  • 注意:不能在同一个block中描述EXCEPTION两次,但是可以描述一个exception在两个不同的block中。异常(exception)是有作用域的,子块的异常不能被当前块所捕捉, 
  •  
  •   
  •  
  • --4、使用异常函数: 
  • Oracle内置函数sqlcode和sqlerrm主要用在others处理器中,分别用来返回oracle的错误代码和错误消息。 
  • 一般情况下sqlcode返回负数标识的oracle错误代码,除非错误 
  • 为‘ora-01403:no data found’,此时对应的sqlcode为+100, 
  • 对于用户自定义的异常,sqlcode返回+1,如果没有异常被触发,sqlcode返回0。 
  •   Begin 
  •   Exception 
  •    When  others then 
  •       Dbms_output.put_line(sqlcode||sqlerrm(sqlcode)); 
  •   End; 
  •     
  •  
  •   
  •  
  •  
  • Oracle过程raise_application_error用于在plsql应用程序中自定义错误消息。 
  • 注意该过程只能在数据库端的子程序(过程、函数、包、触发器)中使用,而不能在匿名块和客户端的子程序中使用。 
  • 语法为raise_application_error(error_number,message[,[true|false]]); 
  • 其中 
  •  
  • error_number用于定义错误号,该错误号必须在-20000到-20999之间的负整数; 
  • message用于指定错误消息,并且该消息的长度不 
  • 能超过2048字节; 
  • 第三个参数如果为true,则该错误会被放在先前错误堆栈中,如果为false(默认值)则会替代先前所有错误。 
  •   IF product_not_found THEN 
  •                RAISE_APPLICATION_ERROR(-20123,'Invald product code'  TRUE); 
  •   END IF; 
  •     
  •  
  •   
  •  
  •  
  • --5、plsql编译警告: 
  • plsql警告可以分为四类: 
  • severe:用于 
  • 检查可能出现的不可预料或者错误结果,例如参数的别名问题; 
  • performance:用于检查可能引起的性能问题,例如执行insert操作时为 number列提供了varchar2类型数据; 
  • informational:用于检查子程序中的死代码; 
  • all:用于检查所有警告。 
  •  
  •  
  • 为了数据库可以在编 
  • 译plsql子程序时发出警告信息,需要设置初始化参数plsql_warnings。这个参数不仅可以在系统级或者会话级设置,也可以在alter procedure命令中设置。 
  •   Alter {system|session|procedure}  
  •   set plsql_warnings= 
  •    
  • ’{enable|disable:{all |performance|severe|informational}}’; 
  •     
  •  
  •  
  • 为了检查是否存在对应警告信息,必须先激活警告检查,然后重新编译子程序, 
  • 最后使用show errors命令显示警告错误。 
  •   create or  replace procedure  my_test 
  •   is 
  •   begin 
  •    if  1=0 then 
  •       dbms_output.put_line('test'); 
  •    endif;  
  •   end; 
  •   SQL>  alter procedure  my_test compile plsql_warnings = 'enable:all'; 
  •    
  •  
  •   Procedure altered 
  •    SQL>  show errors; 
  •   Errors for  PROCEDURE SYS.MY_TEST: 
  •    LINE/COL ERROR 
  •   --------  ------------------------- 
  •   10/5      PLW-06002: 无法执行的代码 
  •     
  •  
  •  
  • --6、定义Exception时要注意的一些事项 
  • 当异常发生时,在块的内部没有该异常处理器时,控制将转到或传播到上一层块的异常处理部分。 
  • 没有处理的异常将沿检测异常调用程序传播到外层,当异常被处理并解决或到达程序最外层传播停止。在声明部分抛出的异常将控制转到上一层的异常部分。 
  •  
  •  
  • 用户必须在独立的WHEN子串中为每个异常设计异常处理代码,WHEN OTHERS子串必须放置在最后面作为缺省处理器处理没有显式处理的异常。当异常发生时,控制转到异常部分,ORACLE查找当前异常相应的WHEN..THEN语句,捕捉异常,THEN之后的代码被执行,如果错误陷阱代码只是退出相应的嵌套块,那么程序将继续执行内部块END后面的语句。如果没有找到相应的异常陷阱,那么将执行WHEN OTHERS。在异常部分WHEN 子串没有数量限制。 
  •   EXCEPTION 
  •    
  • WHEN inventory_too_low THEN 
  •    
  •       ...... 
  •    
  • WHEN discontinued_item THEN 
  •    
  •       ...... 
  •    
  • WHEN zero_divide THEN 
  •    
  •       ...... 
  •    
  • WHEN OTHERS THEN 
  •    
  •       ......  
  •  
  •  
  • oracle预定义的异常列表 
  • 2008-10-30 16:06 
  • 命名的系统异常         产生原因  
  • ACCESS_INTO_NULL         未定义对象  
  • CASE_NOT_FOUND         CASE 中若未包含相应的 WHEN ,并且没有设置 ELSE 时  
  • COLLECTION_IS_NULL         集合元素未初始化  
  • CURSER_ALREADY_OPEN         游标已经打开  
  • DUP_VAL_ON_INDEX         唯一索引对应的列上有重复的值  
  • INVALID_CURSOR         在不合法的游标上进行操作  
  • INVALID_NUMBER         内嵌的 SQL 语句不能将字符转换为数字  
  • NO_DATA_FOUND         使用 select into 未返回行,或应用索引表未初始化的元素时  
  • TOO_MANY_ROWS         执行 select into 时,结果集超过一行  
  • ZERO_DIVIDE         除数为 0  
  • SUBSCRIPT_BEYOND_COUNT         元素下标超过嵌套表或 VARRAY 的最大值  
  • SUBSCRIPT_OUTSIDE_LIMIT         使用嵌套表或 VARRAY 时,将下标指定为负数  
  • VALUE_ERROR         赋值时,变量长度不足以容纳实际数据  
  • LOGIN_DENIED         PL/SQL 应用程序连接到 oracle 数据库时,提供了不正确的用户名或密码  
  • NOT_LOGGED_ON         PL/SQL 应用程序在没有连接 oralce 数据库的情况下访问数据  
  • PROGRAM_ERROR         PL/SQL 内部问题,可能需要重装数据字典& pl./SQL 系统包  
  • ROWTYPE_MISMATCH         宿主游标变量与 PL/SQL 游标变量的返回类型不兼容  
  • SELF_IS_NULL         使用对象类型时,在 null 对象上调用对象方法  
  • STORAGE_ERROR         运行 PL/SQL 时,超出内存空间  
  • SYS_INVALID_ID         无效的 ROWID 字符串  
  • TIMEOUT_ON_RESOURCE         Oracle 在等待资源时超时 
  •  
  • ============================================================= 
  •  
  • BEGIN 
  • 《PL/SQL块》; 
  • Exception 
  • when no_data_found then --没有找到数据 
  • 《响应命令》; 
  • when too_many_rows then --返回多行,隐式光标每次只能检索一行数据 
  • 《响应命令》; 
  • when invalid_number then --字符向数字转换失败 
  • 《响应命令》; 
  • when zero_divide then --被零除 
  • 《响应命令》; 
  • when dup_val_on_index then --向唯一索引中插入重复数据 
  • 《响应命令》; 
  • when invalid_cursor then --非法游标操作 
  • 《响应命令》; 
  • when value_error then --数字的,数据转换,截字符串或强制性的错误 
  • 《响应命令》; 
  • when others then --发生其它任何错误 
  • null; --选择一:什么也不做,就当错误没发生 
  • raise form_trigger_failure; --选择二:挂起当前程序 
  • END; 
  •  
  •  
  • 常用预定义例外 
  • EXCEPTION 
  • WHEN CURSOR_ALREADY_OPEN THEN -- ORA-06511 SQLCODE = -6511 游标已经打开 
  • ..WHEN DUP_VAL_ON_INDEX THEN -- ORA-00001 SQLCODE = -1 向唯一索引中插入重复数据 
  • ..WHEN INVALID_CURSOR THEN -- ORA-01001 SQLCODE = -1001 非法游标操作 
  • ..WHEN INVALID_NUMBER THEN -- ORA-01722 SQLCODE = -1722 字符向数字转换失败 
  • ..WHEN LOGIN_DENIED THEN -- ORA-01017 SQLCODE = -1017  
  •  
  • ..WHEN NO_DATA_FOUND THEN -- ORA-01403 SQLCODE = +100 没有找到数据 
  • ..WHEN NOT_LOGGED_ON THEN -- ORA-01012 SQLCODE = -1012  
  • ..WHEN PROGRAM_ERROR THEN -- ORA-06501 SQLCODE = -6501 程序错误 
  • ..WHEN STORAGE_ERROR THEN -- ORA-06500 SQLCODE = -6500 
  • ..WHEN TIMEOUT_ON_RESOURCE THEN -- ORA-00051 SQLCODE = -51 
  •  
  • ..WHEN TOO_MANY_ROWS THEN -- ORA-01422 SQLCODE = -1422 返回多行 
  • ..WHEN TRANSACTION_BACKED_OUT THEN -- ORA-00061 SQLCODE = -61 
  •  
  • ..WHEN VALUE_ERROR THEN -- ORA-06502 SQLCODE = -6502 数值转换错误 
  • ..WHEN ZERO_DIVIDE THEN -- ORA-01476 SQLCODE = -1476 被零除 
  • ..WHEN OTHERS THEN -- 其它任何错误的处理 
  • ..END;  

     

    ORA-00001: 违反唯一约束条件 (.) 
    ORA-00017: 请求会话以设置跟踪事件 
    ORA-00018: 超出最大会话数 
    ORA-00019: 超出最大会话许可数 
    ORA-00020: 超出最大进程数 () 
    ORA-00021: 会话附属于其它某些进程;无法转换会话 
    ORA-00022: 无效的会话 ID;访问被拒绝 
    ORA-00023: 会话引用进程私用内存;无法分离会话 
    ORA-00024: 单一进程模式下不允许从多个进程注册 
    ORA-00025: 无法分配  
    ORA-00026: 丢失或无效的会话 ID 
    ORA-00027: 无法删去当前会话 
    ORA-00028: 您的会话己被删去 
    ORA-00029: 会话不是用户会话 
    ORA-00030: 用户会话 ID 不存在。 
    ORA-00031: 标记要删去的会话 
    ORA-00032: 无效的会话移植口令 
    ORA-00033: 当前的会话具有空的移植口令 
    ORA-00034: 无法在当前 PL/SQL 会话中  
    ORA-00035: LICENSE_MAX_USERS 不能小于当前用户数 
    ORA-00036: 超过递归 SQL () 级的最大值 
    ORA-00037: 无法转换到属于不同服务器组的会话 
    ORA-00038: 无法创建会话: 服务器组属于其它用户 
    ORA-00050: 获取入队时操作系统出错 
    ORA-00051: 等待资源超时 
    ORA-00052: 超出最大入队资源数 () 
    ORA-00053: 超出最大入队数 
    ORA-00054: 资源正忙,要求指定 NOWAIT 
    ORA-00055: 超出 DML 锁的最大数 
    ORA-00056: 对象 '.' 上的 DDL 锁以不兼容模式挂起 
    ORA-00057: 超出临时表锁的最大数 
    ORA-00058: DB_BLOCK_SIZE 必须为才可安装此数据库 (非 ) 
    ORA-00059: 超出 DB_FILES 的最大值 
    ORA-00060: 等待资源时检测到死锁 
    ORA-00061: 另一个例程设置了不同的 DML_LOCKS 
    ORA-00062: 无法获得 DML 全表锁定;DML_LOCKS 为 0 
    ORA-00063: 超出 LOG_FILES 的最大数 
    ORA-00064: 对象过大以至无法分配在此 O/S (,) 
    ORA-00065: FIXED_DATE 的初始化失败 
    ORA-00066: LOG_FILES 为  但需要成为  才可兼容 
    ORA-00067: 值  对参数  无效;至少必须为  
    ORA-00068: 值  对参数  无效,必须在  和  之间 
    ORA-00069: 无法获得锁定 -- 禁用了表锁定 
    ORA-00070: 命令无效 
    ORA-00071: 进程号必须介于 1 和  之间 
    ORA-00072: 进程""不活动 
    ORA-00073: 命令  介于  和  个参数之间时使用 
    ORA-00074: 未指定进程 
    ORA-00075: 在此例程未找到进程 "" 
    ORA-00076: 未找到转储  
    ORA-00077: 转储  无效 
    ORA-00078: 无法按名称转储变量 
    ORA-00079: 未找到变量  
    ORA-00080: 层次  指定的全局区域无效 
    ORA-00081: 地址范围 [,) 不可读 
    ORA-00082:  的内存大小不在有效集合 [1], [2], [4] 之内 
    ORA-00083: 警告: 可能损坏映射的 SGA  
    ORA-00084: 全局区域必须为 PGA, SGA 或 UGA 
    ORA-00085: 当前调用不存在 
    ORA-00086: 用户调用不存在 
    ORA-00087: 命令无法在远程例程上执行 
    ORA-00088: 共享服务器无法执行命令 
    ORA-00089: ORADEBUG 命令中无效的例程号 
    ORA-00090: 未能将内存分配给群集数据库 ORADEBUG 命令 
    ORA-00091: LARGE_POOL_SIZE 至少必须为  
    ORA-00092: LARGE_POOL_SIZE 必须大于 LARGE_POOL_MIN_ALLOC 
    ORA-00093:  必须介于  和  之间 
    ORA-00094:  要求整数值 
    ORA-00096: 值  对参数  无效,它必须来自  之间 
    ORA-00097: 使用 Oracle SQL 特性不在 SQL92  级中 
    ORA-00099: 等待资源时发生超时,可能是 PDML 死锁所致 
    ORA-00100: 未找到数据 
    ORA-00101: 系统参数 DISPATCHERS 的说明无效 
    ORA-00102: 调度程序无法使用网络协议  
    ORA-00103: 无效的网络协议;供调度程序备用 
    ORA-00104: 检测到死锁;全部公用服务器已锁定等待资源 
    ORA-00105: 未配置网络协议  的调度机制 
    ORA-00106: 无法在连接到调度程序时启动/关闭数据库 
    ORA-00107: 无法连接到 ORACLE 监听器进程 
    ORA-00108: 无法设置调度程序以同步进行连接 
    ORA-00111: 由于服务器数目限制在 , 所以没有启动所有服务器 
    ORA-00112: 仅能创建多达  (最多指定) 个调度程序 
    ORA-00113: 协议名  过长 
    ORA-00114: 缺少系统参数 SERVICE_NAMES 的值 
    ORA-00115: 连接被拒绝;调度程序连接表已满 
    ORA-00116: SERVICE_NAMES 名过长 
    ORA-00117: 系统参数 SERVICE_NAMES 的值超出范围 
    ORA-00118: 系统参数 DISPATCHERS 的值超出范围 
    ORA-00119: 系统参数  的说明无效 
    ORA-00120: 未启用或安装调度机制 
    ORA-00121: 在缺少 DISPATCHERS 的情况下指定了 SHARED_SERVERS 
    ORA-00122: 无法初始化网络配置 
    ORA-00123: 空闲公用服务器终止 
    ORA-00124: 在缺少 MAX_SHARED_SERVERS 的情况下指定了 DISPATCHERS 
    ORA-00125: 连接被拒绝;无效的演示文稿 
    ORA-00126: 连接被拒绝;无效的重复 
    ORA-00127: 调度进程  不存在 
    ORA-00128: 此命令需要调度进程名 
    ORA-00129: 监听程序地址验证失败 '' 
    ORA-00130: 监听程序地址 '' 无效 
    ORA-00131: 网络协议不支持注册 '' 
    ORA-00132: 语法错误或无法解析的网络名称 '' 
    ORA-00150: 重复的事务处理 ID 
    ORA-00151: 无效的事务处理 ID 
    ORA-00152: 当前会话与请求的会话不匹配 
    ORA-00153: XA 库中的内部错误 
    ORA-00154: 事务处理监视器中的协议错误 
    ORA-00155: 无法在全局事务处理之外执行工作 
    ORA-00160: 全局事务处理长度  超出了最大值 () 
    ORA-00161: 事务处理的分支长度  非法 (允许的最大长度为 ) 
    ORA-00162: 外部 dbid 的长度  超出了最大值 () 
    ORA-00163: 内部数据库名长度  超出了最大值 () 
    ORA-00164: 在分布式事务处理中不允许独立的事务处理 
    ORA-00165: 不允许对远程操作进行可移植分布式自治转换 
    ORA-00200: 无法创建控制文件 
    ORA-00201: 控制文件版本  与 ORACLE 版本  不兼容 
    ORA-00202: 控制文件: '' 
    ORA-00203: 使用错误的控制文件 
    ORA-00204: 读控制文件时出错 (块 ,# 块 ) 
    ORA-00205: 标识控制文件出错,有关详情,请检查警告日志 
    ORA-00206: 写控制文件时出错 (块 ,# 块 ) 
    ORA-00207: 控制文件不能用于同一数据库 
    ORA-00208: 控制文件的名称数超出限制  
    ORA-00209: 控制文件块大小不匹配,有关详情,请检查警告日志 
    ORA-00210: 无法打开指定的控制文件 
    ORA-00211: 控制文件与先前的控制文件不匹配 
    ORA-00212: 块大小  低于要求的最小大小 ( 字节) 
    ORA-00213: 不能重新使用控制文件;原文件大小为 ,还需  
    ORA-00214: 控制文件 '' 版本  与文件 '' 版本  不一致 
    ORA-00215: 必须至少存在一个控制文件 
    ORA-00216: 无法重新调整从 8.0.2 移植的控制文件大小 
    ORA-00217: 从 9.0.1 进行移植无法重新调整控制文件的大小 
    ORA-00218: 控制文件的块大小  与 DB_BLOCK_SIZE () 不匹配 
    ORA-00219: 要求的控制文件大小  超出了允许的最大值  
    ORA-00220: 第一个例程未安装控制文件,有关详情,请检查警告日志 
    ORA-00221: 写入控制文件出错 
    ORA-00222: 操作将重新使用当前已安装控制文件的名称 
    ORA-00223: 转换文件无效或版本不正确 
    ORA-00224: 控制文件重设大小尝试使用非法记录类型 () 
    ORA-00225: 控制文件的预期大小  与实际大小  不同 
    ORA-00226: 备用控制文件打开时不允许进行操作 
    ORA-00227: 控制文件中检测到损坏的块: (块 ,# 块 ) 
    ORA-00228: 备用控制文件名长度超出了最大长度  
    ORA-00229: 操作不允许: 已挂起快照控制文件入队 
    ORA-00230: 操作不允许: 无法使用快照控制文件入队 
    ORA-00231: 快照控制文件未命名 
    ORA-00232: 快照控制文件不存在, 已损坏或无法读取 
    ORA-00233: 控制文件副本已损坏或无法读取 
    ORA-00234: 标识或打开快照或复制控制文件时出错 
    ORA-00235: 控制文件固定表因并发更新而不一致 
    ORA-00236: 快照操作不允许: 挂上的控制文件为备份文件 
    ORA-00237: 快照操作不允许: 控制文件新近创建 
    ORA-00238: 操作将重用属于数据库一部分的文件名 
    ORA-00250: 未启动存档器 
    ORA-00251: LOG_ARCHIVE_DUPLEX_DEST 不能是与字符串  相同的目的地 
    ORA-00252: 日志  在线程  上为空,无法存档 
    ORA-00253: 字符限制在  以内,归档目的字符串  超出此限制 
    ORA-00254: 存档控制字符串 '' 时出错 
    ORA-00255: 存档日志  (线程 , 序列 # ) 时出错 
    ORA-00256: 无法翻译归档目的字符串  
    ORA-00257: 存档器错误。在释放之前仅限于内部连接 
    ORA-00258: NOARCHIVELOG 模式下的人工存档必须标识日志 
    ORA-00259: 日志  (打开线程 ) 为当前日志,无法存档 
    ORA-00260: 无法找到联机日志序列  (线程 ) 
    ORA-00261: 正在存档或修改日志  (线程 ) 
    ORA-00262: 当前日志  (关闭线程 ) 无法切换 
    ORA-00263: 线程  没有需要存档的记录 
    ORA-00264: 不要求恢复 
    ORA-00265: 要求例程恢复,无法设置 ARCHIVELOG 模式 
    ORA-00266: 需要存档日志文件名 
    ORA-00267: 无需存档日志文件名 
    ORA-00268: 指定的日志文件不存在 '' 
    ORA-00269: 指定的日志文件为线程  的一部分 (非 ) 
    ORA-00270: 创建存档日志  时出错 
    ORA-00271: 没有需要存档的日志 
    ORA-00272: 写存档日志  时出错 
    ORA-00273: 未记录的直接加载数据的介质恢复 
    ORA-00274: 非法恢复选项  
    ORA-00275: 已经开始介质恢复 
    ORA-00276: CHANGE 关键字已指定但未给出更改编号 
    ORA-00277: UNTIL 恢复标志  的非法选项 
    ORA-00278: 此恢复不再需要日志文件 '' 
    ORA-00279: 更改  (在  生成) 对于线程  是必需的 
    ORA-00280: 更改  对于线程  是按序列 #  进行的 
    ORA-00281: 不能使用调度进程执行介质恢复 
    ORA-00282: UPI  调用不被支持,请使用 ALTER DATABASE RECOVER 
    ORA-00283: 恢复会话因错误而取消 
    ORA-00284: 恢复会话仍在进行 
    ORA-00285: TIME 未作为字符串常数给出 
    ORA-00286: 无可用成员,或成员无有效数据 
    ORA-00287: 未找到指定的更改编号  (在线程  中) 
    ORA-00288: 要继续恢复,请键入 ALTER DATABASE RECOVER CONTINUE 
    ORA-00289: 建议:  
    ORA-00290: 操作系统出现存档错误。请参阅下面的错误 
    ORA-00291: PARALLEL 选项要求数字值 
    ORA-00292: 未安装并行恢复功能 
    ORA-00293: 控制文件与重做日志不同步 
    ORA-00294: 无效的存档日志格式标识 '' 
    ORA-00295: 数据文件号  无效,必须介于 1 与  之间 
    ORA-00296: 已超出 RECOVER DATAFILE LIST 的最大文件数 () 
    ORA-00297: 必须在 RECOVER DATAFILE START 之前指定 RECOVER DATAFILE LIST 
    ORA-00298: 丢失或无效的 TIMEOUT 间隔 
    ORA-00299: 必须在数据文件  上使用文件级介质恢复 
    ORA-00300: 指定的重做日志块大小  非法 - 超出限制  
    ORA-00301: 添加日志文件 '' 时出错 - 无法创建文件 
    ORA-00302: 日志超出限制  
    ORA-00303: 无法处理多次中断的重做 
    ORA-00304: 请求的 INSTANCE_NUMBER 在使用中 
    ORA-00305: 日志  (线程 ) 不一致;属于另一个数据库 
    ORA-00306: 此数据库中的例程限制  
    ORA-00307: 请求的 INSTANCE_NUMBER 超出限制,最大为  
    ORA-00308: 无法打开存档日志 '' 
    ORA-00309: 日志属于错误的数据库 
    ORA-00310: 存档日志包含序列 ;要求序列  
    ORA-00311: 无法从存档日志读取标题 
    ORA-00312: 联机日志  线程 : '' 
    ORA-00313: 无法打开日志组  (线程 ) 的成员 
    ORA-00314: 日志  (线程 ),预计序号  与  不匹配 
    ORA-00315: 日志  (线程 ),标题中的线程 #  错误 
    ORA-00316: 日志  (线程 ),标题中的类型  不是日志文件 
    ORA-00317: 标题中的文件类型  不是日志文件 
    ORA-00318: 日志  (线程 ),预计文件大小  与  不匹配 
    ORA-00319: 日志  (线程 ) 具有错误的日志重置状态 
    ORA-00320: 无法从日志  (线程 ) 读取文件标题 
    ORA-00321: 日志  (线程 ),无法更新日志文件标题 
    ORA-00322: 日志  (线程 ) 不是当前副本 
    ORA-00323: 线程  的当前日志不可用而所有其它日志均需要存档 
    ORA-00324: 日志文件 '' 的翻译名 '' 太长, 字符超出  限制 
    ORA-00325: 已归档线程  的日志,标题中的线程 #  错误 
    ORA-00326: 日志在更改  开始,需要更早的更改  
    ORA-00327: 日志  (线程 ),实际大小  小于需要的  
    ORA-00328: 归档日志在更改  结束,需要稍后的更改  
    ORA-00329: 归档日志在更改  开始,需要更改  
    ORA-00330: 归档日志在更改  结束,需要更改  
    ORA-00331: 日志版本  与 ORACLE 版本  不兼容 
    ORA-00332: 归档日志过小 - 可能未完全归档 
    ORA-00333: 重做日志读取块  计数  出错 
    ORA-00334: 归档日志: '' 
    ORA-00335: 联机日志 : 没有此编号的日志,日志不存在 
    ORA-00336: 大小为  的日志文件块数小于最小  块数 
    ORA-00337: 日志文件 '' 不存在且未指定大小 
    ORA-00338: 日志  (线程 ) 比控制文件更新 
    ORA-00339: 归档日志未包含任何重做 
    ORA-00340: 处理联机日志  (线程 ) 时出现 I/O 错误 
    ORA-00341: 日志  (线程 ),标题中的日志 #  错误 
    ORA-00342: 归档日志在上一个 RESETLOGS 之前创建程序包 
    ORA-00343: 错误过多,已关闭日志成员 
    ORA-00344: 无法重新创建联机日志 '' 
    ORA-00345: 重做日志写入块  计数  出错 
    ORA-00346: 日志成员标记为 STALE 
    ORA-00347: 日志  (线程 ),预计块大小  与  不匹配 
    ORA-00348: 单一进程重做失败;必须中止例程 
    ORA-00349: 无法获得 '' 的块大小 
    ORA-00350: 日志  (线程 ) 中需要归档 
    ORA-00351: recover-to 时间无效 
    ORA-00352: 线程  的所有日志均需要归档 - 无法启用 
    ORA-00353: 日志损坏接近块  更改  时间  
    ORA-00354: 损坏重做日志块标题 
    ORA-00355: 更改编号无次序 
    ORA-00356: 更改说明中的长度不一致 
    ORA-00357: 日志文件指定了过多成员,最大为  
    ORA-00358: 指定了过多文件成员,最大为  
    ORA-00359: 日志文件组  不存在 
    ORA-00360: 非日志文件成员:  
    ORA-00361: 无法删除最后一个日志成员  (组 ) 
    ORA-00362: 组成组  中的有效日志文件要求输入成员 
    ORA-00363: 日志不是归档版本 
    ORA-00364: 无法将标题写入新日志成员 
    ORA-00365: 指定日志不是正确的下一个日志 
    ORA-00366: 日志  (线程 ),文件标题中的校验和错误 
    ORA-00367: 日志文件标题中的校验和错误 
    ORA-00368: 重做日志块中的校验和错误 
    ORA-00369: 线程  的当前日志不可用且其它日志已被清除 
    ORA-00370: Rcbchange 操作过程中可能出现死锁 
    ORA-00371: 共享池内存不足 
    ORA-00372: 此时无法修改文件  
    ORA-00373: 联机日志版本  与 ORACLE 版本  不兼容 
    ORA-00374: 参数 db_block_size =  无效; 它必须是  的倍数, 范围为 [..] 
    ORA-00375: 无法获得默认 db_block_size 
    ORA-00376: 此时无法读取文件  
    ORA-00377: 文件  的频繁备份导致写操作延迟 
    ORA-00378: 无法按指定创建缓冲池 
    ORA-00379: 缓冲池  中无法提供 K 块大小的空闲缓冲区 
    ORA-00380: 无法指定 db_k_cache_size, 因为 K 是标准块大小 
    ORA-00381: 无法将新参数和旧参数同时用于缓冲区高速缓存的大小说明 
    ORA-00382:  不是有效的块大小, 有效范围为 [..] 
    ORA-00383: DEFAULT 高速缓存的块大小  不能减少至零 
    ORA-00384: 没有足够的内存来增加高速缓存的大小 
    ORA-00385: cannot enable Very Large Memory with new buffer cache parameters 
    ORA-00390: 日志  (线程 ) 正被清除,无法成为当前日志 
    ORA-00391: 所有线程必须同时转换为新的日志格式 
    ORA-00392: 日志  (线程 ) 正被清除,不允许操作 
    ORA-00393: 脱机数据文件的恢复需要日志  (线程 ) 
    ORA-00394: 在尝试存档时重新使用联机日志 
    ORA-00395: '克隆' 数据库的联机日志必须重命名 
    ORA-00396: 错误  需要退回到单次遍历恢复 
    ORA-00397: 对于文件  (块 ), 检测到写入丢失情况 
    ORA-00398: 由于重新配置而中止了线程恢复 
    ORA-00399: 重做日志中的更改说明已损坏 
    ORA-00400: 无效的版本值  (对于参数 ) 
    ORA-00401: 此版本不支持参数  的值 
    ORA-00402: 版本  的数据库更改无法用于版本  
    ORA-00403:  () 不同于其它例程 () 
    ORA-00404: 未找到转换文件: '' 
    ORA-00405: 兼容类型"" 
    ORA-00406: COMPATIBLE 参数需要为  或更大 
    ORA-00407: 不允许从版本 . 到 . 滚动升级 
    ORA-00408: 参数  设置为 TRUE 
    ORA-00409: COMPATIBLE 必须是  或更高值才能使用 AUTO SEGMENT SPACE MANAGEMENT 
    ORA-00436: 没有 ORACLE 软件使用权,请与 Oracle 公司联系获得帮助 
    ORA-00437: 没有 ORACLE 软件功能使用权,请与 Oracle 公司联系获得帮助 
    ORA-00438: 未安装  选项 
    ORA-00439: 未启用特性:  
    ORA-00443: 背景进程 "" 未启动 
    ORA-00444: 背景进程 "" 启动时失败 
    ORA-00445: 背景进程 "" 在  秒之后仍没有启动 
    ORA-00446: 背景进程意外启动 
    ORA-00447: 背景进程出现致命错误 
    ORA-00448: 背景进程正常结束 
    ORA-00449: 背景进程 '' 因错误  异常终止 
    ORA-00470: LGWR 进程因错误而终止 
    ORA-00471: DBWR 进程因错误而终止 
    ORA-00472: PMON 进程因错误而终止 
    ORA-00473: ARCH 进程因错误而终止 
    ORA-00474: SMON 进程因错误而终止 
    ORA-00475: TRWR 进程因错误而终止 
    ORA-00476: RECO 进程因错误而终止 
    ORA-00477: SNP* 进程因错误而终止 
    ORA-00478: SMON 进程由于  错误终止 
    ORA-00480: LCK* 进程因错误而终止 
    ORA-00481: LMON 进程因错误而终止 
    ORA-00482: LMD* 进程因错误而终止 
    ORA-00483: 关闭进程过程中异常终止 
    ORA-00484: LMS* 进程因错误而终止 
    ORA-00485: DIAG 进程由于  错误终止 
    ORA-00486: 功能不可用 
    ORA-00568: 超出中断处理程序的最大数 
    ORA-00574: osndnt: $CANCEL 失败 (中断) 
    ORA-00575: osndnt: $QIO 失败 (发送 out-of-band 中断) 
    ORA-00576: 带内中断协议错误 
    ORA-00577: 带外中断协议错误 
    ORA-00578: 重置协议错误 
    ORA-00579: osndnt: 服务器收到连接请求格式不正确 
    ORA-00580: 协议版本不匹配 
    ORA-00581: osndnt: 无法分配上下文区域 
    ORA-00582: osndnt: 无法撤消分配上下文区域 
    ORA-00583: osndnt: $TRNLOG 失败 
    ORA-00584: 无法关闭连接 
    ORA-00585: 主机名称格式错误 
    ORA-00586: osndnt: LIB$ASN_WTH_MBX 失败 
    ORA-00587: 无法连接到远程主机 
    ORA-00588: 来自主机的信息过短 
    ORA-00589: 来自主机的信息数据长度错误 
    ORA-00590: 来自主机的信息类型错误 
    ORA-00591: 写入的字节数错误 
    ORA-00592: osndnt: $QIO 失败 (邮箱队列) 
    ORA-00593: osndnt: $DASSGN 失败 (网络设备) 
    ORA-00594: osndnt: $DASSGN 失败 (邮箱) 
    ORA-00595: osndnt: $QIO 失败 (接收) 
    ORA-00596: osndnt: $QIO 失败 (发送) 
    ORA-00597: osndnt: $QIO 失败 (邮箱队列) 
    ORA-00598: osndnt: $QIO IO 失败 (邮箱读取) 
    ORA-00600: 内部错误代码,参数: [], [], [], [], [], [], [], [] 
    ORA-00601: 清除锁定冲突 
    ORA-00602: 内部编程异常错误 
    ORA-00603: ORACLE 服务器会话因致命错误而终止 
    ORA-00604: 递归 SQL 层  出现错误 
    ORA-00606: 内部错误代码 
    ORA-00607: 当更改数据块时出现内部错误 
    ORA-00701: 无法改变热启动数据库所需的对象 
    ORA-00702: 引导程序版本 '' 与版本 '' 不一致 
    ORA-00703: 超出行高速缓存例程锁的最大数 
    ORA-00704: 引导程序进程失败 
    ORA-00705: 启动过程中的状态不一致;请在关闭例程后重新启动 
    ORA-00706: 更改文件 '' 的格式时出错 
    ORA-00816: 错误信息无法转换 
    ORA-00900: 无效 SQL 语句 
    ORA-00901: 无效 CREATE 命令 
    ORA-00902: 无效数据类型 
    ORA-00903: 表名无效 
    ORA-00904: : 无效的标识符 
    ORA-00905: 缺少关键字 
    ORA-00906: 缺少左括号 
    ORA-00907: 缺少右括号 
    ORA-00908: 缺少 NULL 关键字 
    ORA-00909: 参数个数无效 
    ORA-00910: 指定的长度对于数据类型而言过长 
    ORA-00911: 无效字符 
    ORA-00913: 值过多 
    ORA-00914: 缺少 ADD 关键字 
    ORA-00915: 当前不允许网络访问字典表 
    ORA-00917: 缺少逗号 
    ORA-00918: 未明确定义列 
    ORA-00919: 无效函数 
    ORA-00920: 无效的关系运算符 
    ORA-00921: 未预期的 SQL 命令结尾 
    ORA-00922: 缺少或无效选项 
    ORA-00923: 未找到预期 FROM 关键字 
    ORA-00924: 缺少 BY 关键字 
    ORA-00925: 缺失 INTO 关键字 
    ORA-00926: 缺少 VALUES 关键字 
    ORA-00927: 缺少等号 
    ORA-00928: 缺少 SELECT 关键字 
    ORA-00929: 缺少句号 
    ORA-00930: 缺少星号 
    ORA-00931: 缺少标识 
    ORA-00932: 不一致的数据类型: 要求  得到的却是  
    ORA-00933: SQL 命令未正确结束 
    ORA-00934: 此处不允许使用分组函数 
    ORA-00935: 分组函数的嵌套太深 
    ORA-00936: 缺少表达式 
    ORA-00937: 非单组分组函数 
    ORA-00938: 函数没有足够的参数 
    ORA-00939: 函数的参数过多 
    ORA-00940: 无效的 ALTER 命令 
    ORA-00941: 群集名缺少 
    ORA-00942: 表或视图不存在 
    ORA-00943: 群集不存在 
    ORA-00944: 没有足够的聚簇列数 
    ORA-00945: 指定的聚簇列不存在 
    ORA-00946: 缺少 TO 关键字 
    ORA-00947: 没有足够的值 
    ORA-00948: 不再支持 ALTER CLUSTER 语句 
    ORA-00949: 非法引用远程数据库 
    ORA-00950: 无效 DROP 选项 
    ORA-00951: 群集非空 
    ORA-00952: 缺少 GROUP 关键字 
    ORA-00953: 缺少或无效索引名 
    ORA-00954: 缺少 IDENTIFIED 关键字 
    ORA-00955: 名称已由现有对象使用 
    ORA-00956: 缺少或无效审计选项 
    ORA-00957: 列名重复 
    ORA-00958: 缺少 CHECK 关键字 
    ORA-00959: 表空间''不存在 
    ORA-00960: 选择列表中的命名含糊 
    ORA-00961: 错误的日期/间隔值 
    ORA-00962: group-by / order-by 表达式过多 
    ORA-00963: 不支持的间隔类型 
    ORA-00964: 表名不在 FROM 列表中 
    ORA-00965: 列别名中不允许'*' 
    ORA-00966: 缺少 TABLE 关键字 
    ORA-00967: 缺少 WHERE 关键字 
    ORA-00968: 缺少 INDEX 关键字 
    ORA-00969: 缺少 ON 关键字 
    ORA-00970: 缺少 WITH 关键字 
    ORA-00971: 缺少 SET 关键字 
    ORA-00972: 标识过长 
    ORA-00973: 无效的行数估计 
    ORA-00974: 无效 PCTFREE 值 (百分比) 
    ORA-00975: 不允许日期 + 日期 
    ORA-00976: 此处不允许为 LEVEL, PRIOR 或 ROWNUM 
    ORA-00977: 重复的审计选项 
    ORA-00978: 嵌套分组函数没有 GROUT BY 
    ORA-00979: 不是 GROUP BY 表达式 
    ORA-00980: 同义词转换不再有效 
    ORA-00981: 不能将表和系统审计选项混在一起 
    ORA-00982: 缺少加号 
    ORA-00984: 列在此处不允许 
    ORA-00985: 无效的程序名 
    ORA-00986: 缺少或无效组名 
    ORA-00987: 缺少或无效用户名 
    ORA-00988: 缺少或无效口令 
    ORA-00989: 给出的用户名口令过多 
    ORA-00990: 缺少或无效权限 
    ORA-00991: 过程仅有 MAC 权限 
    ORA-00992: REVOKE 命令格式无效 
    ORA-00993: 缺少 GRANT 关键字 
    ORA-00994: 缺少 OPTION 关键字 
    ORA-00995: 缺少或无效同义词标识 
    ORA-00996: 连接运算符是 || 而不是 | 
    ORA-00997: 非法使用 LONG 数据类型 
    ORA-00998: 必须使用列别名命名此表达式 
    ORA-00999: 无效的视图名 
    ORA-01000: 超出打开游标的最大数 
    ORA-01001: 无效的游标 
    ORA-01002: 读取违反顺序 
    ORA-01003: 语句未进行语法分析 
    ORA-01004: 不支持默认用户名特性;登录被拒绝 
    ORA-01005: 未给出口令;登录被拒绝 
    ORA-01006: 赋值变量不存在 
    ORA-01007: 选择列表中没有变量 
    ORA-01008: 并非所有变量都已关联 
    ORA-01009: 缺少法定参数 
    ORA-01010: 无效的 OCI 操作 
    ORA-01011: 在与第 6 版服务器会话时不能使用第 7 版兼容模式 
    ORA-01012: 没有登录 
    ORA-01013: 用户请求取消当前的操作 
    ORA-01014: ORACLE 正在关闭过程中 
    ORA-01015: 循环登录请求 
    ORA-01016: 此函数仅可以在读取后调用 
    ORA-01017: 无效的用户名/口令;拒绝登录 
    ORA-01018: 列不具有 LONG 数据类型 
    ORA-01019: 无法在用户方分配内存 
    ORA-01020: 未知的上下文状态 
    ORA-01021: 指定的上下文大小无效 
    ORA-01022: 此配置中不支持数据库操作 
    ORA-01023: 未找到游标上下文 (无效的游标编号) 
    ORA-01024: OCI 调用中的数据类型无效 
    ORA-01025: UPI 参数超出范围 
    ORA-01026: 赋值列表中存在多个大小 > 4000 的缓冲区 
    ORA-01027: 在数据定义操作中不允许对变量赋值 
    ORA-01028: 内部双工错误 
    ORA-01029: 内部双工错误 
    ORA-01030: SELECT ...INTO 变量不存在 
    ORA-01031: 权限不足 
    ORA-01032: 没有这样的用户标识 
    ORA-01033: ORACLE 正在初始化或关闭过程中 
    ORA-01034: ORACLE 不可用 
    ORA-01035: ORACLE 只允许具有 RESTRICTED SESSION 权限的用户使用 
    ORA-01036: 非法的变量名/编号 
    ORA-01037: 超出最大游标内存 
    ORA-01038: 无法写入数据库文件版本  (使用 ORACLE 版本 ) 
    ORA-01039: 视图基本对象的权限不足 
    ORA-01040: 口令中的字符无效;登录被拒绝 
    ORA-01041: 内部错误,hostdef 扩展名不存在 
    ORA-01042: 不允许使用打开游标分离会话 
    ORA-01043: 用户方内存损坏 [], [], [], [] 
    ORA-01044: 缓冲区大小  (与变量关联) 超出了最大限制  
    ORA-01045: 用户  没有 CREATE SESSION 权限;登录被拒绝 
    ORA-01046: 无法获得扩展上下文区域的空间 
    ORA-01047: 以上错误出现在 schema=, package=, procedure= 中 
    ORA-01048: 给定的上下文中无法找到指定的过程 
    ORA-01049: 流动 RPC 中不支持按名称赋值 
    ORA-01050: 无法获得打开上下文区域的空间 
    ORA-01051: 延迟 rpc 缓冲区格式无效 
    ORA-01052: 未指定所需的目的 LOG_ARCHIVE_DUPLEX_DEST 
    ORA-01053: 无法读取用户存储地址 
    ORA-01054: 无法写入用户存储地址 
    ORA-01057: 用户出口中引用的 block.field 无效或有歧义 
    ORA-01058: 内部 New Upi 接口错误 
    ORA-01059: 在赋值或执行之前进行语法分析 
    ORA-01060: 不允许数组赋值或执行 
    ORA-01061: 无法使用第 7 版客户应用程序启动第 8 版服务器 
    ORA-01062: 无法分配定义缓冲区所需的内存 
    ORA-01070: 服务器使用 Oracle 的旧版本 
    ORA-01071: 无法不启动 ORACLE 而执行操作 
    ORA-01072: 无法停止 ORACLE;因为 ORACLE 不在运行 
    ORA-01073: 致命的连接错误: 不能识别的调用类型 
    ORA-01074: 无法关闭 ORACLE;请首先在注册会话中注销 
    ORA-01075: 您现在已登录 
    ORA-01076: 尚不支持每个进程的多次登录 
    ORA-01077: 背景进程初始化失败 
    ORA-01078: 处理系统参数失败 
    ORA-01079: ORALCE 数据库未正确创建,操作中止 
    ORA-01080: 关闭 ORACLE 时出错 
    ORA-01081: 无法启动已在运行的 ORACLE --- 请首先关闭 
    ORA-01082: 'row_locking = always' 要求事务处理处理选项 
    ORA-01083: 参数 "" 的值与其它例程序的相应参数值不一致。 
    ORA-01084: OCI 调用中的参数无效 
    ORA-01085: 延迟 rpc 到 ".." 之前的错误 
    ORA-01086: 从未创建保留点 '' 
    ORA-01087: 不能启动 ORALCE --- 现在已登录 
    ORA-01088: 不能在存在活动进程时关闭 ORACLE 
    ORA-01089: 正在进行紧急关闭 - 不允许进行任何操作 
    ORA-01090: 正在进行关闭 --- 不允许连接 
    ORA-01091: 强行启动出错 
    ORA-01092: ORACLE 例程终止。强行断开连接 
    ORA-01093: ALTER DATABASE CLOSE 仅允许在没有连接会话时使用 
    ORA-01094: ALTER DATABASE CLOSE 正在进行。不允许连接 
    ORA-01095: DML 语句处理了零个行 
    ORA-01096: 程序版本 () 与例程 () 不兼容 
    ORA-01097: 无法在事务处理过程中关闭 - 首先提交或返回 
    ORA-01098: 在 Long Insert 过程中出现程序接口错误 
    ORA-01099: 如果在单进程模式下启动,则无法在 SHARED 模式下安装数据库 
    ORA-01100: 数据库已安装 
    ORA-01101: 要创建的数据库当前正由其它例程安装 
    ORA-01102: 无法在 EXCLUSIVE 模式下安装数据库 
    ORA-01103: 控制文件中的数据库名 '' 不是 '' 
    ORA-01104: 控制文件数 () 不等于  
    ORA-01105: 安装与其它例程的安装不兼容 
    ORA-01106: 必须在卸下之前关闭数据库 
    ORA-01107: 必须安装数据库才可以进行介质恢复 
    ORA-01108: 文件  正处于备份或介质恢复过程中 
    ORA-01109: 数据库未打开 
    ORA-01110: 数据文件 : '' 
    ORA-01111: 数据文件  名称未知 - 请重命名以更正文件 
    ORA-01112: 未启动介质恢复 
    ORA-01113: 文件  需要介质恢复 
    ORA-01114: 将块写入文件  时出现 IO 错误 (块 # ) 
    ORA-01115: 从文件  读取块时出现 IO 错误 (块 # ) 
    ORA-01116: 打开数据库文件时出错 
    ORA-01117: 对文件 '' 添加非法块大小: ;限制为  
    ORA-01118: 无法添加任何其它数据库文件: 超出限制  
    ORA-01119: 创建数据库文件 '' 时出错 
    ORA-01120: 无法删除联机数据库文件  
    ORA-01121: 无法重命名数据库文件  - 文件在使用中或在恢复中 
    ORA-01122: 数据库文件  验证失败 
    ORA-01123: 无法启动联机备份;未启用介质恢复 
    ORA-01124: 无法恢复数据文件  - 文件在使用中或在恢复中 
    ORA-01125: 无法禁用介质恢复 - 文件  设置了联机备份 
    ORA-01126: 对于此操作,数据库必须以 EXCLUSIVE 模式安装且未打开 
    ORA-01127: 数据库名 '' 超出  个字符的限制 
    ORA-01128: 无法启动联机备份 - 文件  处于脱机状态 
    ORA-01129: 用户默认或临时表空间不存在 
    ORA-01130: 数据库文件版本  与 ORACLE 版本  不兼容 
    ORA-01131: DB_FILES 系统参数值  超出限制  
    ORA-01132: 数据库文件名 '' 的长度超出  个字符的限制 
    ORA-01133: 日志文件名 '' 的长度超出  个字符的限制 
    ORA-01134: 数据库已由其它例程独立安装 
    ORA-01135: DML/query 访问的文件  处于脱机状态 
    ORA-01136: 文件  ( 块) 的指定大小小于  块的原大小 
    ORA-01137: 数据文件  仍处于脱机过程中 
    ORA-01138: 数据库必须在此例程中打开或根本没有打开 
    ORA-01139: RESETLOGS 选项仅在不完全数据库恢复后有效 
    ORA-01140: 无法结束联机备份 - 所有文件均处于脱机状态 
    ORA-01141: 重命名数据文件  时出错 - 未找到新文件 '' 
    ORA-01142: 无法结束联机备份 - 没有文件在备份中 
    ORA-01143: 不能禁用介质恢复 - 文件  需要介质恢 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



特斯拉 CEO Elon Musk 发话:开放所有专利技术

$
0
0

昨天,特斯拉 CEO Elon Musk 通过品牌博客发表文章 《All Our Patent Are Belong To You》,首次提出将开放所有专利技术,并表示之后不会再发起任何专利侵权诉讼,“特斯拉的真正对手并非电动汽车同行,而是传统燃油汽车,我们希望借此推动全球电动汽车行业的发展。”

在特斯拉的各项专利技术中,充电技术一直是其引以为豪的部分,但同时其在充电站连接标准上的特殊性也阻碍着企业的发展。开放专利一方面或许的确会进一步推动特斯拉乃至电动汽车行业的进步,另一方面也势必会带给这一领域更激烈的竞争,但不管怎么说,这样的开放胸怀和技术的共享,最终受益的势必是咱们消费者了。

Alphadict v1.1 发布,辞典软件

$
0
0

主要的更新是:

1) 移植到了 windows 平台。

2) 增加了 生词本功能。

3) 支持 IDP 和 dict.info的词典。

4) 重新对UI界面进行了设计,增加了中文。


AlphaDict 是一个轻量级的开放辞典格式的软件, 前端是xml文本, 是用户进行编辑的格式。 后端则是辞典软件识别的格式。用户可以直接使用 前端的xml 来制作自己的辞典,使用任意的文本编辑工具,来写xml就可以了。 具体内容在 doc 文件夹下面可以找到。 也可以使用工具软件支持的辞典格式来编辑,如 CEDICT 的 txt 格式。

目前支持 cedict 和 stardict 辞典格式。

为什么 iPhone 的拍照效果比其它手机优秀?

$
0
0

  知乎用户提问:影像行业不是需要很多年的积累才能有优异的表现吗?iPhone 的影像基础从何而来,索尼有柯尼卡美能达的基础为何在手机成像上反而做不过苹果?为什么苹果在没有任何影像基础(恐是不�描述)的情况下制造出了拍照效果比其他手机优秀的 iPhone?

   知乎用户回答:

   知乎用户:李楠

  实际上,主流手机厂商的摄像头供货商就是那么几家。而 Sony 就是 iPhone 的主要摄像头供货商的一家。(另外一家是 omnivision ,他也向三星供货)

  但是无可否认,近几代 iPhone 实际使用中的拍照效果是超越同期的 Sony 和 三星 的手机的。类似甚至一样的摄像头,结果有差的原因如下:

  1 低像素

  市场有个极为脑残的认识,就是像素越高拍照效果越好。而事实是,至少 iPhone5 的时期, 1200 万,无法超越 800 万。

  但是 Sony 和 三星 这样的日韩厂家没有对用户说不的勇气。你们想要高像素?我就给你。

  而苹果敢:苹果在摄像头的选择上总是青睐低像素。还记得乔布斯在 iPhone4(?) 发布会上计算单个像素大小的 keynote 吗?他就是想告诉用户,高像素并不一定有好的效果。

  可惜强势如乔布斯,其实也没有扭转市场的认识。只懂小学算数的消费者,还是热衷于比较像素多少。今天这个脑残认识仍然深入人心。好在, iPhone 出色的单个像素质量为一张优秀的照片提供了更多保障, 他的拍照效果慢慢得到了用户的认可。(但是不可否认,一部分重视拍照的用户可能因为像素少,去买了 Sony 。)

  2 软件优化

  不同的厂家拿到摄像头,会通过软件调整各种功能和出片效果。这方面就见功力了。

  苹果在 Mac 上做了多年图像处理软件,这方面的水准是足够的。(白平衡,锐度,噪点。。。)

  而自己掌控的系统也应该让他更容易优化相机的各种功能。(快门延迟,对焦速度。。。)

  Android 厂家一般是买第三方的软件算法和功能自己集成。各种调整上感觉没有 iOS 细致用心。

  (吃透一个摄像头的特性是需要时间的,他们出机的频率也不允许)

  3 屏幕配合

  苹果的软件调整再出色,比如他调整出了一流的白平衡,屏幕不给力也都白搭。

  而 iPhone 搭载的是业界最高水准的屏幕。苹果绝不会拿偏色严重的"未来"技术忽悠用户。因为所有在摄像头,软件上下的功夫,都必须通过屏幕表现出来。

  4 最后的话

  所以,苹果真的是良心企业。

  他既不会利用消费者在像素多少上面的无知,也不会在消费者看不到的算法调整上偷懒,也不会让消费者为半成品的屏幕技术埋单。

  他所有的努力,都指向一个单纯的结果,他的手机用户对着家人按下快门的时候,可以留下一个美好的回忆。即使,为此牺牲营销上的优势,也在所不惜。

  所以苹果能赢得我的尊敬,因为作为业内人士,我知道抵御销量的诱惑为用户做这种受累不讨好的事情有多难。

   知乎用户:王寒

  世界上第一款家用数码相机是Apple QuickTake,由苹果设计,柯达代工,帮主回归后砍掉了这个产品。但苹果并没有完全放弃影像技术,从硬件上来看,可以说mac上的iSight是quicktake的遗产,从软件上来看,有专业级别的Aperture和消费级别的iPhoto,iMovie。

  如今的iPhone和移动设备上的摄像头可以说是QuickTake,iSight在移动设备上的延伸,岂能说苹果没有任何影像基础?

  苹果既有如此深厚的影像基础沉淀,又一向重视完美的产品用户体验,因此iPhone的拍照效果要远比其它手机优秀是理所当然的。

  附上1996年使用Apple QuickTake所拍摄的帮主照片。

   知乎用户:Ratoo

  说几个事实:

  iPhone original/3G 拍照效果不能和当时如日中天的 Nokia Nseries, 或者 SE 的 Cybershot 相比. 3GS 也只能算是 so-so.

  iPhone 4 与 Atrix 4G 使用相同的 CMOS, 一个是最好的 500w 手机, 一个几乎是最差的 (如果不考虑用来垫底的 webOS 机型和 Galaxy Nexus.)

  iPhone 4S 推出半年多之前 SE 的 Arc/Arc S/ray 等就已经用上了它使用的感光元器件, 但由于 Android 2.3 时硬件优化不足 (?) 或是 Sony 自身开发能力不足, 2.3 时照片压缩很严重, 完全没发挥出优势. 我想 SE 使用者应该都有了解.

  iPhone 5 的摄像头硬件与 4S 基本一致, 但 A6 的 ISP 让 iPhone 5 的效果即便在阳光下也上了一个台阶. (有人对比过 iPad (3rd generation) 和 iPad (4th generation) 吗?)

  任何相机拍摄的照片在 Galaxy Nexus 上看起来都是一坨翔.

  最后 Apple QuickTake 倒也是最早的消费级数码相机之一.

  总结:

  除了感光元器件, 镜头, ISP 的设计, 软件优化等等, 都影响着照片的效果.

  屏幕对用户的第一印象起了很大的作用.

  iPhone 4 之后 iPhone 拍照超过大部分同时代手机, 用心, 很重要.

   知乎用户:maomaobear

  1、iphone的相机早期很烂,到了iphone4赶上主流水平,到了iphone4s,才进入一流水平。

  2、相机成像效果取决于cmos、镜头、isp和软件算法,苹果在软件方面投入的人力物力资本非常大。

  这决定了在不掌握cmos、镜头、isp技术的条件下,买别人的元件依然有一流的效果

  3、像素决定论和像素无用论,都是白痴理论。

  同样总面积,单位面积大并不意味着画质一定好,相机这点cmos总面积。像素密度高意味着锐度高,强光下出色。像素密度低意味着接受光线多,弱光下有优势。

  选择像素多,还是低,单位面积大还是小,要看用户的使用环境。nokia 808找到了一个好办法,光线强就用3800万像素,光线弱就把3800万合并成500万,单个面积增大。在不同环境下求的出色的效果。

  4、目前,拍照第一的手机是诺基亚808,因为镜头品质和CMOS面积有绝对优势。白天光线下,1300万的高品质手机,已经超过了iphone5的800万。暗光和夜景,有长曝光光学防抖的诺基亚920和htc one也超过了iphone5的800万。

  iphone5还iphone4s的差距基本可以忽略,在iphone4s时代,可以说苹果拍照是手机里面一流的,但是到了iphone5,只能说是优秀的。

  专业手机网站gsmarena有各个手机在摄影棚的对比拍摄图,大家有兴趣可以去看一下,互相对比,也可以和无敌兔直接对比,看看不同手机在锐度,色彩上的差距。国产机,他们评测过荣耀、魅族mx、mx2、oppo find5,国外品牌基本都评过。

  法国权威专业摄像器材评测网站DxOMark有各种手机的评分,和评价,结论和gsmarena一致

  808最高,三星s4第二,iphone5、iphone4s、9300、note2差不多,不过法国人没评测过国产机。



 

  文章来源:知乎

  本文链接: http://www.yixieshi.com/it/17652.html

  ===============关于互联网的一些事===============

   互联网的一些事http://www.yixieshi.com)  ——  专注于互联网产品设计的媒体平台,报道互联网前沿资讯,分享产品设计经验、用户体验心得。为产品策划和产品运营人士提供专业的产品资讯文档,以及产品设计、策划、运营、交互设计、用户体验、电子商务信息、互联网创业信息、移动互联网等专业信息服务。

   官方微博: @互联网的一些事

   官方微信: 互联网的一些事(ID:imyixieshi)

  如果您对互联网产品有独特的想法和见解,欢迎给我们投稿。投稿信箱:tougao#yixieshi.com (自行将“#”修改为“@”)


如何让js不产生冲突,避免全局变量的泛滥

$
0
0

为了避免变量之间的覆盖于冲突,可以生成命名空间,敏敏空间是一种特殊的前缀,在js中,通过{ }对象实现。

在不同的匿名函数中,根据功能声明一个不同的命名空间,每个匿名函数中GLOBAL对象的属性都不直接挂在GLOBAL上,而是挂在次匿名函数的命名空间下,如:

<script type="text/javascript">

var GLOBAL={}

</script><script type="text/javascript">

(function(){

var a=123, a1=256;

GLOBAL.A={}

GLOBAL.A.str=a;

})();

</script><script type="text/javascript">

(function(){

var b1=123, b2=256;

GLOBAL.B={}

GLOBAL.B.str=a;

})();

</script>

 

如果同一个匿名函数中的程序非常复杂,变量名很多,命名空间可以进一步扩展,生成二级命名空间:

<script type="text/javascript">

    var GLOBAL={}

</script><script type="text/javascript">

   (function(){

      var a=123, a1=256;

      GLOBAL.A={};

      GLOBAL.A.CAT={};

      GLOBAL.A.DOG={};

      GLOBAL.A.CAT.name="mini";

      GLOBAL.A.CAT.move=function(){

      }

      GLOBAL.A.DOG.name="mini";

      GLOBAL.A.DOG.move=function(){

      }

   })();

</script>


因生成命名空间是非常常用的功能,可以进一步将生成命名空间的功能定义成一个函数,方便调用,如下:

<pre class="html" name="code"><script type="text/javascript">

   var GLOBAL={}

   GLOBAL.namespace=function(str){

      var arr=str.split("."), o=GLOBAL;
      for(i=arr[0]=="GLOBAL"?1:0;i<arr.length; i++){

      o[arr[i]]=o[arr[i]] || {};

      o=o[arr[i]];

      }

   }</script>

 

调用命名空间具体操作

<script type="text/javascript">
 //=============================================================

//     功能A

//     工程师甲

//     email:ctkl68945@gmail.com     msn:ctkl68945@hotmail.com

//     2012-11-06

//=============================================================
 

(function(){

   var a=123, a1="hello world";

   GLOBAL.namespace("A.CAT");

   GLOBAL.namespace("A.DOG");

   GLOBAL.A.CAT.name="mini";

   GLOBAL.A.CAT.move=function(){

   }

   GLOBAL.A.DOG.name="mini";

   GLOBAL.A.DOG.move=function(){

   }

   GLOBAL.A.str=a;

   GLOBAL.A.str1=a1;

})();


 

 

依次类似,无论多人的直接团队开发,还是个人的间接团队合作,都需要良好的可维护性。

1、添加必要的代码注释

2、让JS不产生冲突,需避免全局变量的泛滥,合理使用命名空间

 

 

 

 

 

 

好开会好看

 

 

作者:comeonstone 发表于2014-6-13 16:16:34 原文链接
阅读:2 评论:0 查看评论

如何在AWS云平台上构建千万级用户应用

$
0
0

AWS 服务概述

高扩展性应用建设并非把应用直接迁移到云平台上就能轻易实现,相反我们需要根据云平台的特性进行专门的设计,这包括选择合适的云服务类型并进行良好的应用架构设计。对于希望基于 AWS 构建千万级用户应用的开发者而言,不仅需要对区域(Region)、可用区(AZ)和边缘站点等基础设施的分布有所了解,更需要了解不同的 AWS 服务各自的特点和最佳实践。

AWS 的服务可大致按照其所处层面分为三类,从下到上依次是基础服务层、应用服务层、部署和管理层。基础服务层也有两层,下层是计算(EC2、WorkSpaces)、存储(S3、EBS、Glacier、Storage Gateway)、网络(VPC、Direct Connect、ELB、Route53),上层是数据库(RDS、Dynamo、ElastiCache、RedShift)、数据分析(EMR、Data Pipeline、Kinesis)、内容分发(CloudFront)。应用服务层主要是把邮件服务、消息队列服务等通用的功能单独抽离出来。部署和管理层则有用于监控的 CloudWatch,用于部署运维工作的 BeanStalk、OpsWorks、CloudFormation 和 CloudTrail 等,以及 IAM、Federation 等身份管理服务。

单机到多实例

传统的单机服务,到 AWS 上面就是跑在一个 EC2 实例上,这个实例上跟以前的服务器一样上面安装所有的 Web 应用、数据库等,搭配一个 EIP,外部用 Route53 做 DNS。遇到瓶颈后,简单的扩展就是将小的实例换成大的实例,比如 small 换成 2xlarge、8xlarge,服务结构不变,可以快速实现,但是最终都会遇到极限。

到了这一步,就要从单实例服务变成多实例。这一步骤涉及到 Web 实例和数据库实例的拆分,数据库可以开始考虑选择 SQL 或者 NoSQL。SQL 大家比较熟悉,优点很明显,缺点主要在规模变大之后呈现,不过一般对于百万级用户量内的应用,SQL 是能够满足需求的;但如果数据量增长速度很快,数据是非结构化或者半结构化的,应用要求的延时低、写入的速度要求快,那考虑 NoSQL 会更合适一些。

几百个用户的情况,一个 RDS 实例+一个 Web 实例即可满足需求,前端直接用一个 EIP,即单机的情况;用户上千的情况,建议启动两个 RDS 实例 +Web 实例并将实例部署在不同的可用区,前端用 ELB 做负载均衡。

对于百万级以下用户的规模,每一个可用区内会有多个 Web 实例和 RDS 实例组成的集群,其中 Active RDS 实例和 Standby RDS 实例要放在不同的可用区,其他 RDS 实例均为只读。

到了这个规模之后,再要往上扩展到百万级,就需要改变部分工作负载的设计方式了。

改变部分工作负载的设计方式

第一步可以引入 S3 和 CloudFront。把静态内容从 Web 实例中迁移到 S3 上,适合的文件类型包括静态数据(CSS、JS、图片、视频)、日志、备份等。S3 具备 11 个 9 的持久性,本身是海量存储,可以支撑大量的并发访问,而且成本很低。CDN 方面,CloudFront 以 Web Service 接口的方式提供服务,支持动态和静态内容、流式视频,支持根域,支持客户化 SSL 证书。

第二步可以引入 ElastiCache 和 DynamoDB。ElastiCache 是托管的 Memcached 和 Redis 服务,API 是一样的,两者都是非常快的缓存服务(毫秒级别),区别在于 Memcached 使用一个 AZ,Redis 可以跨 AZ 复制。DynamoDB 是 NoSQL 服务,后台存储基于 SSD,平均延时在毫秒级别。

这时候我们可以开始考虑弹性的问题,即应用的自动扩展。弹性的实现有四个前提:

  1. 完善的、基于指标的监控体系
  2. 自动化构建
  3. 自动化部署
  4. 集中化日志管理

在 AWS 上实现自动构建部署,可以选择 Beanstalk、OpsWorks 或 CloudFormation,也可以完全自己写脚本配合定制 AMI 来实现。Elastic Beanstalk 是全自动化的,基于容器实现,适合常规的 Web 应用;OpsWorks 是半自动化的,适合较为复杂的应用开发流程,可以对资源配给、配置管理、应用部署、软件升级、监控、身份控制进行定制化;CloudFormation 是基于模板的管理模式,可定制的范围更大。

如果以上都做到,那么一个百万级用户量的应用基本上可以比较好的管理起来。进一步到千万级用户量的规模,我们需要更多的引入面向服务的架构设计,即 SOA。

SOA、SOA、SOA

SOA 在 04、05 年讲得比较多,到现在基本上已经是大家都认可的做法,非常适合大规模应用的场景,其核心在于松耦合。

比如消息队列服务 SQS,加在模块A和模块B之间,这样即使模块A宕掉了,模块B也仍然可以正常运行一段时间。美国大选网站就是采用了这样的思路,在 SQL 实例压力大的时候把实例关掉,换上一个更大的实例,因为前面有 SQS 顶着才可以这样做。

而 AWS 上的通知服务(SNS)、邮件服务(SES),也建议大家多多采用,而不要自己搭建 Web 实例来做,因为此类服务在处理海量请求方面的能力要远远超过一般的实现。

千万级规模对数据库的性能挑战是很大的,对于 SQL,联邦(federation)、分片(sharding)都是常用的方法,将“热”表、快速写数据迁移到 NoSQL 也是一种思路。应用的性能挑战方面,重点则在于即时获得反馈(完善实时的监控+报警),以及持续的调优各个模块。

参考资料

本文链接

财务和会计的区别和联系是什么?

$
0
0
要区分会计和财务并不是一件容易的事,实际运用中会计、财务很多时候也是混着使用的。从职业上,会计、财务的区分也不是那么显然,可能顶着财务的头衔做着会计的活,反之亦然。

从以下几个方面区分可能有助于理解:

一、从历史来看,「会计」的产生早于「财务」。
近代会计产生于13~14世纪的意大利,以复式记账法(借贷记账法)为开始的。随着经济的发展,金融市场特别是资本市场的发展,财务才慢慢独立成为一个职业。分工不断细化,行业也不断细化和深化。从职业角度,财务是脱胎于会计的,是从大的会计范畴中某些职能分化出来的。

二、从学科来看,会计学的产生早于财务相关学科。
会计是一门实践的科学,随着会计实践的不断深化与发展,会计学理论不断发展。财务相关学科本是会计学理论中的分支,后从中分化,逐渐走向独立。

三、从大学专业设置来看,财务管理或者作为会计学专业的一个方向,或者从会计学专业中独立出来,或者从金融学专业中独立出来。从国内来看,前两种情况居多。

四、在学术上,关于会计的本质有着「管理活动论」与「信息系统论」之争。我是这么看的,
会计关注的是资金活动,资金活动贯穿于企业运营的全流程,会计以资金活动为视角全面介入了企业的管理活动。所以,会计本身具有管理的职能。会计以账/表的形式将企业的资金活动予以呈现。资金活动转化为财务信息,而账/表则是表达这些财务信息的形式。
但不管如何争论,「钱」和「账」都是会计/财务的核心要素。会计产生于记账活动,所以会计是偏向于「账」的,即会计核算是会计的核心工作;而财务更多地关注「钱」,包括钱怎么用(营运资金管理、投资活动),钱怎么来(筹资活动)。

五、把会计/财务做过细的区分并没有太大的意义,从职业来讲,基于会计/财务的目标,对岗位作进一步的分析可能更有意义。在企业中,财务总监/主管财务机构的负责人是会计/财务职业的顶峰。不过,财务总监的来源是多样的,不同财务总监的特点与强项也不一样。对绝大多数人来说,有「一招鲜」+没有掉链子项目应该是更加合理的。

六、会计是基础,财务高大上。这是偏见。
基于会计/财务的目标,对岗位的划分其实并没有那么明显的高低之分,优秀的财务核算人员同样是稀缺的,财务核算人员的作为空间并不是那么狭小。会计/财务工作作为管理活动,关键都是实践,是具体问题具体分析的一点点实践。
大的会计/财务工作包括核算、结算(出纳)、资金(筹资)、投资、预算、税务、审计等等。基于不同的目标,划分不同的岗位,一个员工可能是多个岗位的复合。有的岗位是外向的、积极型的,有的岗位是内向的、防守型的。一个立足于发展,一个立足于生存。发展很重要,生存同样重要!

— 完 —
本文作者: JON TANG

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 39 个回答,查看全部。
延伸阅读:
从小会计到财务总监,如何做规划?
知乎在【会计财务】领域有哪些专家?

欧盟考虑将肥胖定义为残疾

$
0
0
欧盟最高法院正在考虑对一个判例案件作出裁决,结果可能会迫使雇主将肥胖雇员作为残疾人对待。丹麦Billund的儿童保育员Karsten Kaltoft声称因为太肥被雇主解雇。他重约160公斤,自称是因为养成了坏习惯才会如此胖,但表示肥胖并没有影响他的工作,他说自己可以坐在地上和孩子们一起玩耍。Kaltoft不认为自己是残疾人,称他希望法庭的结果将确保雇主不会因为胖而解雇雇员。欧盟法院的裁决将会适用于所有欧盟成员国。如果法官决定将肥胖定义为残疾,那么雇主将面临新的义务,如为肥胖雇员保留车位,调查办公空间等。






Web 开发中 20 个很有用的 CSS 库

$
0
0

在过去的几年中,CSS已经成为一大部分开发者和设计者的最爱,因为它提供了一系列功能和特性。每个月都有无数个围绕CSS的工具被开发者发布以简化WEB开发。像CSS 库,框架,应用这样的工具能够为开发者做很多事,而且可以使开发者创造出创新立异的WEB应用。

 

在这篇文件章中我们找到了一系列对开发者有用的CSS库,它们能帮助开发者在一定的期限内取得有创造性和创新性的成果。我们希望这个列表能有助于您的开发并为您提供方便。尽情享受吧!

 

1. Kite

Kite
Kite是一个灵活的布局助手CSS库。Kite使用`inline-block`而不是最新的CSS语法。它注重实际,易于理解且容易使用。Kite用 法与flexbox相似:justify-content,等等。你可以很轻松地创建复杂的模块。Kite是基于OOCSS 与 MindBEMding,它可以帮助您快速构建自己的组件。Kite支持几乎所有浏览器,它属于MIT许可。

 

2. DynCSS

dyncss
DynCSS 将您的CSS解析成-dyn-(attribute)规则。这些规则是模拟浏览器事件(如滚动和缩放)的javascript表达式。其结果会应用到上面 指出的CSS属性。你可以将任何CSS属性设置为动态--前提是它对于jQuery的css()方法是可写的。你可以通过附加-dyn-前缀并指定一个引 用的javascript表达式来实现。

 

 

3. Progressjs

progressjs
ProgressJs 是一个 JavaScript 和CSS3库,可以帮助开发者创建和管理页面上所有元素的进度。你可以设计自己的进度条模板并且可以轻松自定义它。你也可以用ProgressJs 来为用户显示内容加载(图片,视频等)的进度。它可以用在textbox,textarea 甚至整个body上。

 

4. Hover.CSS

hover-css
Hover.CSS 是一个有用的CSS3悬停效果集合,可用于动作调用,按钮,商标,特性图片等。 自定或直接应用到你自己的元素上都非常的简单。 hover.css可以用多种方式来使用; 可以复制粘贴你喜欢的效果到你自己的样式表里,也可以引用样式表。然后只需向你想要的元素需添加对应效果的class名称即可。如果你只打算使用一个或几 个效果,最佳实践是复制粘贴一个效果。

 

 

5. Spinkit

spinkit
Spin kit是一个酷炫的加载动画CSS集合。 Spinkit使用CSS动画来创建吸引人的易于自定义的动画。该集合目标不是提供所有浏览器的解决方案--如果你需要支持哪些还没实现CSS动画属性 (像是IE9及之前的版本)的浏览器,你需要检测下这些动画属性并实现一个变通方案。

 

6. Magic CSS3 Animation

css-animations-effect
Magic CSS3 Animations 是一个特殊效果的CSS3动画库,你可以免费用于你的web项目。简单的引用CSS样式:magic.css或精简版magic.min.css即可。

 

 

7.Bounce.js

bounce-js

Bounce.js是一个用来生成不错的CSS3驱动关键帧动画的工具。用于生成动态动画的JS库是在该工具中投入使用。简单地添加一个组件,选择预设,然后你就会得到一个短URL地址或者导出到CSS。

 

8. ImaCSS

imacss

Imacss是用来将图像文件转换为数据地址的库和应用。该地址可以用来插入到CSS文件中作为背景图片。本质上来讲,它能让你减少所有你对你设计的图片(如图标等)的HTTP请求,并使之能够单个调用。

 

 

9.Buttons

buttons

Buttons是一个可以创建高度自定义、灵活和现代感十足的web按钮的CSS库。该库由Sass+Compass构建,支持正方形、圆角矩形或 者圆形的按钮,并且可选是否扁平以及其他自定义的效果(如发光)。所使用到的尺寸、颜色、效果和字体可以通过变量的帮助进行修改,并且可以非常容易的进行 扩展。

 

10.OdoMeter

odometer

OdeMeter是一个用来创建一些我们比较熟悉的如“汽车里程显示,机场信息板或角子机”等效果或者面板的JavaScript-CSS库。该库 是独立式+轻量级(3kb)的,使用CSS为效果进行转换,所以效率极高(当然也有回退设置)。它简单地将一个给定的元素转换到另一个具有单行函数的预定 义的值。

 

 
 

11. Single Element CSS Spinner

Single Element CSS Spinners
Single Element CSS Spinners是一个CSS螺旋动画加载的集合。每个旋转包含一个使用‘loader’ class的div,其文本内容为‘Loading…’。文本是为屏幕阅读器使用的且可用作老浏览器的后退的状态。

 

12. Ani.js

anijs
AniJS是一个CSS动画的声明处理库,它能够使开发更便利且能提高开发速度。它文档完善且易于上手。

 

 

13. Beautons

beautons
Beautons是一个用来创建漂亮、简洁按钮的易用库。你可以应用各种样式、函数已经其他的更多内容到按键上,包括改变它们的大小,设置它们的可用与否以及更多设置。

 

14. Saffron

Saffron
Saffron是一系列Sass混合器和助手集,能够使添加CSS3的动画和过渡非常简单。只需要包括一个mixin在SASS声明中,然后使用变量和混合参数设置一些配置。使用Saffron,你能够完全控制动画和过渡的行为。

 

 

15. CSS Shakes

CSS Shake
这是一个能够震动和晃动‘DOM’的CSS类集合。

 

16. Typebase.css

typebasecss
Typebase.css是个最小化的、可定制的字体样式表。它有less和SASS版本,所以能够很容易地修改融入现代的Web项目。它提供了所有排版 所必要的基础工具且不需添加其他任何设计内容。它被创建用来完成项目发展和成长期时的修改,能和normalize.css很好的工作。

 

 

17. Sassline

Sassline
在web上使用Sass & rems设置文本到基线网格。Sassline可以用在博客、prototyping以及其他Web项目。它有建议的基础字体样式和混合比例已达到基线网格的良好配合。为每个断点选择一个modular-scale,其运行响应将会更好。

 

18. TypeSettings

Typesettings
一个Sass工具包,基于modular scale有Ems风格,纵向风格,响应比基于headlines。

 

 

19. Type Rendering Mix

Type-Rendering-Mix
Type Rendering Mix是个小型的JavaScript库,它允许只有使用核心文本时(在iOS和OS X上)才应用样式,在实现更一致的渲染同时保持高精度原态。

 

20. Hint.css

hintcss
Hint.css是一个使用SASS构建只使用CSS和HTML的提示库。该库使用数据属性、内容属性、伪元素以及CSS3转换。提示框简洁漂亮,有箭头且可放置在父元素的任何一边。

 

 

转自: http://www.oschina.net/translate/css-libraries-for-developers

英文原文: 20 Useful CSS Libraries for Web Development

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



[转][CSDN采访稿] 并不是所有的程序员都适合做技术管理

$
0
0

原文链接: http://news.csdn.net/article_preview.html?preview=1&reload=1&arcid=2820217

[记者:张勇] 写在之前:在CSDN博客闲逛时无意间进入一个博客( 博客地址),博客里的文章质量很高,文章话题主要涉及程序员素养和管理,文章有翻译也有原创。看了几篇文章之后,突然很想和这篇博名为“呦呦鹿鸣”,签名则引用孟子“穷则独善其身,达则兼济天下”的博主聊聊。

在邮件中得知,博主真实姓名叫陆其明,是爱奇艺研发总监,负责爱奇艺、PPS影音客户端软件的研发工作,而在这之前,他则是名DirectShow大牛。不过,如今的他已经不再做具体的技术工作了,而是转型做技术团队的日常管理工作。

提到技术团队管理,他声称,个人的实际性格是偏内向,不善言辞也少言寡语,可以说是一个技术男的形象(不是那种被扭曲了的技术宅男)。但由于管理者的职责所在,所以就决定了他不能太内敛,要主动沟通,发挥自己的影响力,调动所有可以调用的资源去积极解决问题……借此,他也分享了个人对程序人生、对技术管理的看法。

以下是陆其明在采访中叙述的内容:

技术改变生活,技术让生活更美好。我曾经是一名技术高手,而今却是一位职业经理人。我为什么会有这样的转变呢?

为什么要转型做管理?

其实,做程序员挺好的,学会一种新技术或者解决一个技术难题,很容易就能获得成就感。但做了3到5年之后,你就会觉得迷茫:似乎该会的也都会了,再多学点别的吧工作中又用不到,我的前路在何方?现代的软件都不是单靠一个人能做出来的,必须靠团队。个人做得再好,也未必能做出更好的产品。我当时就意识到,个人技术再牛又怎么样呢,让团队发挥最大的效力一起把事情做好则是另外一门学问。那才是我要走的路!

我从带4到5人的小团队开始,从负责底层的SDK开始做起,后来负责整体的应用软件,负责从开发、测试到产品发布的整个流程,团队规模也越做越大。工作越来越忙,管的事情越来越杂,也慢慢地不再有时间写代码。在这个过程中,我得到了很多人的帮助,自己的能力也得到了长足的发展。自然而然地,我不再是一名程序员了!我已是一位职业的管理者。

从技术到管理,我的转型还算是成功的。如今的我不愿意再被别人看成是技术牛人。对我而言,褪去技术的光环是不容易的。但这条路我会继续走下去!现在,有些网友还会给我发来这样的私信,“陆老师,您好!我想请教个关于DirectShow的问题:现在我用mp4 demux filter将多流的MP4文件分理出八路码流...但是我现在控制不了接收的顺序。请问有什么解决办法么?”对于这种具体的技术问题,我以前的回答是,“抱歉,我已经不写代码很多年了!帮不了你。”如今我更是连抱歉也懒得说了。值此机会,统一向大家说一声“抱歉”吧!

并不是所有人都适合做管理

我相信,很多程序员都想转做管理。一方面,做管理可以拿到更高的薪水(这在国内基本上也是事实),另一方面,觉得做管理很风光,工作起来很轻松(只须使唤别人干活)。我想提醒这些程序员的是:

  • 不是所有人都适合做管理的。技术和管理是两个完全不一样的领域。技术做得好,不见得管理就能做好。对于很多程序员来说,与机器沟通要比与人沟通简单得多。还要看个人的性格,不过,我不能说自己就适合做管理。只能说,事在人为吧!
  • 管理者表面上很风光。其实你要明白:权力有多大,责任(和压力)也就有多大。管理者每天要面对杂七杂八的很多问题,很难做到专注,一门心思只做自己喜欢的事情。如果你追求的是简单的快乐,做程序员更能让你得到满足。
  • 思维方式需要很大的转变。作为管理者,你的职责是帮助团队成功,你的成功也需要依靠团队。没有团队很失败而个人很成功的管理者。

与此同时,他也分享了做管理,需要注意的事:

  • 懂技术的管理者是很有优势的,但从技术向管理的转变过程中“坑”也很多。技术注重的是细节,而管理需要的是大局观。这一点对于很多人来说特别难把握。
  • 不要轻易放弃写代码。因为从技术转向管理的过程中,是有一段危险期的。不要荒废了技术,管理能力又不够强,这时候如果公司出点变故,你将很难再找到一份理想的工作。找一份好工作,实力是一方面,运气也很关键。

那如何走上做管理的道路呢?

还是先从一名高效能的程序员做起吧!千万不要放松对自己的要求,也不要沉溺于代码而忽略了用户体验。Jeff Atwood曾经指出,“成为一名杰出的程序员其实跟写代码没有太大的关系。做程序员确实需要一些技术能力,当然,还要有坚忍不拔的精神。但除此之外,更重要的还是要有良好的沟通技巧。”他还在“ 最牛B的编码套路”一文中说道,“你也应该写博客。最后闻达于天下的人,往往就是那些能够有效书写和沟通的人。”杰出程序员的功力更在代码之外!

我强烈建议大家读一读Jeff Atwood的那两本书(《高效能程序员的修炼》和《程序员的修炼——从优秀到卓越》)。如果你读过之后没有共鸣,也没关系,你再踏踏实实做3~5年编程工作再说吧。

结束语:

在文章的最后,引用陆其明在邮件中和我聊天的内容,希望能够给大家更多的共鸣。

我是一个做事认真、细致的人。每个人都有一辈子,但各有各的活法。我不甘平庸,我希望自己的人生能够绽放别样的精彩。谁不想成功呢?差别在于各人的付出,重要的是勤奋和努力,朝着更高的目标一步一步迈进吧。我在路上……
作者:happydeer 发表于2014-6-13 19:23:06 原文链接
阅读:47 评论:0 查看评论

uglifyjs批量压缩js

$
0
0
jquery官方使用uglifyjs进行压缩的,压缩比较高

需要安装软件
1、node.js
2、uglifyjs
3、java
4、ant

uglifyjs的安装方法

npm install uglify-js -g



新建build.xml
<project name="前端js压缩" default="compress" basedir="."><description>前端js压缩,使用uglifyjs压缩当前目录里的所有js文件,
      压缩后,会将原文件替换为压缩过的文件。
    </description><!-- set global properties for this build --><!-- 项目根目录 --><property name="root" location="../public_html/js/" /><!-- js文件压缩后的前缀,比如prefix=.min.js,生成*.min.js --><property name="suffix"  value=".js"/><!-- node.js npm的路径 用npm root -g 命令查看 --><property name="npm"  value="C:\Users\consumer\AppData\Roaming\npm"/><target name="compress" description="压缩" ><echo>开始压缩js文件</echo><apply executable="${npm}\uglifyjs.cmd" dest="${root}" force="true" verbose="true"><srcfile/><arg value="-m"/><arg value="-c"/><arg line="-o"/><targetfile/><fileset dir="${root}"><filename name="**/*.js"/></fileset><mapper type="glob" from="*.js" to="*${suffix}"/></apply><echo>压缩结束</echo></target></project>


执行命令
ant  -d -v -f c:\build.xml

结果:
     [echo] 压缩结束

BUILD SUCCESSFUL
Total time: 31 seconds

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




Java类加载机制深度分析(转载)

$
0
0

Java类加载机制

类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行。研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性。 
   
在java.lang包里有个ClassLoader类,ClassLoader 的基本目标是对类的请求提供服务,按需动态装载类和资源,只有当一个类要使用(使用new 关键字来实例化一个类)的时候,类加载器才会加载这个类并初始化。一个Java应用程序可以使用不同类型的类加载器。例如Web Application Server中,Servlet的加载使用开发商自定义的类加载器, java.lang.String在使用JVM系统加载器。

在JVM里由类名和类加载器区别不同的Java类型。因此,JVM允许我们使用不同的加载器加载相同namespace的java类,而实际上这些相同namespace的java类可以是完全不同的类。这种机制可以保证JDK自带的java.lang.String是唯一的。

一、Java类加载器 
   
顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例。 
   
二、java.class.ClassLoader类介绍

java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class类的一个实例。除此之外,ClassLoader还负责加载 Java 应用所需的资源,如图像文件和配置文件等。 
   
ClassLoader 中与加载类相关的方法:

getParent()           返回该类加载器的父类加载器。 
loadClass(String name)      加载名称为 name的类,返回的结果是 java.lang.Class类的实例。 
findClass(String name)      查找名称为 name的类,返回的结果是 java.lang.Class类的实例。 
findLoadedClass(String name)   查找名称为 name的已经被加载过的类,返回的结果是 java.lang.Class类的实例。 
defineClass(String name, byte[] b, int off, int len)   把字节数组 b中的内容转换成 Java 类,返回的结果是 java.lang.Class类的实例。这个方法被声明为 final的。 
resolveClass(Class<?> c)     链接指定的 Java 类。

对于以上给出的方法,表示类名称的 name参数的值是类的二进制名称。需要注意的是内部类的表示,如 com.example.Sample$1和com.example.Sample$Inner等表示方式。 
   
三、类加载器的树状组织结构

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:

•引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader。 
•扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载Java 类。 
•系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。除了引导类加载器之外,所有的类加载器都有一个父类加载器。通过给出的 getParent()方法可以得到。对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java类如同其它的 Java 类一样,也是要由类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来,形成树状结构。树的根节点就是引导类加载器。

ClassLoaderTreeClassLoaderParent2ClassLoaderParent 
如以上三图给出了一个典型的类加载器树状组织结构示意图,其中的箭头指向的是父类加载器。

image  
如上图给出了类加载器的树状组织结构演示代码。 
   
四、类加载器的代理模式 
   
类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载(loadClass)这个类,依次类推。在介绍代理模式背后的动机之前,首先需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。 
   
比如:一个 Java 类 com.example.Sample,编译之后生成了字节代码文件 Sample.class。两个不同的类加载器 ClassLoaderA和 ClassLoaderB分别读取了这个 Sample.class文件,并定义出两个 java.lang.Class类的实例来表示这个类。这两个实例是不相同的。对于 Java 虚拟机来说,它们是不同的类。试图对这两个类的对象进行相互赋值,会抛出运行时异常 ClassCastException。   
image 

如上图代码,但未出现上述的异常,因为FileSystemClassLoader已继承自java.class.ClassLoader类,从而使用了类加载的代理机制,两个类加载过程都是由父类加器完成的,所以不会抛出ClassCastException异常;此处先暂时假定会抛出ClassCastException异常;

有关ClassLoader还有很重要一点: 
同一个ClassLoader加载的类文件,只有一个Class实例。但是,如果同一个类文件被不同的ClassLoader载入,则会有两份不同的ClassLoader实例(前提是着两个类加载器不能用相同的父类加载器)。 
   
运行结果可以看到,运行时抛出了 java.lang.ClassCastException异常。虽然两个对象 obj1和 obj2的类的名字相同,但是这两个类是由不同的类加载器实例来加载的,因此不被 Java 虚拟机认为是相同的。了解了这一点之后,就可以理解代理模式的设计动机了。代理模式是为了保证 Java 核心库的类型安全。所有Java 应用都至少需要引用 java.lang.Object类,也就是说在运行的时候,java.lang.Object这个类需要被加载到 Java 虚拟机中。如果这个加载过程由 Java 应用自己的类加载器来完成的话,很可能就存在多个版本的 java.lang.Object类,而且这些类之间是不兼容的。通过代理模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。不同的类加载器为相同名称的类创建了额外的名称空间。相同名称的类可以并存在 Java 虚拟机中,只需要用不同的类加载器来加载它们即可。不同类加载器加载的类之间是不兼容的,这就相当于在 Java 虚拟机内部创建了一个个相互隔离的 Java 类空间。 
   
五、加载类的过程 
   
在前面介绍类加载器的代理模式的时候,提到过类加载器会首先代理给其它类加载器来尝试加载(loadClass)某个类。这就意味着真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。真正完成类的加载工作是通过调用 defineClass来实现的;而启动类的加载过程是通过调用 loadClass来实现的。前者称为一个类的 定义加载器(defining loader),后者称为 初始加载器(initiating loader)。在 Java 虚拟机判断两个类是否相同的时候,使用的是类的 定义加载器(此句可与第四部分一起理解哦)。 也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器

两种类加载器的关联之处在于: 一个类的定义加载器是它引用的其它类的初始加载器。有点晦涩,这句话可以举例说明:ClassA的类加载器为ClassLoaderA,ClassLoaderB是ClassLoaderA父类加载器,那么当ClassLoaderA初始加载ClassA时,由于类加载器的代理模式,则会调用父类加载器ClassLoaderB来定义ClassA,所以ClassLoaderA叫做ClassA的初始加载器,而ClassLoaderB叫做ClassA的定义加载器,然而ClassA中引用了ClassC,那么当父类加载器ClassLoaderB定义ClassLoaderA时,会初始加载ClassC,所以ClassLoaderB又叫做ClassC的初始加载器,又由于类加载器的代理模式,则会调用ClassLoaderB的父类加载器--系统类加载器来定义ClassC,所以最后系统类加载器叫作ClassC的定义加载器)。

如类 com.example.Outer引用了类 com.example.Inner,则由类 com.example.Outer的定义加载器负责启动类 com.example.Inner的加载过程。 
   
方法 loadClass()抛出的是 java.lang.ClassNotFoundException异常;方法 defineClass()抛出的是 java.lang.NoClassDefFoundError异常。类加载器在成功加载某个类之后,会把得到的 java.lang.Class类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。也就是说,对于一个类加载器实例来说,相同全名的类只加载一次,即 loadClass方法不会被重复调用(可借类加载这一特点,实现线程安全哦)。

一般简单加载过程: 
Java程序运行的场所是内存,当在命令行下执行:java HelloWorld命令的时候,JVM会将HelloWorld.class加载到内存中,并形成一个Class的对象HelloWorld.class。

其中的过程就是类加载过程:

1、寻找jre目录,寻找jvm.dll,并初始化JVM; 
2、产生一个Bootstrap Loader(引导类加载器); 
3、Bootstrap Loader自动加载Extended Loader(扩展类加载器),并将其父Loader设为Bootstrap Loader。 
4、Bootstrap Loader自动加载AppClass Loader(系统类加载器),并将其父Loader设为Extended Loader。 
5、最后由AppClass Loader加载HelloWorld类。

image  
如图,给出了类加载器各自搜索目录代码。

类加载器特点:

1、运行一个程序时,总是由AppClass Loader(系统类加载器)开始加载指定的类。 
2、在加载类时,每个类加载器会将加载任务上交给其父,如果其父找不到,再由自己去加载。 
3、Bootstrap Loader(引导类加载器)是最顶级的类加载器了,其父加载器为null。

六、线程上下文类加载器

类 java.lang.Thread中的方法  getContextClassLoader()setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。

在线程中运行的代码可以通过此类加载器来加载类和资源。 
   
前面提到的类加载器的代理模式并不能解决 Java 应用开发中会遇到的类加载器的全部问题。如:Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。这些 SPI 的接口由 Java 核心库来提供,如 JAXP 的 SPI 接口定义包含在 javax.xml.parsers包中。这些 SPI 的实现代码很可能是作为 Java 应用所依赖的 jar 包被包含进来,可以通过类路径(CLASSPATH)来找到,如实现了 JAXP SPI 的 Apache Xerces所包含的 jar 包。SPI 接口中的代码经常需要加载具体的实现类。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory类中的 newInstance()方法用来生成一个新的 DocumentBuilderFactory的实例。这里的实例的真正的类是继承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的实现所提供的。如在 Apache Xerces 中,实现的类是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。而问题在于, SPI 的接口是 Java 核心库的一部分,是由引导类加载器来加载的SPI 实现的 Java 类一般是由系统类加载器来加载的引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的代理模式无法解决这个问题。 
   
线程上下文类加载器正好解决了这个问题。如果不做任何的设置,Java 应用的线程的上下文类加载器默认就是系统上下文类加载器。在 SPI 接口的代码中使用线程上下文类加载器,就可以成功的加载到 SPI 实现的类。线程上下文类加载器在很多 SPI 的实现中都会用到。此处理解很晦涩,简单说明下个人理解:

1. 首先说明类加载器代理机制解决不了的问题: 引导类加载器仅会加载Java核心库,如SPI接口,但是对于第三方对SPI接口实现的Java类,引导类加载器却无法加载(引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库),它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。所以导致代理机制解决不了该问题。但是SPI 实现的 Java 类一般会被系统类加载器来加载(通过类路径CLASSPATH找到),虽然加载了SPI 实现的 Java 类,但导致了SPI接口被引导类加载器加载,SPI接口实现的Java类被系统类加载器加载的困境。 
2.  那么面对该问题,使用线程上下文类加载器可解决,因为Java 应用的线程的上下文类加载器默认就是系统上下文类加载器,在 SPI 接口的代码中使用线程上下文类加载器(即引导类加载器),就可以成功的加载到 SPI 实现的类。从而引导类加载器将SPI接口与SPI实现的Java类一同加载了。该问题解决。 
   
七、另外一种加载类的方法:Class.forName

Class.forName是一个静态方法,同样可以用来加载类。

该方法有两种形式:Class.forName(String name, boolean initialize, ClassLoader loader)和 Class.forName(String className)。

第一种形式的参数 name表示的是类的全名;initialize表示是否初始化类;loader表示加载时使用的类加载器。 
第二种形式则相当于设置了参数 initialize的值为 true,loader的值为当前类的类加载器(只要不是自定义的类加载器,便是系统类加载)。

Class.forName的一个很常见的用法是在加载数据库驱动的时候。如 Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance()用来加载 Apache Derby 数据库的驱动。 
   
调用只有一个参数的forName()方法等效于 Class.forName(className, true, loader)。这两个方法,最后都要连接到原生方法forName0(),其定义如下:

private static native Class forName0(String name, boolean initialize,ClassLoader loader) throws ClassNotFoundException;

只有一个参数的forName()方法,最后调用的是:forName0(className, true, ClassLoader.getCallerClassLoader());而三个参数的forName(),最后调用的是:forName0(name, initialize, loader); 
所以,不管使用的是new 來实例化某个类、或是使用只有一个参数的Class.forName()方法,内部都隐含了“载入类 + 运行静态代码块”的步骤。而使用具有三个参数的Class.forName()方法时,如果第二个参数为false,那么类加载器只会加载类,而不会初始化静态代码块,只有当实例化这个类的时候,静态代码块才会被初始化;如果第二个参数为true,那么类加载器加载类同时,会初始化静态代码块。

注:类加载有三种方式:不同方式加载时,会影响静态代码块执行顺序。

1、命令行启动应用时候由JVM初始化加载。 
2、通过Class.forName()方法动态加载。 
3、通过ClassLoader.loadClass()方法动态加载。

image

image 

如图,给出了各种加载方式与静态块执行顺序测试类代码。

八、开发自定义类加载

在绝大多数情况下,系统默认提供的类加载器实现已经可以满足需求。在某些情况下,您还是需要为应用开发出自己的类加载器。比如您的应用通过网络来传输 Java 类的字节代码,为了保证安全性,这些字节代码经过了加密处理。这个时候您就需要自己的类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出要在 Java 虚拟机中运行的类来。

文件系统类加载器:

image  image 
image

网络类加载器:

image  image  image  
注:大家在看此处时,不要真的以为是由两个自定义加载器加载的类文件,有很大误导,此处是由父类加载器加载完成的,因为加载的类文件与父类加载器是处在同一个project中,导致子类加载器代理给父类加载器时,父类加载器是可以加载到类文件的,从而不会再调用子类加载器的findClass()方法,大家可调试得出结论。我们在使用自定义加载器类时,首先明确的前提是,被加载的类文件,不是当前project产生的,或者是由网络得来,或者是其他本地类文件,否则会产生以上误区。 
   
九、类加载器与 Web 容器

对于运行在 Java EE™容器中的 Web 应用来说,类加载器的实现方式与一般的 Java 应用有所不同。不同的 Web 容器的实现方式也会有所不同。以 Apache Tomcat 来说,每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是:Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。 
   
绝大多数情况下,Web 应用的开发人员不需要考虑与类加载器相关的细节。下面给出几条简单的原则:

•每个 Web 应用自己的 Java 类文件和使用的库的 jar 包,分别放在 WEB-INF/classes和 WEB-INF/lib目录下面。 
•多个应用共享的 Java 类文件和 jar 包,分别放在 Web 容器指定的由所有 Web 应用共享的目录下面。 
•当出现找不到类的错误时,检查当前类的类加载器和当前线程的上下文类加载器是否正确。

十、总结 
   
类加载器是 Java 语言的一个创新。它使得动态安装和更新软件组件成为可能。本文详细介绍了类加载器的相关话题,包括基本概念、代理模式、线程上下文类加载器、与 Web 容器的关系等。开发人员在遇到 ClassNotFoundException和 NoClassDefFoundError等异常的时候,应该检查抛出异常的类的类加载器和当前线程的上下文类加载器,从中可以发现问题的所在。在开发自己的类加载器的时候,需要注意与已有的类加载器组织结构的协调。



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Apache与Nginx的优缺点比较

$
0
0

Apache与Nginx的优缺点比较  

转载他人的

1、nginx相对于apache的优点: 
轻量级,同样起web 服务,比apache 占用更少的内存及资源 
抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能 
高度模块化的设计,编写模块相对简单 
社区活跃,各种高性能模块出品迅速啊 
apache 相对于nginx 的优点: 

rewrite , 比nginx 的rewrite 强大 

动态页面

模块超多,基本想到的都可以找到 
少bug ,nginx 的bug 相对较多 

超稳定 

 

存在就是理由,一般来说, 需要性能的web 服务,用nginx 。如果不需要性能只求稳定,那就apache 吧。 后者的各种功能模块实现得比前者,例如ssl 的模块就比前者好,可配置项多。这里要注意一点,epoll(freebsd 上是 kqueue )网络 IO 模型是nginx 处理性能高的根本理由,但并不是所有的情况下都是epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文 件,apache 的select 模型或许比epoll 更高性能。当然,这只是根据网络IO 模型的原理作的一个假设,真正的应用还是需要实测了再说 的。 

2、作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点 使 Nginx 尤其受到虚拟主机提供商的欢迎。在高连接并发的情况下,Nginx是Apache服务器不错的替代品: Nginx在美国是做虚拟主机生 意的老板们经常选择的软件平台之一. 能够支持高达 50,000 个并发连接数的响应,  感谢Nginx为我们选择了 epoll and kqueue 作为开发模型. 
Nginx 作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务, 也可以支持作为 HTTP代理 服务器对外进行 服务. Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多. 
作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器), Last.fm 描述了成功并且美妙的使用经验. 
Nginx 是 一个安装非常的简单 , 配置文件非常简洁(还能够支持perl语法), Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到 7*24不间断运行,即使运行数个月也不需要重新启动. 你还能够不间断服务的情况下进行软件版本的升级 . 

3、Nginx 配置简洁, Apache 复杂 
Nginx 静态处理性能比 Apache 高 3倍以上 
Apache 对 PHP 支持比较简单,Nginx 需要配合其他后端用 
Apache 的组件比 Nginx 多 
现在 Nginx 才是 Web 服务器的首选 

4、最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程 

5、 nginx处理静态文件好,耗费内存少.但无疑apache仍然是目前的主流,有很多丰富的特性.所以还需要搭配着来.当然如果能确定nginx就适合需求,那么使用nginx会是更经济的方式. 

apache有先天不支持多核心處理負載雞肋的缺點,建議使用nginx做前端,後端用apache。大型網站建議用nginx自代的集群功能


6、 从个人过往的使用情况来看,nginx的负载能力比apache高很多。最新的服务器也改用nginx了。而且nginx改完配置能-t测试一下配置有没 有问题,apache重启的时候发现配置出错了,会很崩溃,改的时候都会非常小心翼翼现在看有好多集群站,前端nginx抗并发,后端apache集群, 配合的也不错。

 


7、 nginx处理动态请求是鸡肋,一般动态请求要apache去做,nginx只适合静态和反向。 

8、從我個人的經驗來看,nginx是很不錯的前端服務器,負載性能很好,在老奔上開nginx,用webbench模擬10000個靜態文件請求毫不吃力。apache對php等語言的支持很好,此外apache有強大的支持網路,發展時間相對nginx更久,

9、 Nginx优于apache的主要两点:1.Nginx本身就是一个反向代理服务器 2.Nginx支持7层负载均衡;其他的当然,Nginx可能会比 apache支持更高的并发,但是根据NetCraft的统计,2011年4月的统计数据,Apache依然占有62.71%,而Nginx是 7.35%,因此总得来说,Aapche依然是大部分公司的首先,因为其成熟的技术和开发社区已经也是非常不错的性能。 

10、你对web server的需求决定你的选择。 大 部分情况下nginx都优于APACHE,比如说静态文件处理、PHP-CGI的支持、反向代理功能、前端Cache、维持连接等等。在 Apache+PHP(prefork)模式下,如果PHP处理慢或者前端压力很大的情况下,很容易出现Apache进程数飙升,从而拒绝服务的现象。 

11、可以看一下nginx lua模块:https://github.com/chaoslaw...apache比nginx多的模块,可直接用lua实现apache是最流行的,why?大多数人懒得更新到nginx或者学新事物 

12、对于nginx,我喜欢它配置文件写的很简洁,正则配置让很多事情变得简单运行效率高,占用资源少,代理功能强大,很适合做前端响应服务器 

13、Apache在处理动态有优势,Nginx并发性比较好,CPU内存占用低,如果rewrite频繁,那还是Apache吧


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



软件构架设计--质量属性

$
0
0

软件质量属性是影响软件架构设计的重要因素,常见的软件质量属性有:

性能(Performance):指的是系统的响应能力,即要经过多长时间才能对某个事件做出响应,或者在某段时间内系统所能处理事件的个数

可用性(Avaliability):是系统能够正常运行的时间比例 

可靠性(Reliability):可靠性是指软件系统在应用或错误面前,在意外或错误使用的情况下维护软件系统功能特性的基本能力

健壮性(Robustness):系统能够承受压力或变更的能力

安全性(Security):系统向合法用户提供服务的同时能够阻止非授权用户使用的企图或拒绝服务的能力

可修改性(Modification):是指能够快速地以较高的性能价格比对系统进行变更的能力

可变性(Changeability):指体系结构经扩充或变更成为新体系结构的能力

易用性(Usability):衡量用户使用一个软件产品完成指定任务的难易程度

可测试性(Testability):指软件发现故障并隔离、定位其故障的能力特性,以及在一定时间和成本 前提下,进行测试设计、测试执行的能力

功能性(Functionality):系统所能完成所期望工作的能力

互操作性(Inter-operation):系统与外界或系统与系统之前的相互作用能力



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Javascript实现简单的下拉二级菜单

$
0
0

在线演示; http://jsfiddle.net/Web_Code/ThhbG/embedded/result/

<span style="font-size:14px;"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="content-type" content="texthtml;charset=utf-8"><title>Menu</title><style type="text/css">
	    #nav
	    {
	    	list-style: none;
	    	text-align: center;
	    }
	    #nav li
	    {
	    	float: left;
	    	width: 100px;
	    	color: white;
	    	background-color: #3E3E3E;
	    }
	    #menu
	    {
	    	list-style: none;
	        padding: 5px;
	    	display: none;
	    	margin-left: -5px;
	    	margin-top: -5px;
	    }
	    #menu li
	    {
	    	background-color: #ccc;
	    	width: 100px;
	    	text-align: left;
	    	padding-left: 10px;
	    }
	    #menu li a:link
	    {
	    	text-decoration: none;
	    	display: block;
	    }
	    #menu li a:hover
	    {
	    	background-color:#3E3E3E;
	    	color: white
	    }</style></head><body><ul id="nav"><li class="child">数 据 库
			<ul id="menu"><li><a href="http://blog.csdn.net/u011043843">MySQL</a></li><li><a href="http://blog.csdn.net/u011043843">SQL Server</a></li><li><a href="http://blog.csdn.net/u011043843">Oracle</a></li><li><a href="http://blog.csdn.net/u011043843">DB2</a></li></ul></li><li class="child">前台脚本
			<ul id="menu"><li><a href="http://blog.csdn.net/u011043843">JavaScript</a></li><li><a href="http://blog.csdn.net/u011043843">Ruby</a></li><li><a href="http://blog.csdn.net/u011043843">HTML</a></li><li><a href="http://blog.csdn.net/u011043843">Python</a></li></ul></li><li class="child">后台脚本
			<ul id="menu"><li><a href="http://blog.csdn.net/u011043843">PHP</a></li><li><a href="http://blog.csdn.net/u011043843">ASP</a></li><li><a href="http://blog.csdn.net/u011043843">ASP.NET</a></li><li><a href="http://blog.csdn.net/u011043843">JSP</a></li></ul></li></ul><script type="text/javascript">
		var lis = document.getElementById("nav").getElementsByTagName('li');
		var i = 0;
		for( i = 0; i < lis.length; i++)
		{
			if(lis[i].className == "child")
			{
				lis[i].onmouseover = function()
				{
					var ulObj1 = this.getElementsByTagName('ul')[0];
					ulObj1.style.display = "block";
					this.style.backgroundColor="#ccc";
					this.style.color="black";
				}
			}

				lis[i].onmouseout = function()
				{
					var ulObj1 = this.getElementsByTagName('ul')[0]; //this是HTMLElement对象
					ulObj1.style.display = "none";
					this.style.backgroundColor="#3E3E3E";
					this.style.color="white";
				}
		}</script></body></html></span>



作者:u011043843 发表于2014-6-14 11:36:47 原文链接
阅读:101 评论:0 查看评论

电影字幕下载网站大全(By乐葛格)

$
0
0

电影字幕下载网站大全(srt、sub等格式)

By  乐葛格


中文字幕下载站(chinese language)

射手网: www.shooter.com.cn(极力推荐,最全面)
TLF原创字幕站 : http://tlfsubs.eastgame.net/
汉风中文字幕库: http://sub.hanstyle.org/default.asp
新视界字幕站 : http://www.newmov.com/dvd/film.asp
伊甸园电影字幕下载区: http://bbs.ydy.com/forumdisplay.php?fid=230


多语种字幕站(Multi Language)

http://subscene.com/(这个好像是德国的,很不错的,各种语种都有)

http://subtitlesbank.com/zh/ (这个也挺不错)

http://www.titles.to 
http://www.subtitles.ro/ 
http://subtitlesonline.uw.hu/ 
http://www.allsubtitles.co.uk/ 
http://subtitles.images.o2.cz/ 
http://www.sub-titles.net 
http://subtitles.co.il/ - English, hebrew, russian 
http://www.podnapisi.net/ - Eastern Languages, English 
http://divxstation.com/subtitles.asp 
http://www.subbiee.com - search engine 

英语字幕站(English Language)

DivXSubtitles 
http://www.divxsubtitles.net/ 

DVD.box.sk 
http://dvd.box.sk/ 

Subtitles.CZ 
http://www.subtitles.cz/en/ 

Kloofy‘s 
http://kloofy.vze.com/ 

english subs for asian movies
www.kloofy.net/modules/news/ 

DivxStation - Subtitles 
http://divxstation.com/searchsubtitles.asp 

DIVXsubs 
http://www.divxsubs.com/ 

SuperSubtitles 
http://www.subpage.net/ 

TV Shows (eng, cz)
http://www.titulkykserialum.net/en/ 

englis subs for asian cinema   
http://hardcore.xo.st/     

Subland 
http://www.hot.ee/subland/        

Bollywood印度语字幕站(Bollywood/Indian language subs) 
http://www.desisubs.com/ 

DivXToday 
http://www.divxtoday.com/subtitles.html 

荷兰语字幕站(Dutch Language) 
http://www.nlondertitels.com/ 
http://www.ondertitels.net/site/ 

芬兰语字幕站(Finnish Language) 
http://www.hot.ee/subland/ Finnish, estonian and english 
http://subsearch.kapsi.fi/   search engine for finnish, english and estonian subs 
http://www.divxfinland.org/divxfi/index.html 
http://www.divxnurkka.net/ 
http://www.xvidsubs.com/ 

法语字幕站(French Language) 
http://davidbillemont5.free.fr/ 

德语字幕站(German Language) 
http://www.subtitles.de/ 

希伯来语字幕站(Hebrew Language) 
http://www.lala.co.il/ 
http://subtitles.co.il/ 

马吉尔语(匈牙利语)字幕站(Magyar Language ( Hungarian) )
http://kopasz.host.sk/subs/ 
http://www.feliratok.hu/ 

波兰语字幕站(Polish) 
http://napisy.gwrota.com/ 
http://napisy.info/ 

葡萄牙语(包括巴西)(Portuguese Language ( Brazilian Included ) )
Central Subtitles 
http://www.central-subtitles.com/ 

Legendas Tugas 
http://www.legendastugas.pt.vu/ 

Legendas-PT 
http://www.legendas-ed2k.com 

LegendasDivX 
http://www.legendasdivx.com/nuke6/ 

CinemaMania 
http://www.cinemania.filmesdivx.com/modules/news/ 

Legendario 
http://www.legendaz.com.br/ 

DivxBR 
http://divxbr.net/index.php 

Legendas Brasil 
http://www.legendas.com.br/ 

Legendas Brasil 
http://www.legendasbrasil.com.br/portal/html/index.php 

Legendas Brasil 
Divx  http://www.legendasbrasildivx.hpg2.ig.com.br/ 

Moviez-X 
http://www.moviez-x.com/br/ 

Videoloucos 
http://www.videoloucos.com.br/ 

罗马尼亚语字幕站(Romanian Language) 
Softpedia Subtitles
http://subtitrari.softpedia.com/ 

斯洛文尼亚、克罗地亚、塞尔维亚语字幕站(Slovenian, Croatian, Serbian:)
http://www.slodivx.net/modules.php?...wdownload&cid=1 
http://www.podnapisi.net/ 
http://www.divx-titlovi.com/ 

西班牙语字幕站(Spanish Language) 
http://grupoutopia.unlugar.com/ 
http://www.subdivx.com/ 
http://foro.argenteam.net/ Argenteam:
http://www.allzine.com/Foro/   Spanish subs for asian movies 
http://www.asia-team.net     Spanish subs for asian movies 

土耳其语字幕站(Turkish Language)
DivxForever 
http://www.divxforever.com

DivxPlanet (English - Turkish - Some other Lang.) 
http://www.divxplanet.net       
http://www.organizeatak.com/ 


作者:yangle20081982 发表于2014-6-14 10:30:32 原文链接
阅读:114 评论:0 查看评论
Viewing all 15843 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>