??xml version="1.0" encoding="utf-8" standalone="yes"?> 丰富的数据结构得redis的设计非常的有趣。不像关pd数据库那PDEV和DBA需要深度沟通,review每行sql语句Q也不像memcached那样Q不需要DBA的参与。redis的DBA需要熟(zhn)数据结构,q能?jin)解使用场景?/p>
下面举一些常见适合kv数据库的例子来谈谈键值的设计Qƈ与关pd数据库做一个对比,发现关系型的不之处?/p>
记录用户d信息的一个系l, 我们化业务后只留下一张表?/p>
user_id表的主键Qname表示用户名,login_times表示该用L(fng)dơ数Q每ơ用L(fng)录后Qlogin_times?x)自增,而last_login_time更新为当前时间?/p>
关系型数据{化ؓ(f)KV数据库,我的Ҏ(gu)如下Q?/p>
key 表名Q主键|(x)列名 value 列?/p>
一般用冒号做分割W,q是不成文的规矩。比如在php-admin for redispȝ里,是默认以冒号分Ԍ于是user:1 user:2{key?x)分成一l。于是以上的关系数据转化成kv数据后记录如下:(x) q样在已知主键的情况下,通过get、set可以获得或者修改用L(fng)dơ数和最后登录时间和姓名?/p>
一般用h无法知道自己的id的,只知道自q用户名,所以还必须有一个从name到id的映关p,q里的设计与上面的有所不同?/p>
q样每次用户d的时候业务逻辑如下Qpython版)(j)Qr是redis对象Qname是已l获知的用户名?/p>
如果需求仅仅是已知idQ更新或者获取某个用L(fng)最后登录时_(d)dơ数Q关pd和kv数据库无啥区别。一个通过btree pkQ一个通过hashQ效果都很好?/p>
假设有如下需求,查找最q登录的N个用戗开发h员看看,q是比较单的Q一个sql搞定?/p>
DBA?jin)解需求后Q考虑C后表如果比较大,所以在last_login_time上徏个烦(ch)引。执行计划从索引leafblock 的最双开始访问N条记录,再回表Nơ,效果很好?/p>
q了(jin)两天Q又来一个需求,需要知道登录次数最多的人是谁。同L(fng)关系型如何处理?DEV说简?/p>
DBA一看,又要在login_time上徏立一个烦(ch)引。有没有觉得有点问题呢,表上每个字段上都有素引?/p>
关系型数据库的数据存储的的不灉|是问题的源头Q数据仅有一U储存方法,那就是按行排列的堆表。统一的数据结构意味着你必M用烦(ch)引来改变sql的访问\径来快速访问某个列的,而访问\径的增加又意味着你必M用统计信息来辅助Q于是一大堆的问题就出现?jin)?/p>
没有索引Q没有统计计划,没有执行计划Q这是kv数据库?/p>
redis里如何满以上的需求呢Q?对于求最新的N条数据的需求,链表的后q后出的特点非常适合。我们在上面的登录代码之后添加一D代码,l护一个登录的链表Q控制他的长度,使得里面永远保存的是最q的N个登录用戗?/p>
q样需要获得最新登录h的idQ如下的代码卛_ 另外Q求dơ数最多的人,对于排序Q积分榜q类需求,sorted set非常的适合Q我们把用户和登录次数统一存储在一个sorted set里?/p>
q样假如某个用户dQ额外维护一个sorted setQ代码如?/p>
那么如何获得dơ数最多的用户呢,逆序排列取的排名WN的用户即?/p>
可以看出QDEV需要添?行代码,而DBA不需要考虑索引什么的?/p>
tag在互联网应用里尤其多见,如果以传l的关系型数据库来设计有点不伦不cR我们以查找书的例子来看看redis在这斚w的优ѝ?/p>
两张表,一张book的明l,一张tag表,表示每本的tagQ一本书存在多个tag?/p>
tag表自兌2ơ再与book兌Q这个sqlq是比较复杂的,如果要求即rubyQ但不是web斚w的书c呢Q?/p>
关系型数据其实ƈ不太适合q些集合操作?/p>
首先book的数据肯定要存储的,和上面一栗?/p>
tag表我们用集合来存储数据Q因为集合擅长求交集、ƈ?/p>
那么Q即属于ruby又属于web的书Q?/p>
卛_于rubyQ但不属于web的书Q?/p>
属于ruby和属于web的书的合集? 单到不行ѝ?/p>
从以?个例子可以看出在某些场景里,关系型数据库是不太适合的,你可能能够设计出满需求的pȝQ但L感觉的怪怪的Q有U生搬硬套的感觉?/p>
其dpȝq个例子Q频J的Z务徏立烦(ch)引。放在一个复杂的pȝ里,ddlQ创建烦(ch)引)(j)有可能改变执行计划。导致其它的sql采用不同的执行计 划,业务复杂的老系l,q个问题是很N估的Qsql千奇百怪。要求DBA对这个系l里所有的sql都了(jin)解,q点太难?jin)。这个问题在oracle里尤其严 重,每个DBA估计都碰到过。对于MySQLq类pȝQddl又不方便Q虽然现在有online ddl的方法)(j)。碰到大表,DBA凌晨爬v来在业务低峰期操作,q事我没干q。而这U需求放到redis里就很好处理QDBA仅仅对容量进行预估即可?/p>
未来的OLTPpȝ应该是kv和关pd的紧密结合?/p>
来源Q?a target="_blank" rel="nofollow">www.hoterran.info (1)非静(rn)态对象的初始?/p>
在创建对象时Q对象所在类的所有数据成员(sh)(x)首先q行初始化?/p>
基本cdQ?a class="bluekey" target="_blank">int型,初始化ؓ(f)0?/p>
如果为对象:(x)q些对象?x)按序初始化?/p>
d所有类成员初始化完成之后,才调用本cȝ构造方法创建对象?/p>
构造方法的作用是初始化?/p>
(2)?rn)态对象的初始?/p>
E序中主cȝ?rn)态变量会(x)在mainҎ(gu)执行前初始化?/p>
不仅W一ơ创建对象时Q类中的所有静(rn)态变量都初始化,q且W一ơ访问某c?注意此时未创建此cd?的静(rn)态对象时Q所有的?rn)态变量也要按它们在类中的序初始化?/p>
2、(h)承时Q对象的初始化过E? (1)ȝ的超cȝ高到低按序初始化静(rn)态成员,无论?rn)态成员是否ؓ(f)private?/p>
(2)ȝ?rn)态成员的初始化?/p>
(3)ȝ的超cȝ高到低进行默认构造方法的调用。注意,在调用每一个超cȝ默认构造方法前Q先q行Ҏ(gu)类q行非静(rn)态对象的初始化?/p>
(4)ȝ非静(rn)态成员的初始化?/p>
(5)调用ȝ的构造方法?/p>
3、关于构造方?/font> (1)cd以没有构造方法,但如果有多个构造方法,应该要有默认的构造方法,否则在(h)承此cLQ需要在子类中显式调用父cȝ某一个非默认的构造方法了(jin)?/p>
(2)在一个构造方法中Q只能调用一ơ其他的构造方法,q且调用构造方法的语句必须是第一条语句?/p>
4、有关public、private和protected (1)无public修饰的类Q可以被其他c访问的条g是:(x)a.两个cd同一文g中,b.两个cd同一文g夹中Qc.两个cd同一软g包中?/p>
(2)protectedQ(h)承类和同一软g包的cd讉K?/p>
(3)如果构造方法ؓ(f)privateQ那么在其他cM不能创徏该类的对象?br />
5、抽象类
(1)抽象cM能创建对象?/p>
(2)如果一个类中一个方法ؓ(f)抽象Ҏ(gu)Q则q个cdMؓ(f)abstract抽象cR?/p>
(3)l承抽象cȝcdcM必须实现抽象cM的抽象方法?/p>
(4)抽象cM可以有抽象方法,也可有非抽象Ҏ(gu)。抽象方法不能ؓ(f)private?/p>
(5)间接l承抽象cȝcd以不l出抽象Ҏ(gu)的定义?/p>
6、final关键?/font>
(1)一个对象是帔RQ不代表不能转变对象的成员,仍可以其成员q行操作?/p>
(2)帔R在用前必须赋|但除?jin)在声明的同时初始化外,只能在构造方法中初始化?/p>
(3)final修饰的方法不能被重置(在子cM不能出现同名Ҏ(gu))?/p>
(4)如果声明一个类为finalQ则所有的Ҏ(gu)均ؓ(f)finalQ无论其是否被final修饰Q但数据成员可ؓ(f)final也可不是?/p>
7、接?/font>interface(用implements来实现接? (1)接口中的所有数据均为static和final即静(rn)态常量。尽可以不用这两个关键字修饎ͼ但必ȝ帔R赋初倹{?/p>
(2)接口中的Ҏ(gu)均ؓ(f)publicQ在实现接口cMQ实现方法必dpublic关键字?/p>
(3)如果使用public来修饰接口,则接口必M文g名相同?/p>
8、多重(h)?
(1)一个类l承?jin)一个类和接口,那么必须类写在前面Q接口写在后面,接口之间用逗号分隔?/p>
(2)接口之间可多重(h)承,注意使用关键字extends?/p>
(3)一个类虽只实现?jin)一个接口,但不仅要实现q个接口的所有方法,q要实现q个接口l承的接口的Ҏ(gu)Q接口中的所有方法均dcM实现?/p>
9、接口的嵌入 (1)接口嵌入cMQ可以用private修饰。此Ӟ接口只能在所在的cM实现Q其他类不能讉K?/p>
(2)嵌入接口中的接口一定要为public? (1)cd以嵌入另一个类中,但不能嵌入接口中?/p>
} (2)在静(rn)态方法或其他Ҏ(gu)中,不能直接创徏内部cd象,需通过手段来取得?/p>
手段有两U:(x) class A { class B {} B getB() { B b = new B(); return b; } } static void m() { A a = new A(); A.B ab = a.getB(); // 或者是 A.B ab = a.new B(); } (3)一个类l承?jin)另一个类的内部类Q因cL内部c,而内部类的构造方法不能自动被调用Q这样就需要在子类的构造方法中明确的调用超cȝ构造方法。接上例Q?/p>
class C extends A.B { C() { new A().super(); // q一句就实现?jin)对内部cL造方法的调用?} } 构造方法也可这样写Q?/p>
C(A a) { a.super(); } // 使用q个构造方法创建对象,要写成C c = new C(a); a是A的对象?/p>
11、异常类JAVA中除?jin)RunTimeExceptionc,其他异常均须捕获或抛出?/p>
原文地址Q?a id="viewpost1_TitleUrl" href="/hill/archive/2009/06/12/281852.html" target="_blank">Struts2 如何?jdk 1.4下运?/font> xwork-j4-2.0-beta-1.jar<J4文g?gt; retrotranslator-runtime-1.0.8.jar<J4文g?gt; retrotranslator-transformer-1.0.8.jar<J4文g?gt; freemarker-2.3.4.jar<lib文g?gt; commons-logging-1.0.4.jar<lib文g?gt; backport-util-concurrent.jar<J4文g?gt; (tng) (tng) (tng) (tng) ognl-2.6.7.jar<lib文g?gt; struts2-api-j4-2.0.1.jar<J4文g?gt; 开?j)过好每一天。。。。?/p>
用户dpȝ
关系型数据库的设?/h4>
mysql> select * from login;
+---------+----------------+-------------+---------------------+
| user_id | name (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) | login_times | last_login_time (tng) (tng) (tng) (tng) |
+---------+----------------+-------------+---------------------+
| (tng) (tng) (tng) (tng) (tng) (tng) 1 | ken thompson (tng) (tng) | (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 5 | 2011-01-01 00:00:00 |
| (tng) (tng) (tng) (tng) (tng) (tng) 2 | dennis ritchie | (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1 | 2011-02-01 00:00:00 |
| (tng) (tng) (tng) (tng) (tng) (tng) 3 | Joe Armstrong (tng) | (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 2 | 2011-03-01 00:00:00 |
+---------+----------------+-------------+---------------------+
REDIS的设?/h4>
Set login:1:login_times 5
Set login:2:login_times 1
Set login:3:login_times 2
Set login:1:last_login_time 2011-1-1
Set login:2:last_login_time 2011-2-1
Set login:3:last_login_time 2011-3-1
set login:1:name ”ken thompson?
set login:2:name “dennis ritchie?
set login:3:name ”Joe Armstrong?/pre>
set "login:ken thompson:id" (tng) 1
set "login:dennis ritchie:id" (tng) (tng) (tng) 2
set "login: (tng)Joe Armstrong:id" (tng) 3
1
#获得用户的id
2
uid
=
r.get(
"login:%s:id"
%
name)
3
#自增用户的登录次?/code>
4
ret
=
r.incr(
"login:%s:login_times"
%
uid)
5
#更新该用L(fng)最后登录时?/code>
6
ret
=
r.
set
(
"login:%s:last_login_time"
%
uid, datetime.datetime.now())
1
select
*
from
login
order
by
last_login_time
desc
limit N
1
select
*
from
login
order
by
login_times
desc
limit N
1
#把当前登录hd到链表里
2
ret
=
r.lpush(
"login:last_login_times"
, uid)
3
#保持链表只有N?/code>
4
ret
=
redis.ltrim(
"login:last_login_times"
,
0
, N
-
1
)
1
last_login_list
=
r.lrange(
"login:last_login_times"
,
0
, N
-
1
)
zadd login:login_times 5 1
zadd login:login_times 1 2
zadd login:login_times 2 3
1
#对该用户的登录次数自?
2
ret
=
r.zincrby(
"login:login_times"
,
1
, uid)
1
ret
=
r.zrevrange(
"login:login_times"
,
0
, N
-
1
)
TAGpȝ
关系型数据库的设?/h4>
mysql> select * from book;
+------+-------------------------------+----------------+
| id | name | author |
+------+-------------------------------+----------------+
| 1 | The Ruby Programming Language | Mark Pilgrim |
| 1 | Ruby on rail | David Flanagan |
| 1 | Programming Erlang | Joe Armstrong |
+------+-------------------------------+----------------+
mysql> select * from tag;
+---------+---------+
| tagname | book_id |
+---------+---------+
| ruby | 1 |
| ruby | 2 |
| web | 2 |
| erlang | 3 |
+---------+---------+
假如有如此需求,查找x(chng)ruby又是web斚w的书c,如果以关pd数据库会(x)怎么处理Q?/pre>
1
select
b.
name
, b.author (tng)
from
tag t1, tag t2, book b
2
where
t1.tagname =
'web'
and
t2.tagname =
'ruby'
and
t1.book_id = t2.book_id
and
b.id = t1.book_id
REDIS的设?/h4>
set book:1:name (tng) (tng) (tng)”The Ruby Programming Language?
Set book:2:name (tng) (tng) (tng) ”Ruby on rail?
Set book:3:name (tng) (tng) (tng) ”Programming Erlang?
set book:1:author (tng) (tng) (tng)”Mark Pilgrim?
Set book:2:author (tng) (tng) (tng) ”David Flanagan?
Set book:3:author (tng) (tng) (tng) ”Joe Armstrong?/pre>
sadd tag:ruby 1
sadd tag:ruby 2
sadd tag:web 2
sadd tag:erlang 3
inter_list = redis.sinter("tag.web", "tag:ruby")
inter_list = redis.sdiff("tag.ruby", "tag:web")
inter_list = redis.sunion("tag.ruby", "tag:web")
]]>
#
(tng)注意单位问题Q当需要设|内存大的时候,可以使用cM1k?GB?Mq样的常见格式:(x)
#
#
(tng)1k (tng)=> (tng)1000 (tng)bytes
#
(tng)1kb (tng)=> (tng)1024 (tng)bytes
#
(tng)1m (tng)=> (tng)1000000 (tng)bytes
#
(tng)1mb (tng)=> (tng)1024*1024 (tng)bytes
#
(tng)1g (tng)=> (tng)1000000000 (tng)bytes
#
(tng)1gb (tng)=> (tng)1024*1024*1024 (tng)bytes
#
#
(tng)单位是大写不敏感的Q所?GB (tng)1Gb (tng)1gB的写法都是完全一L(fng)?/span>
#
(tng)Redis默认是不作ؓ(f)守护q程来运行的。你可以把这个设|ؓ(f)"yes"让它作ؓ(f)守护q程来运行?/span>
#
(tng)注意Q当作ؓ(f)守护q程的时候,Redis?x)把q程ID写到 (tng)/var/run/redis.pid
daemonize (tng)no
#
(tng)当以守护q程方式q行的时候,Redis?x)把q程ID默认写到 (tng)/var/run/redis.pid。你可以在这里修改\径?/span>
pidfile (tng)
/
var
/
run
/
redis.pid
#
(tng)接受q接的特定端口,默认?379?/span>
#
(tng)如果端口讄?QRedis׃?x)监听TCP套接字?/span>
port (tng)
6379
#
(tng)如果你想的话Q你可以l定单一接口Q如果这里没单独讄Q那么所有接口的q接都会(x)被监听?/span>
#
#
(tng)bind (tng)127.0.0.1
#
(tng)指定用来监听q接的unxi套接字的路径。这个没有默认|所以如果你不指定的话,Redis׃?x)通过unix套接字来监听?/span>
#
#
(tng)unixsocket (tng)/tmp/redis.sock
#
(tng)unixsocketperm (tng)755
#
一个客L(fng)I闲多少U后关闭q接?0代表用Q永不关?
timeout (tng)0
#
(tng)讄服务器调试等U?/span>
#
(tng)可能|(x)
#
(tng)debug (tng)Q很多信息,对开?试有用Q?/span>
#
(tng)verbose (tng)Q很多精的有用信息,但是不像debug{那么多)(j)
#
(tng)notice (tng)Q适量的信息,基本上是你生产环境中需要的E度Q?/span>
#
(tng)warning (tng)Q只有很重要/严重的信息会(x)记录下来Q?/span>
loglevel (tng)verbose
#
(tng)指明日志文g名。也可以使用"stdout"来强制让Redis把日志信息写到标准输Z?/span>
#
(tng)注意Q如果Redis以守护进E方式运行,而你讄日志昄到标准输出的话,那么日志?x)发送到 (tng)/dev/null
logfile (tng)stdout
#
(tng)要用系l日志记录器很简单,只要讄 (tng)"syslog-enabled" (tng)为?yes" (tng)可以了(jin)?/span>
#
(tng)然后Ҏ(gu)需要设|其他一些syslog参数可以了(jin)?/span>
#
(tng)syslog-enabled (tng)no
#
(tng)指明syslogw䆾
#
(tng)syslog-ident (tng)redis
#
(tng)指明syslog的设备。必L一个用h者是 (tng)LOCAL0 (tng)~ (tng)LOCAL7 (tng)之一?/span>
#
(tng)syslog-facility (tng)local0
#
(tng)讄数据库个数。默认数据库是?tng)DB (tng)0Q你可以通过SELECT (tng)<dbid> (tng)WHERE (tng)dbidQ??databases' (tng)- (tng)1Q来为每个连接用不同的数据库?/span>
databases (tng)
16
#
############################### (tng)快照 (tng)#################################
#
#
(tng)把数据库存到盘?sh)?
#
#
(tng) (tng) (tng)save (tng)<seconds> (tng)<changes>
#
(tng) (tng) (tng)
#
(tng) (tng) (tng)?x)在指定U数和数据变化次C后把数据库写到磁盘(sh)?/span>
#
#
(tng) (tng) (tng)下面的例子将?x)进行把数据写入盘的操?
#
(tng) (tng) (tng)900U(15分钟Q之后,且至?ơ变?/span>
#
(tng) (tng) (tng)300U(5分钟Q之后,且至?0ơ变?/span>
#
(tng) (tng) (tng)60U之后,且至?0000ơ变?/span>
#
#
(tng) (tng) (tng)注意Q你要想不写盘的话把所有?save" (tng)讄注释掉就行了(jin)?/span>
save (tng)
900
(tng)
1
save (tng)
300
(tng)
10
save (tng)
60
(tng)
10000
#
(tng)当导出到 (tng).rdb (tng)数据库时是否用LZF压羃字符串对象?/span>
#
(tng)默认讄为?yes"Q所以几乎L生效的?/span>
#
(tng)如果你想节省CPU的话你可以把q个讄为?no"Q但是如果你有可压羃的key的话Q那数据文g׃(x)更大?jin)?/span>
rdbcompression (tng)yes
#
(tng)数据库的文g?/span>
dbfilename (tng)dump.rdb
#
(tng)工作目录
#
#
(tng)数据库会(x)写到q个目录下,文g名就是上面的 (tng)"dbfilename" (tng)的倹{?/span>
#
(tng)
#
(tng)累加文g也放q里?/span>
#
(tng)
#
(tng)注意你这里指定的必须是目录,不是文g名?/span>
dir (tng).
/
#
################################ (tng)同步 (tng)#################################
#
#
(tng)M同步。通过 (tng)slaveof (tng)配置来实现Redis实例的备份?/span>
#
(tng)注意Q这里是本地从远端复制数据。也是_(d)本地可以有不同的数据库文件、绑定不同的IP、监听不同的端口?/span>
#
#
(tng)slaveof (tng)<masterip> (tng)<masterport>
#
(tng)如果master讄?jin)密码(通过下面的?requirepass" (tng)选项来配|)(j)Q那么slave在开始同步之前必进行n份验证,否则它的同步h?x)被拒绝?/span>
#
#
(tng)masterauth (tng)<master-password>
#
(tng)当一个slave失去和master的连接,或者同步正在进行中Qslave的行为有两种可能Q?/span>
#
#
(tng)1) (tng)如果 (tng)slave-serve-stale-data (tng)讄为?yes" (tng)(默认?Qslave?x)?h)l响应客L(fng)hQ可能是正常数据Q也可能是还没获得值的I数据?/span>
#
(tng)2) (tng)如果 (tng)slave-serve-stale-data (tng)讄为?no"Qslave?x)回?正在从master同步QSYNC (tng)with (tng)master (tng)in (tng)progressQ?来处理各U请求,除了(jin) (tng)I(yng)NFO (tng)和?tng)SLAVEOF (tng)命o(h)?/span>
#
slave
-
serve
-
stale
-
data (tng)yes
#
(tng)slaveҎ(gu)指定的时间间隔向服务器发送pingh?/span>
#
(tng)旉间隔可以通过 (tng)repl_ping_slave_period (tng)来设|?/span>
#
(tng)默认10U?/span>
#
#
(tng)repl-ping-slave-period (tng)10
#
(tng)下面的选项讄?jin)大块数据I/O、向masterh数据和ping响应的过期时间?/span>
#
(tng)默认?0U?/span>
#
#
(tng)一个很重要的事情是Q确保这个值比 (tng)repl-ping-slave-period (tng)大,否则master和slave之间的传输过期时间比预想的要短?/span>
#
#
(tng)repl-timeout (tng)60
#
################################# (tng)安全 (tng)###################################
#
(tng)要求客户端在处理M命o(h)旉要验证n份和密码?/span>
#
(tng)q在你信不过来访者时很有用?/span>
#
#
(tng)Z(jin)向后兼容的话Q这D应该注释掉。而且大多Ch不需要n份验证(例如Q它们运行在自己的服务器上。)(j)
#
(tng)
#
(tng)警告Q因为Redis太快?jin),所以居?j)不良的人可以每U尝?50k的密码来试图破解密码?/span>
#
(tng)q意味着你需要一个高强度的密码,否则破解太容易了(jin)?/span>
#
#
(tng)requirepass (tng)foobared
#
(tng)命o(h)重命?/span>
#
#
(tng)在共享环境下Q可以ؓ(f)危险命o(h)改变名字。比如,你可以ؓ(f) (tng)CONFIG (tng)改个其他不太Ҏ(gu)猜到的名字,q样你自׃然可以用,而别人却没法做坏事了(jin)?/span>
#
#
(tng)例如:
#
#
(tng)rename-command (tng)CONFIG (tng)b840fc02d524045429941cc15f59e41cb7be6c52
#
#
(tng)甚至也可以通过l命令赋g个空字符串来完全用q条命o(h)Q?/span>
#
#
(tng)rename-command (tng)CONFIG (tng)""
#
################################## (tng)限制 (tng)####################################
#
#
(tng)讄最多同时连接客L(fng)数量?/span>
#
(tng)默认没有限制Q这个关pdRedisq程能够打开的文件描q符数量?/span>
#
(tng)Ҏ(gu)?0"表示没有限制?/span>
#
(tng)一旦达到这个限ӞRedis?x)关闭所有新q接q发送错?辑ֈ最大用h上限Qmax (tng)number (tng)of (tng)clients (tng)reachedQ?
#
#
(tng)maxclients (tng)128
#
(tng)不要用比讄的上限更多的内存。一旦内存(sh)用达C限,Redis?x)根据选定的回收策略(参见Qmaxmemmory-policyQ删除key?/span>
#
#
(tng)如果因ؓ(f)删除{略问题Redis无法删除keyQ或者策略设|ؓ(f) (tng)"noeviction"QRedis?x)回复需要更多内存的错误信息l命令?/span>
#
(tng)例如QSET,LPUSH{等。但是会(x)l箋(hu)合理响应只读命o(h)Q比如:(x)GET?/span>
#
#
(tng)在用Redis作ؓ(f)LRU~存Q或者ؓ(f)实例讄?jin)硬性内存限制的时候(使用 (tng)"noeviction" (tng){略Q的时候,q个选项q是满有用的?/span>
#
#
(tng)警告Q当一堆slaveq上辑ֈ内存?sh)限的实例的时候,响应slave需要的输出~存所需内存?sh)计在使用内存当中?/span>
#
(tng)q样当请求一个删除掉的key的时候就不会(x)触发|络问题Q重新同步的事gQ然后slave׃(x)收到一堆删除指令,直到数据库空?jin)?f)止?/span>
#
#
(tng)而言之,如果你有slaveq上一个master的话Q那你把master内存限制讑ְ点儿Q确保有_的系l内存用作输出缓存?/span>
#
(tng)Q如果策略设|ؓ(f)"noeviction"的话׃无所谓了(jin)Q?/span>
#
#
(tng)maxmemory (tng)<bytes>
#
(tng)内存{略Q如果达到内存限制了(jin)QRedis如何删除key。你可以在下面五个策略里面选:(x)
#
(tng)
#
(tng)volatile-lru (tng)-> (tng)Ҏ(gu)LRU法生成的过期时间来删除?/span>
#
(tng)allkeys-lru (tng)-> (tng)Ҏ(gu)LRU法删除Mkey?/span>
#
(tng)volatile-random (tng)-> (tng)Ҏ(gu)q期讄来随机删除key?/span>
#
(tng)allkeys->random (tng)-> (tng)无差别随机删?/span>
#
(tng)volatile-ttl (tng)-> (tng)Ҏ(gu)最q过期时间来删除Q辅以TTLQ?/span>
#
(tng)noeviction (tng)-> (tng)谁也不删Q直接在写操作时q回错误?/span>
#
(tng)
#
(tng)注意Q对所有策略来_(d)如果Redis找不到合适的可以删除的key都会(x)在写操作时返回一个错误?/span>
#
#
(tng) (tng) (tng) (tng) (tng) (tng) (tng)q里涉及(qing)的命令:(x)set (tng)setnx (tng)setex (tng)append
#
(tng) (tng) (tng) (tng) (tng) (tng) (tng)incr (tng)decr (tng)rpush (tng)lpush (tng)rpushx (tng)lpushx (tng)linsert (tng)lset (tng)rpoplpush (tng)sadd
#
(tng) (tng) (tng) (tng) (tng) (tng) (tng)sinter (tng)sinterstore (tng)sunion (tng)sunionstore (tng)sdiff (tng)sdiffstore (tng)zadd (tng)zincrby
#
(tng) (tng) (tng) (tng) (tng) (tng) (tng)zunionstore (tng)zinterstore (tng)hset (tng)hsetnx (tng)hmset (tng)hincrby (tng)incrby (tng)decrby
#
(tng) (tng) (tng) (tng) (tng) (tng) (tng)getset (tng)mset (tng)msetnx (tng)exec (tng)sort
#
#
(tng)默认值如下:(x)
#
#
(tng)maxmemory-policy (tng)volatile-lru
#
(tng)LRU和最TTL法的实现都不是很精,但是很接q(Z(jin)省内存)(j)Q所以你可以用样例做试?/span>
#
(tng)例如Q默认Redis?x)检查三个key然后取最旧的那个Q你可以通过下面的配|项来设|样本的个数?/span>
#
#
(tng)maxmemory-samples (tng)3
#
############################# (tng)U篏加模式?##############################
#
(tng)默认情况下,Redis是异步的把数据导出到盘?sh)。这U情况下Q当Redis挂掉的时候,最新的数据׃?jin)?/span>
#
(tng)如果不希望丢掉Q何一条数据的话就该用U篏加模式:(x)一旦开启这个模式,Redis?x)把每次写入的数据在接收后都写入?tng)appendonly.aof (tng)文g?/span>
#
(tng)每次启动时Redis都会(x)把这个文件的数据d内存里?/span>
#
#
(tng)注意Q异步导出的数据库文件和U篏加文件可以ƈ存(你得把上面所?save"讄都注释掉Q关掉导出机Ӟ(j)?/span>
#
(tng)如果U篏加模式开启了(jin)Q那么Redis?x)在启动时蝲入日志文件而忽略导出的 (tng)dump.rdb (tng)文g?/span>
#
#
(tng)重要Q查看?tng)BGREWRITEAOF (tng)来了(jin)解当累加日志文g太大?jin)之后,怎么在后台重新处理这个日志文件?/span>
appendonly (tng)no
#
(tng)U篏加文件名字(默认Q?appendonly.aof"Q?/span>
#
(tng)appendfilename (tng)appendonly.aof
#
(tng)fsync() (tng)h操作pȝ马上把数据写到磁盘(sh)Q不要再{了(jin)?/span>
#
(tng)有些操作pȝ?x)真的把数据马上刷到盘(sh);有些则要蹭一下,但是?x)尽快去做?/span>
#
#
(tng)Redis支持三种不同的模式:(x)
#
#
(tng)noQ不要立dQ只有在操作pȝ需要刷的时候再列比较快?/span>
#
(tng)alwaysQ每ơ写操作都立d入到aof文g。慢Q但是最安全?/span>
#
(tng)everysecQ每U写一ơ。折h案?/span>
#
#
(tng)默认的?everysec" (tng)通常来说能在速度和数据安全性之间取得比较好的^衡?/span>
#
(tng)如果你真的理解了(jin)q个意味着什么,那么讄"no"可以获得更好的性能表现Q如果丢数据的话Q则只能拿到一个不是很新的快照Q;
#
(tng)或者相反的Q你选择 (tng)"always" (tng)来牺牲速度保数据安全、完整?/span>
#
#
(tng)如果拿不准,q (tng)"everysec"
#
(tng)appendfsync (tng)always
appendfsync (tng)everysec
#
(tng)appendfsync (tng)no
#
(tng)如果AOF的同步策略设|成 (tng)"always" (tng)或者?everysec"Q那么后台的存储q程Q后台存储或写入AOF日志Q会(x)产生很多盘I(y)/O开销?/span>
#
(tng)某些Linux的配|下?x)Redis因ؓ(f) (tng)fsync() (tng)而阻塞很久?/span>
#
(tng)注意Q目前对q个情况q没有完修正,甚至不同U程的?tng)fsync() (tng)?x)阻塞我们的?tng)write(2) (tng)h?/span>
#
#
(tng)Z(jin)~解q个问题Q可以用下面q个选项。它可以在?tng)BGSAVE (tng)或?tng)BGREWRITEAOF (tng)处理旉止?tng)fsync()?/span>
#
(tng)
#
(tng)q就意味着如果有子q程在进行保存操作,那么Redis处?不可同步"的状态?/span>
#
(tng)q实际上是说Q在最差的情况下可能会(x)丢掉30U钟的日志数据。(默认Linux讑֮Q?/span>
#
(tng)
#
(tng)如果你有延迟的问题那把q个设ؓ(f) (tng)"yes"Q否则就保持 (tng)"no"Q这是保存持久数据的最安全的方式?/span>
no
-
appendfsync
-
on
-
rewrite (tng)no
#
(tng)自动重写AOF文g
#
#
(tng)如果AOF日志文g大到指定癑ֈ比,Redis能够通过 (tng)BGREWRITEAOF (tng)自动重写AOF日志文g?/span>
#
(tng)
#
(tng)工作原理QRedisC上次重写时AOF日志的大(或者重启后没有写操作的话,那就直接用此时的AOF文gQ,
#
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)基准寸和当前尺寸做比较。如果当前尺寸超q指定比例,׃(x)触发重写操作?/span>
#
#
(tng)你还需要指定被重写日志的最尺寸,q样避免?jin)达到约定百分比但尺总然很的情况q要重写?/span>
#
#
(tng)指定癑ֈ比ؓ(f)0?x)禁用AOF自动重写Ҏ(gu)?/span>
auto
-
aof
-
rewrite
-
percentage (tng)
100
auto
-
aof
-
rewrite
-
min
-
size (tng)64mb
#
################################# (tng)慢查询日志?##################################
#
(tng)Redis慢查询日志可以记录超q指定时间的查询。运行时间不包括各种I/O旉?/span>
#
(tng)例如Q连接客L(fng)Q发送响应数据等。只计算命o(h)q行的实际时_(d)q是唯一一U命令运行线E阻塞而无法同时ؓ(f)其他h服务的场景)(j)
#
(tng)
#
(tng)你可以ؓ(f)慢查询日志配|两个参敎ͼ(x)一个是标旉Q单位ؓ(f)微妙Q记录超q个旉的命令?/span>
#
(tng)另一个是慢查询日志长度。当一个新的命令被写进日志的时候,最老的那个记录?x)被删掉?/span>
#
#
(tng)下面的时间单位是微秒Q所?000000是1U。注意,负数旉?x)禁用慢查询日志Q?则会(x)强制记录所有命令?/span>
slowlog
-
log
-
slower
-
than (tng)
10000
#
(tng)q个长度没有限制。只要有_的内存就行。你可以通过 (tng)SLOWLOG (tng)RESET (tng)来释攑ֆ存。(译者注Q日志居然是在内存里的OrzQ?/span>
slowlog
-
max
-
len (tng)
128
#
############################### (tng)虚拟内存 (tng)###############################
#
## (tng)警告Q虚拟内存在Redis (tng)2.4是反对的?/span>
#
## (tng)非常不鼓׃用虚拟内存!Q?/span>
#
(tng)虚拟内存可以使Redis在内存(sh)够的情况下仍然可以将所有数据序列保存在内存里?/span>
#
(tng)Z(jin)做到q一点,高频key?x)调到内存里Q而低频key?x){C换文仉Q就像操作系l用内存页一栗?/span>
#
#
(tng)要用虚拟内存,只要把?vm-enabled" (tng)讄为?yes"QƈҎ(gu)需要设|下面三个虚拟内存参数就可以?jin)?/span>
vm
-
enabled (tng)no
#
(tng)vm-enabled (tng)yes
#
(tng)q是交换文g的\径。估计你猜到?jin),交换文g不能在多个Redis实例之间׃nQ所以确保每个Redis实例使用一个独立交换文件?/span>
#
#
(tng)最好的保存?sh)换文gQ被随机讉KQ的介质是固态硬盘(SSDQ?/span>
#
#
(tng)*** (tng)警告 (tng)*** (tng)如果你用共享主机,那么默认的交换文件放刊W?tmp (tng)下是不安全的?/span>
#
(tng)创徏一个Redis用户可写的目录,q|Redis在这里创Z换文件?/span>
vm
-
swap
-
file (tng)
/
tmp
/
redis.swap
#
(tng)"vm-max-memory" (tng)配置虚拟内存可用的最大内存容量?/span>
#
(tng)如果交换文gq有I间的话Q所有超标部分都?x)放C换文仉?/span>
#
#
(tng)"vm-max-memory" (tng)讄?表示pȝ?x)用掉所有可用内存?/span>
#
(tng)q默认g咋地Q只是把你能用的内存全用掉了(jin)Q留点余量会(x)更好?/span>
#
(tng)例如Q设|ؓ(f)剩余内存?0%-80%?/span>
vm
-
max
-
memory (tng)0
#
(tng)Redis交换文g是分成多个数据页的?/span>
#
(tng)一个可存储对象可以被保存在多个q箋(hu)里Q但是一个数据页无法被多个对象共享?/span>
#
(tng)所以,如果你的数据太大,那么对象就?x)浪?gu)很多I间?/span>
#
(tng)如果数据太,那用于存储的交换I间׃(x)更少Q假定你讄相同的数据页数量Q?/span>
#
#
(tng)如果你用很多小对象Q徏议分尺ؓ(f)64?2个字节?/span>
#
(tng)如果你用很多大对象Q那q大一些的寸?/span>
#
(tng)如果不确定,那就用默认值?)
vm
-
page
-
size (tng)
32
#
(tng)交换文g里数据页L?/span>
#
(tng)Ҏ(gu)内存?sh)分表Q已?未用的数据页分布情况Q,盘?sh)?个数据页?x)消耗内存里1个字节?/span>
#
#
(tng)交换区容量? (tng)vm-page-size (tng)* (tng)vm-pages
#
#
(tng)Ҏ(gu)默认?2字节的数据页寸?34217728的数据页数来,Redis的数据页文g?x)?GBQ而内存里的分表?x)消?6MB内存?/span>
#
#
(tng)Z的应验程序设|最且够用的数字比较好Q下面这个默认值在大多数情况下都是偏大的?/span>
vm
-
pages (tng)
134217728
#
(tng)同时可运行的虚拟内存I(y)/OU程数?/span>
#
(tng)q些U程可以完成从交换文件进行数据读写的操作Q也可以处理数据在内存(sh)盘间的交互和编?解码处理?/span>
#
(tng)多一些线E可以一定程度上提高处理效率Q虽然I/O操作本n依赖于物理设备的限制Q不?x)因为更多的U程而提高单ơ读写操作的效率?/span>
#
#
(tng)Ҏ(gu)??x)关闭线EI/OQƈ?x)开启阻塞虚拟内存机制?/span>
vm
-
max
-
threads (tng)
4
#
############################## (tng)高配置 (tng)###############################
#
(tng)当有大量数据Ӟ适合用哈希编码(需要更多的内存Q,元素数量上限不能过l定限制?/span>
#
(tng)你可以通过下面的选项来设定这些限Ӟ(x)
hash
-
max
-
zipmap
-
entries (tng)
512
hash
-
max
-
zipmap
-
value (tng)
64
#
(tng)与哈希相cMQ数据元素较?yu)的情况下,可以用另一U方式来~码从而节省大量空间?/span>
#
(tng)q种方式只有在符合下面限制的时候才可以用:(x)
list
-
max
-
ziplist
-
entries (tng)
512
list
-
max
-
ziplist
-
value (tng)
64
#
(tng)q有q样一U特D编码的情况Q数据全?4位无W号整型数字构成的字W串?/span>
#
(tng)下面q个配置就是用来限制这U情况下使用q种~码的最大上限的?/span>
set
-
max
-
intset
-
entries (tng)
512
#
(tng)与第一、第二种情况怼Q有序序列也可以用一U特别的~码方式来处理,可节省大量空间?/span>
#
(tng)q种~码只适合长度和元素都W合下面限制的有序序列:(x)
zset
-
max
-
ziplist
-
entries (tng)
128
zset
-
max
-
ziplist
-
value (tng)
64
#
(tng)哈希hQ每100个CPU毫秒?x)拿?个毫U来hRedis的主哈希表(键值映表Q?/span>
#
(tng)redis所用的哈希表实玎ͼ见dict.cQ采用gq哈希刷新机Ӟ(x)你对一个哈希表操作多Q哈希刷新操作就频J;
#
(tng)反之Q如果服务器非常不活跃那么也是用点内存?sh)存哈希表而已?/span>
#
(tng)
#
(tng)默认是每U钟q行10ơ哈希表hQ用来刷新字典,然后快释放内存?/span>
#
#
(tng)Q?/span>
#
(tng)如果你对延迟比较在意的话q (tng)"activerehashing (tng)no"Q每个请求gq?毫秒不太好嘛?/span>
#
(tng)如果你不太在意gq而希望尽快释攑ֆ存的话就讄 (tng)"activerehashing (tng)yes"?/span>
activerehashing (tng)yes
#
################################# (tng)包含 (tng)###################################
#
(tng)包含一个或多个其他配置文g?/span>
#
(tng)q在你有标准配置模板但是每个redis服务器又需要个性设|的时候很有用?/span>
#
(tng)包含文gҎ(gu)允怽引h其他配置文gQ所以好好利用吧?/span>
#
#
(tng)include (tng)/path/to/local.conf
#
(tng)include (tng)/path/to/other.conf
]]>
启动jvm监控服务。它是一个基于rmi的应用,向远E机器提供本机jvm应用E序的信息。默认端?099?br />实例Qjstatd -J-Djava.security.policy=my.policy
my.policy文g需要自己徏立,内如如下Q?br />grant codebase "file:$JAVA_HOME/lib/tools.jar" {
(tng)permission java.security.AllPermission;
};
q是安全{略文gQ因为jdk对jvm做了(jin)jaas的安全检,所以我们必设|一些策略,使得jstatd被允怽|络操作
jps
列出所有的jvm实例
实例Q?br />jps
列出本机所有的jvm实例
jps 192.168.0.77
列出q程服务?92.168.0.77机器所有的jvm实例Q采用rmi协议Q默认连接端口ؓ(f)1099
Q前提是q程服务器提供jstatd服务Q?br />
输出内容如下Q?br />jones@jones:~/data/ebook/java/j2se/jdk_gc$ jps
6286 Jps
6174 (tng) Jstat
jconsole
一个图形化界面Q可以观察到javaq程的gcQclassQ内存等信息。虽然比较直观,但是个hq是比较們于用jstat命o(h)Q在最后一部分?x)对jstat作详l的介绍Q?br />
jinfoQlinux下特有)(j)
观察q行中的javaE序的运行环境参敎ͼ(x)参数包括Java System属性和JVM命o(h)行参?br />实例Qjinfo 2083
其中2083是javaq程idP可以用jps得到q个id受?br />输出内容太多?jin),不在q里一一列DQ大家可以自己尝试这个命令?br />
jstackQlinux下特有)(j)
可以观察到jvm中当前所有线E的q行情况和线E当前状?br />jstack 2083
输出内容如下Q?br />
jmapQlinux下特有,也是很常用的一个命令)(j)
观察q行中的jvm物理内存的占用情c(din)?br />参数如下Q?strong>
-heapQ打印jvm heap的情?br />-histoQ?/strong>打印jvm heap的直方图。其输出信息包括cdQ对象数量,对象占用大小?br />-histoQlive Q?/strong>同上Q但是只{应存活对象的情?br />-permstatQ?/strong>打印permanent generation heap情况
命o(h)使用Q?br />jmap -heap 2083
可以观察到New GenerationQEden SpaceQFrom SpaceQTo SpaceQ?tenured generation,Perm Generation的内存(sh)用情?br />输出内容Q?br />
jmap -histo 2083 ?jmap -histo:live 2083
可以观察heap中所有对象的情况Qheap中所有生存的对象的情况)(j)。包括对象数量和所占空间大?br />输出内容Q?br />
写个脚本Q可以很快把占用heap最大的对象扑և来,对付内存泄漏特别有效?br />
jstat
最后要重点介绍下这个命令?br />q是jdk命o(h)中比较重要,也是相当实用的一个命令,可以观察到classloaderQcompilerQgc相关信息
具体参数如下Q?br />-classQ统计class loader行ؓ(f)信息
-compileQ统计编译行Z?br />-gcQ统计jdk gc时heap信息
-gccapacityQ统计不同的generationsQ不知道怎么译好,包括新生区,老年区,permanent区)(j)相应的heap定w情况
-gccauseQ统计gc的情况,Q同-gcutilQ和引vgc的事?br />-gcnewQ统计gcӞ新生代的情况
-gcnewcapacityQ统计gcӞ新生代heap定w
-gcoldQ统计gcӞ老年区的情况
-gcoldcapacityQ统计gcӞ老年区heap定w
-gcpermcapacityQ统计gcӞpermanent区heap定w
-gcutilQ统计gcӞheap情况
-printcompilationQ不知道q什么的Q一直没用过?br />
一般比较常用的几个参数是:(x)
jstat -class 2083 1000 10 Q每?U监控一ơ,一共做10ơ)(j)
输出内容含义如下Q?br />Loaded Number of classes loaded. Bytes Number of Kbytes loaded. Unloaded Number of classes unloaded. Bytes Number of Kbytes unloaded. Time Time spent performing class load and unload operations.
jstat -gc 2083 2000 20Q每?U监控一ơ,共做10Q?br />输出内容含义如下Q?br />S0C Current survivor space 0 capacity (KB). EC Current eden space capacity (KB). EU Eden space utilization (KB). OC Current old space capacity (KB). OU Old space utilization (KB). PC Current permanent space capacity (KB). PU Permanent space utilization (KB). YGC Number of young generation GC Events. YGCT Young generation garbage collection time. FGC Number of full GC events. FGCT Full garbage collection time. GCT Total garbage collection time.
输出内容Q?br />
如果能熟l运用这些命令,其是在linux下,那么完全可以代替jprofile{监控工具了(jin)Q谁让它收费呢。呵c(din)?br />用命令的好处是速度快,q且辅助于其他命令,比如grep gawk sed{,可以l装多种W合自己需求的工具?
]]>
]]>
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)10、类的嵌?/font>
int j = i;//拆箱
]]>
import
(tng)java.util.Arrays;
public
(tng)
class
(tng)ArraysTester (tng)
{
(tng) (tng) (tng) (tng)
private
(tng)
int
[] (tng)ar;
(tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng)
public
(tng)ArraysTester(
int
(tng)numValues)
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)ar (tng)
=
(tng)
new
(tng)
int
[numValues];
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
for
(
int
(tng)i
=
0
;i
<
ar.length;i
++
)
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)ar[i] (tng)
=
(tng)(
1000
-
(
300
+
i));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng)
public
(tng)
int
[] (tng)get()
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
return
(tng)ar;
(tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng)
/** (tng)*/
/**
(tng) (tng) (tng) (tng) (tng)* (tng)
@param
(tng)args
(tng) (tng) (tng) (tng) (tng)
*/
(tng) (tng) (tng) (tng)
public
(tng)
static
(tng)
void
(tng)main(String[] (tng)args) (tng)
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
//
(tng)TODO (tng)Auto-generated (tng)method (tng)stub
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)ArraysTester (tng)test (tng)
=
(tng)
new
(tng)ArraysTester(
50
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
int
[] (tng)myArray (tng)
=
(tng)test.get();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
int
[] (tng)myOtherArray (tng)
=
(tng)test.get().clone();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
if
(Arrays.equals(myArray, (tng)myOtherArray))
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
相等
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
else
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
不相{?/span>
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)Arrays.fill(myOtherArray, (tng)
2
,
10
,
new
(tng)Double(Math.PI).intValue());
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)myArray[
30
] (tng)
=
(tng)
98
;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
q是一个未排序的数l?img src="http://www.tkk7.com/images/dot.gif" />
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(Arrays.toString(myArray));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)Arrays.sort(myArray);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
q是一个排序的数组
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(Arrays.toString(myArray));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
int
(tng)index (tng)
=
(tng)Arrays.binarySearch(myArray, (tng)
98
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
98被定位在W?/span>
"
+
index
+
"
个位|上
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)String[][] (tng)ticTacToe (tng)
=
(tng)
{
{
"
X
"
,
"
0
"
,
"
0
"
}
,
{
"
0
"
,
"
X
"
,
"
X
"
}
,
{
"
X
"
,
"
0
"
,
"
X
"
}
}
;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(Arrays.deepToString(ticTacToe));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)String[][] (tng)ticTacToe2 (tng)
=
(tng)
{
{
"
0
"
,
"
0
"
,
"
X
"
}
,
{
"
0
"
,
"
X
"
,
"
X
"
}
,
{
"
X
"
,
"
0
"
,
"
X
"
}
}
;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)String[][] (tng)ticTacToe3 (tng)
=
(tng)
{
{
"
X
"
,
"
0
"
,
"
0
"
}
,
{
"
0
"
,
"
X
"
,
"
X
"
}
,
{
"
X
"
,
"
0
"
,
"
X
"
}
}
;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
if
(Arrays.deepEquals(ticTacToe, (tng)ticTacToe2))
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
相等
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
else
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
不相{?/span>
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
if
(Arrays.deepEquals(ticTacToe, (tng)ticTacToe3))
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
相等
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
else
{
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)System.out.println(
"
不相{?/span>
"
);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng)}
}
Arrays.equals(myArray, myOtherArray)---直接比较两个数组是否相等
Arrays.fill(a, val)---数la中所有元素都用val来填?br />Arrays.fill(a, 2,10,val);---数laQ从索引?的元素到W?0的元素用val来填?br />Arrays.sort(a);---按照自然规律排序Q升?br />Arrays.binarySearch(myArray, 98);---搜烦(ch)myArray中gؓ(f)98的烦(ch)引号Qƈq回索引
Arrays.toString(a)--打印数组a格式Q[2asdf, 3asd, afas]
Arrays.deepToString(ticTacToe)--打印多维数组ticTacToe
Arrays.deepEquals(ticTacToe, ticTacToe2)---比较两个多维数组
List<String> d = Arrays.asList(a);---数l{换ؓ(f)List
]]>
首先讲一下Struts2的标准开发环境:(x)
1.Servlet API 2.4
2.JSP API 2.0
3.Java 5
(q算是比较标准吧Q呵?
但是Q在某些情况下你得用JDK1.4来开?比如我参与的目)Q很昄不符合Java 5的这个标准,怎么办?不要慌,Struts2的开发h员已l想C(jin)。先讲一下struts2的包的目录结构吧Q解压struts2的zip?我这里是 struts-2.0.1-all.zip包,官网下的)Q会(x)有如下几个目录和文gQ?br />
appsQ里面一些war文gQ应该是一些用struts2开发的一些例子,我没跑过Q猜得?br />docsQ包含了(jin)API、FAQs{等文gQ打开docs更目录下面的index.jsp自己慢慢览吧?br />j4Q?一?jar文g和其他文档文件?br />libQ?很显然是struts2提供的标准的接口文g?br />srcQ?struts2的源代码?br />LICENSE.txtQ不解释Q?br />NOTICE.txtQ?不解释!
好了(jin)Qstruts2的包l构解释pP如果你是使用标准的开发环?文章头说q的)Q那么你只需要将lib目录下面的文件全部copyC的lib目录下就行了(jin)?br />我要使用JDK1.4的开发环境怎么办?那么׃用J4目录中的东西啦!
在J4目录?已经Struts2基本的两个jar文g转好?分别是struts2-core-j4-2.0.1.jar和xwork-j4-2.0-beta-1.jar?br />
用这两个包替换掉lib里面的struts2-core-2.0.1.jar和xwork-2.0-beta-1.jar两个包就行了(jin)Q如果你的程序中q用到的其他的jar?可以通过脚本把jar包{成J4版本的,比如Q?br />java -jar retrotranslator-transformer-1.2.2.jar -advanced -srcjar ../lib/<名字1>.jar -destjar <名字1>.jar
可以它们写C个Bat文g?如果你用的是Windows的系l的?br />
x(chng),你的E序应该可以在JDK1.4上运行了(jin).
用JDK1.4开发需要的几个基本jar包如下:(x)
注意Q在jdk1.4下运行时Q不要多加jar包。struts2-core,xworkq两个{换成jdk1.4下的版本后,别的不会(x)再{?jin)。如果用别的包Ӟ转一个加一个试试,struts2在加入jar包时Q可能有问题Q用时心(j)?/strong>
]]>
]]>
TopicID | Title | Boardid | PollID | LockTopic | Child | PostUsername | PostUserid | DateAndTime | hits | Expression | VoteTotal | LastPost | LastPostTime | istop | isvote | isbest | PostTable | SmsUserList | IsSmsTopic | LastSmsTime | TopicMode | Mode | GetMoney | UseTools | GetMoneyType | HideName |
201314 | 亲吻北京Q——我们伟大的国Q?/td> | 37 | 0 |
在很多操作中Q比如徏立目?数据库连接都需要这L(fng)单线E操作?/p>
q有, singleton能够被状态化; q样Q多个单态类在一起就可以作ؓ(f)一个状态仓库一样向外提供服务,比如Q你要论坛中的帖子计数器Q每ơ浏览一ơ需要计敎ͼ单态类能否保持住这个计敎ͼq且能synchronize的安全自动加1Q如果你要把q个数字怹保存到数据库Q你可以在不修改单态接口的情况下方便的做到?/p>
另外斚wQSingleton也能够被无状态化。提供工h质的功能,
Singleton模式׃ؓ(f)我们提供?jin)这样实现的可能。用Singleton的好处还在于可以节省内存Q因为它限制?jin)实例的个数Q有利于Java垃圾回收Qgarbage collectionQ?/p>
我们常常看到工厂模式中类装入?class loader)中也用Singleton模式实现?因ؓ(f)被装入的cd际也属于资源?/p>
具体实施:
用静(rn)态方法实?Singleton
q种Ҏ(gu)是用静(rn)态方法来监视实例的创?Z(jin)防止创徏一个以上的实例,我们最好把构造器声明?private.
q样可以防止客户E序员通过除由我们提供的方法之外的L方式来创Z个实?如果不把构造器声明为private,~译器就?x)自作聪明的自动同步一个默认的friendly构造器.q种实现Ҏ(gu)是最常见?