随笔:93 文章:11 评论:22 引用:0
首页 发新随笔
发新文章 联系 聚合管理

2014年3月3日

--查询表空间、表空间大小及表空间对应物理路径

select a.tablespace_name,b.file_name,a.block_size,a.block_size,b.bytes/1024

/1024 "Sum MB" from dba_tablespaces a,dba_data_files b where a.tablespace_name=b.tablespace_name;

--查询表空间使用情况

  SELECT UPPER(F.TABLESPACE_NAME) "表空间名",

  D.TOT_GROOTTE_MB "表空间大小(M)",

  D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",

  TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",

  F.TOTAL_BYTES "空闲空间(M)",

  F.MAX_BYTES "最大块(M)"

  FROM (SELECT TABLESPACE_NAME,

  ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,

  ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES

  FROM SYS.DBA_FREE_SPACE

  GROUP BY TABLESPACE_NAME) F,

  (SELECT DD.TABLESPACE_NAME,

   ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB

  FROM SYS.DBA_DATA_FILES DD

  GROUP BY DD.TABLESPACE_NAME) D

  WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME

  ORDER BY 1;

--查询表空间的free space

  select tablespace_name,

  count(*) as extends,

  round(sum(bytes) / 1024 / 1024, 2) as MB,

  sum(blocks) as blocks

  from dba_free_space

group by tablespace_name;

 

--查询表空间的总容量

  select tablespace_name, sum(bytes) / 1024 / 1024 as MB

  from dba_data_files

  group by tablespace_name;

 

 

--查询表空间使用率

  select total.tablespace_name,

  round(total.MB, 2) as Total_MB,考试大论坛

  round(total.MB - free.MB, 2) as Used_MB,

  round((1 - free.MB / total.MB) * 100, 2) || '%' as Used_Pct

  from (select tablespace_name, sum(bytes) / 1024 / 1024 as MB

  from dba_free_space

  group by tablespace_name) free,

  (select tablespace_name, sum(bytes) / 1024 / 1024 as MB

  from dba_data_files

  group by tablespace_name) total

  where free.tablespace_name = total.tablespace_name;

 

 

1.查找当前表级锁的SQL如下:

select sess.sid,

    sess.serial#,

    lo.oracle_username,

    lo.os_user_name,

    ao.object_name,

    lo.locked_mode

    from v$locked_object lo,

    dba_objects ao,

    v$session sess

where ao.object_id = lo.object_id and lo.session_id = sess.sid;

 

2.杀掉锁表进程:

alter system kill session '436,35123';

 

3.RAC环境中锁查找:

SELECT inst_id,DECODE(request,0,'Holder: ','Waiter: ')||sid sess,

        id1, id2, lmode, request, type,block,ctime

FROM GV$LOCK

WHERE (id1, id2, type) IN

       (SELECT id1, id2, type FROM GV$LOCK WHERE request>0)

ORDER BY id1, request;

  

 

 

4.监控当前数据库谁在运行什么SQL语句

select osuser, username, sql_text 

from  v$session a, v$sqltext b

where  a.sql_address =b.address order by address, piece;

 

 

 

5.找使用CPU多的用户session

select a.sid,spid,status,substr(a.program,1,40) prog, a.terminal,osuser,value/60/100 value

from  v$session a,v$process b,v$sesstat c

where  c.statistic#=12 and 

       c.sid=a.sid and 

       a.paddr=b.addr 

       order by value desc;

 

 

6.查看死锁信息

SELECT (SELECT username

          FROM v$session

         WHERE SID = a.SID) blocker, a.SID, 'is blocking',

       (SELECT username

          FROM v$session

         WHERE SID = b.SID) blockee, b.SID

  FROM v$lock a, v$lock b

 WHERE a.BLOCK = 1 AND b.request > 0 AND a.id1 = b.id1 AND a.id2 = b.id2;

 

 

7.具有最高等待的对象

SELECT   o.OWNER,o.object_name, o.object_type, a.event,

         SUM (a.wait_time + a.time_waited) total_wait_time

    FROM v$active_session_history a, dba_objects o

   WHERE a.sample_time BETWEEN SYSDATE - 30 / 2880 AND SYSDATE

     AND a.current_obj# = o.object_id

GROUP BY o.OWNER,o.object_name, o.object_type, a.event

ORDER BY total_wait_time DESC;

 

 

SELECT   a.session_id, s.osuser, s.machine, s.program, o.owner, o.object_name,

         o.object_type, a.event,

         SUM (a.wait_time + a.time_waited) total_wait_time

    FROM v$active_session_history a, dba_objects o, v$session s

   WHERE a.sample_time BETWEEN SYSDATE - 30 / 2880 AND SYSDATE

     AND a.current_obj# = o.object_id

     AND a.session_id = s.SID

GROUP BY o.owner,

         o.object_name,

         o.object_type,

         a.event,

         a.session_id,

         s.program,

         s.machine,

         s.osuser

ORDER BY total_wait_time DESC;

 

 

 

8.查询当前连接会话数

select s.value,s.sid,a.username

from

v$sesstat S,v$statname N,v$session A

where

n.statistic#=s.statistic# and

name='session pga memory'

and s.sid=a.sid

order by s.value;

 

 

 

9.等待最多的用户

SELECT   s.SID, s.username, SUM (a.wait_time + a.time_waited) total_wait_time

    FROM v$active_session_history a, v$session s

   WHERE a.sample_time BETWEEN SYSDATE - 30 / 2880 AND SYSDATE

GROUP BY s.SID, s.username

ORDER BY total_wait_time DESC;

 

 

 

10.等待最多的SQL

SELECT   a.program, a.session_id, a.user_id, d.username, s.sql_text,

         SUM (a.wait_time + a.time_waited) total_wait_time

    FROM v$active_session_history a, v$sqlarea s, dba_users d

   WHERE a.sample_time BETWEEN SYSDATE - 30 / 2880 AND SYSDATE

     AND a.sql_id = s.sql_id

     AND a.user_id = d.user_id

GROUP BY a.program, a.session_id, a.user_id, s.sql_text, d.username;

 

 

 

11.查看消耗资源最多的SQL

SELECT hash_value, executions, buffer_gets, disk_reads, parse_calls

FROM V$SQLAREA

WHERE buffer_gets > 10000000 OR disk_reads > 1000000

ORDER BY buffer_gets + 100 * disk_reads DESC;

 

 

 

12.查看某条SQL语句的资源消耗

SELECT hash_value, buffer_gets, disk_reads, executions, parse_calls

FROM V$SQLAREA

WHERE hash_Value = 228801498 AND address = hextoraw('CBD8E4B0');

 

 

13.查询会话执行的实际SQL

SELECT   a.SID, a.username, s.sql_text

    FROM v$session a, v$sqltext s

   WHERE a.sql_address = s.address

     AND a.sql_hash_value = s.hash_value

     AND a.status = 'ACTIVE'

ORDER BY a.username, a.SID, s.piece;

 

 

14.显示正在等待锁的所有会话

SELECT * FROM DBA_WAITERS;

 

DDL

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

/*注意点:

 

1.如果在PL/SQL 等工具里打开的话,直接修改下面的代码中[斜体加粗部分]执行

 

2.确保路径存在,比如【D:\oracle\oradata\Oracle9i\】也就是你要保存文件的路径存在

 

/*分为四步 */

 

/*第1步:创建临时表空间  */

 

create temporary tablespace user_temp 

 

tempfile 'D:\oracle\oradata\Oracle9i\user_temp.dbf'

 

size 50m 

 

autoextend on 

 

next 50m maxsize 20480m 

 

extent management local; 

 

 

 

/*第2步:创建数据表空间  */

 

create tablespace user_data 

 

logging 

 

datafile 'D:\oracle\oradata\Oracle9i\user_data.dbf'

 

size 50m 

 

autoextend on 

 

next 50m maxsize 20480m 

 

extent management local; 

 

 

 

/*第3步:创建用户并指定表空间  */

 

create user username identified by password 

 

default tablespace user_data 

 

temporary tablespace user_temp; 

 

 

 

/*第4步:给用户授予权限  */

 

grant connect,resource,dba to username; 

posted @ 2014-03-03 15:48 redcoatjk 阅读(322) | 评论 (0)编辑 收藏

2013年11月4日

摘自: http://www.douban.com/note/235086917/
http://jackleechina.iteye.com/blog/1595397

为什么一般要采用事件监听而不是直接对元素的事件属性(如:onclick、onmouseover)赋值?

原来用事件属性只能赋值一种方法,即:

button1.onclick = function() { alert(1); };
button1.onclick = function() { alert(2); };

这样后面的赋值语句就将前面的onclick属性覆盖了

而使用添加事件监听的方式就可以实现并行。特别是当团队合作时,事件并行的需求增多,比如:监听document对象的鼠标事件或者window对象的载入事件等。使用事件属性则很容易造成事件覆盖掉

使用事件监听有两种方式:attachEvent和addEventListener

attachEvent与addEventListener区别
适应的浏览器版本不同,同时在使用的过程中要注意
attachEvent方法 按钮onclick
addEventListener方法 按钮click
attachEvent方法, (ie系列)
addEventListener方法 Mozilla系列

例子如下:
 1<!DOCTYPE html>
 2<html>
 3
 4<SCRIPT LANGUAGE="JavaScript">
 5function method1(){
 6    alert("method1");
 7}

 8function method2(){
 9    alert("method2");
10}

11function method3(){
12    alert("method3");
13}

14
</SCRIPT>
15<body>
16<input type="button"  value="dom 元素事件属性绑定的按钮" id="button1"/>
17<input type="button"  value="IE浏览器: attachEvent进行事件绑定的按钮" id="btn1"/>
18<input type="button"  value="火狐浏览器: addEventListener进行事件绑定的按钮" id="btn2"/>
19
20<SCRIPT LANGUAGE="JavaScript">
21     /**方法一: 使用元素的事件属性. [这种方式事件只可绑定一次,最后绑定的执行]**/
22     button1.onclick = function() { alert("1-1"); };
23     button1.onclick = function() { alert("1-2"); };
24     /**方法二: 使用attachEvent注册事件. 格式如下object.attachEvent(event,function);**/
25   var btn1Obj = document.getElementById("btn1");
26    btn1Obj.attachEvent("onclick", method1);
27   btn1Obj.attachEvent("onclick", method2);
28    btn1Obj.attachEvent("onclick", method3);
29     /**方法三: addEventListener. 格式如下element.addEventListener(type,listener,useCapture);**/
30    var btn2Obj = document.getElementById("btn2");
31    btn2Obj.addEventListener("click",method1,false);
32    btn2Obj.addEventListener("click",method2,false);
33    btn2Obj.addEventListener("click",method3,false);
34    //执行顺序为method1->method2->method3
35
</SCRIPT>
36<br/>attachEvent按照注册倒叙执行:    执行顺序为method3->method2->method1 
37<br/>addEventListener按照注册顺序执行:    执行顺序为method1->method2->method3 
38</body>
39</html>

相关衍生阅读:

JavaScript欲速则不达——基本处理事件详解和阻止事件传播

posted @ 2013-11-04 14:22 redcoatjk 阅读(415) | 评论 (0)编辑 收藏

2013年4月16日

     摘要: 摘自http://zhangjunhd.blog.51cto.com/113473/20629/ 1.Servlet过滤器 1.1 什么是过滤器 过滤器是一个程序,它先于与之相关的servlet或JSP页面运行在服务器上。过滤器可附加到一个或多个servlet或JSP页面上,并且可以检查进入这些资源的请求信息。在这之后,过滤器可以作如下的选择: ①以常规的方式调用资源(即,调...  阅读全文
posted @ 2013-04-16 17:28 redcoatjk 阅读(243) | 评论 (0)编辑 收藏

2012年9月5日

     摘要: 摘自 http://www.sandzhang.com/blog/2010/04/07/mysql-show-status-explained-detail/ 要查看MySQL运行状态,要优化MySQL运行效率都少不了要运行show status查看各种状态,下面是参考官方文档及网上资料整理出来的中文详细解释:  如有问题,欢迎指正 状态名 作用域 ...  阅读全文
posted @ 2012-09-05 15:33 redcoatjk 阅读(2086) | 评论 (1)编辑 收藏

2012年7月20日

     摘要: 代码中反复开关自动提交没有必要. 其他方面写得还是很不错的.清晰.摘自 http://wangqinqin.iteye.com/blog/547277  PreparedStatement: 1) addBatch()将一组参数添加到PreparedStatement对象内部。 2) executeBatch()将一批参数提交给数据库来执行,如果全部命令执行成功...  阅读全文
posted @ 2012-07-20 15:04 redcoatjk 阅读(18598) | 评论 (1)编辑 收藏
 
摘自 http://neoremind.net/2010/12/preparedstatement_diff/

JDBC中Statement与PreparedStatement的区别

1. statement每次执行sql语句,相关数据库都要执行sql语句的编译;preparedstatement是预编译的, 采用Cache机制(预编译语句,放在Cache中,下次执行相同SQL语句时,则可以直接从Cache中取出来,有利于sql生成查询计划。),对于批量处理可以大大提高效率. 也叫JDBC存储过程。

例如,如果要执行两条sql语句

SELECT colume FROM TABLE WHERE colume=1;
SELECT colume FROM TABLE WHERE colume=2;

会生成两个执行计划

一千个查询就生成一千个执行计划!

PreparedStatement用于使用绑定变量重用执行计划

SELECT colume FROM TABLE WHERE colume=:x;

通过set不同数据只需要生成一次执行计划,可以重用

是否使用绑定变量对系统影响非常大,生成执行计划极为消耗资源

两种实现 速度差距可能成百上千倍

后者使用了PreparedStatement对象,而前者是普通的Statement对象。PreparedStatement对象不仅包含了SQL语句,而且大多数情况下这个语句已经被预编译过,因而当其执行时,只需DBMS运行SQL语句,而不必先编译。当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度

这种转换也给你带来很大的便利,不必重复SQL语句的句法,而只需更改其中变量的值,便可重新执行SQL语句。选择PreparedStatement对象与否,在于相同句法的SQL语句是否执行了多次,而且两次之间的差别仅仅是变量的不同。如果仅仅执行了一次的话,在对数据库只执行一次性存取的时侯,用 Statement 对象进行处理,PreparedStatement 对象的开销比Statement大,对于一次性操作并不会带来额外的好处。

2. PrepareStatement中执行的SQL语句中是可以带参数的,也就是说可以替换变量,尽量采用使用?号的方式传递参数,增加代码的可读性又可以预编译加速;而Statement则不可以。

3. 防止SQL注入。在SQL中包含特殊字符或SQL的关键字(如:’ or 1 or ‘)时,Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。

SQL注入或者说SQL注入攻击就是利用Statement的漏洞完成的,例如用个用户登录,那么form表单有用户名和密码
那么我提交时,在用户名输入框内 输入 “aaa’ or ’a’=’a” 密码框随便输入,那么这样意味着 sql的
查询语言就是 “select * from 表 where 用户名=’aaa’ or ’a’=’a’ and 密码=’123’  ”,这样查询出来所有的数据或者是混乱。那么不被授权的用户照样可以登录,岂不是被黑了?!实际中现在java程序员早都不用这种方式写查询了,一般都用PreparedStatement来查询,或干脆就用hibernate之类的持久层框架,这样通过sql注入就无从谈起了。
posted @ 2012-07-20 11:14 redcoatjk 阅读(4394) | 评论 (2)编辑 收藏

2012年7月19日

摘自:http://ryxxlong.iteye.com/blog/552884

如何修改mysql root密码
  忘记MySQL ROOT密码是在MySQ使用中很常见的问题,可是有很多朋友并不会重置ROOT密码,那叫苦啊,特写此文章与大家交流:

1、编辑MySQL的配置文件:my.ini
一般在MySQL安装目录下有my.ini即MySQL的配置文件。
在此配置文件的最后添加如下一行:
skip-grant-tables
保存退出编辑。

2、然后重启MySQL服务
在命令行下执行:
net stop MySQL
net start MySQL

3、设置新的ROOT密码
然后用命令提示符cd到对应安装目录的bin下执行:
MySQL -u root -p MySQL或mysql -u root -p
直接回车无需密码即可进入数据库了。
此时,在命令行下执行 use mysql;
现在我们执行如下语句把root密码更新为:
update user set password=PASSWORD("root") where user='root';
(注意:此时不用使用mysqladmin -u root -p password '你的新密码'这条命令修改密码,因为'skip-grant-tables'配置,
不信的话,你可以试用一下,它肯定会报如下所示的错误:
F:\Documents and Settings\long>mysqladmin -u root -p password 'root'
Enter password:
Warning: single quotes were not trimmed from the password by your command
line client, as you might have expected.
mysqladmin:
You cannot use 'password' command as mysqld runs
 with grant tables disabled (was started with --skip-grant-tables).
Use: "mysqladmin flush-privileges password '*'" instead)
exit 退出MySQL。

4、还原配置文件并重启服务

然后修改MySQL配置文件把刚才添加的那一行'skip-grant-tables'删除。
再次重起MySQL服务,密码修改完毕。
用新密码root试一下吧,又能登入重新进入mysql了?



附mysql修改密码的一些方法:
1. 用MYSQL的grant语句,例如
mysql -h hostname –u root 命令登录到mysqld server 用grant 命令改变口令:
mysql -h 192.168.1.101 -u root
上边的192.168.1.101 是偶的mysqld 运行机器,你换成自己的,这样登录上去,就可以修改密码了,
其实没必要这么麻烦,直接mysql -u root就可以了。
GRANT ALL ON *.* TO 'root'@'localhost' IDENTIFIED BY 'root' WITH GRANT OPTION

2. mysqladmin -u 用户名 -p 旧密码 password 新密码
例1:给root 加个密码root。首先进入cmd中,然后键入
以下命令,至于在CMD下能否使用mysqladmin,
就要看你的Windows环境变量PATH中是否添加“E:\Program Files\MySQL\MySQL Server 5.1\bin;”(请改为你自己的安装路径)了。)
mysqladmin -u root password root
注:因为开始时root 没有密码,所以-p 旧密码一项就可以省略了。
例2:再将root 的密码改为admin。
mysqladmin –u root -proot password admin(注意-p 不要和后面的密码分
开写,要写在一起,不然会出错,错误如下所示:
F:\Documents and Settings\long>mysqladmin -u root -p root password admin
Enter password: ****
mysqladmin: Unknown command: 'root')
当然你也可以这样写:mysqladmin –u root -p password admin回车,
然后再输入你的旧密码,这样也是完全也可以的,看你的爱好了.
例3:再将root用户的密码去掉.
F:\Documents and Settings\long>mysqladmin -u root -p password  ;
Enter password: root
此时,root用户又没有密码了.可以通过下面的方法设置:
F:\Documents and Settings\long>mysql -u root
mysql>set password for 'root'@'localhost'=password('root');(语法:SET PASSWORD FOR '用户名'@'主机' = PASSWORD('密码'))
mysql>set password for 'root'@'%'=password('root');
//本条可选,这是在配置mysql数据库,如果你选择了允许root通过远程登录进来时,你在mysql数据库下的user表中,
use mysql;
select * from user;可以看到有两条记录,如果你没有配置这一项的话,只会第一条记录!
Host                    User     Password
'localhost', 'root', '*9C9F4927129ECC3209D8550DC8B67156FDBF9418', ...
'%', 'root', '*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B', ...
通过以上设置,root的密码将变为root这样就完成了根用户root密码的设置工作。

3. use mysql;
 update user set password =password('yourpass') where user='root'

(注:下面的这些方法我本人没有试过,不知对不对,我只是转载了一下:)
下面的方法都在mysql提示符下使用,且必须有mysql的root权限:
方法4
mysql> INSERT INTO mysql.user (Host,User,Password)
VALUES('%','jeffrey',PASSWORD('biscuit'));
mysql> FLUSH PRIVILEGES
确切地说这是在增加一个用户,用户名为jeffrey,密码为biscuit。
在《mysql中文参考手册》里有这个例子,所以我也就写出来了。
注意要使用PASSWORD函数,然后还要使用FLUSH PRIVILEGES。

方法5
和方法三一样,只是使用了REPLACE语句
mysql> REPLACE INTO mysql.user (Host,User,Password)
VALUES('%','jeffrey',PASSWORD('biscuit'));
mysql> FLUSH PRIVILEGES

方法6
使用SET PASSWORD语句,
mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('biscuit');
你也必须使用PASSWORD()函数,
但是不需要使用FLUSH PRIVILEGES。


方法7
使用GRANT ... IDENTIFIED BY语句
mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'biscuit';
这里PASSWORD()函数是不必要的,也不需要使用FLUSH PRIVILEGES。

注:mysql 新设置用户或更改密码后需用flush privileges刷新MySQL的系统权限相关表,
否则会出现拒绝访问,还有一种方法,就是重新启动mysql服务器,来使新设置生效。

posted @ 2012-07-19 10:54 redcoatjk 阅读(306) | 评论 (0)编辑 收藏

2012年6月13日

怎么查看端口占用情况?

       开始--运行--cmd 进入命令提示符 输入netstat -ano 即可看到所有连接的PID 之后在任务管理器中找到这个PID所对应的程序如果任务管理器中没有PID这一项,可以在任务管理器中选"查看"-"选择列"

        经常,我们在启动应用的时候发现系统需要的端口被别的程序占用,如何知道谁占有了我们需要的端口,很多人都比较头疼,下面就介绍一种非常简单的方法,希望对大家有用

假如我们需要确定谁占用了我们的9050端口

1、Windows平台
在windows命令行窗口下执行:

C:\>netstat -aon|findstr "9050"

TCP 127.0.0.1:9050 0.0.0.0:0 LISTENING 2016


看到了吗,端口被进程号为2016的进程占用,继续执行下面命令:

C:\>tasklist|findstr "2016"

tor.exe 2016 Console 0 16,064 K

很清楚吧,tor占用了你的端口。

posted @ 2012-06-13 13:51 redcoatjk 阅读(238) | 评论 (0)编辑 收藏

2012年2月27日

JSON 即 JavaScript Object Natation,它是一种轻量级的数据交换格式,非常适合于服务器与 JavaScript 的交互。本文将快速讲解 JSON 格式,并通过代码示例演示如何分别在客户端和服务器端进行 JSON 格式数据的处理。
管有许多宣传关于 XML 如何拥有跨平台,跨语言的优势,然而,除非应用于 Web Services,否则,在普通的 Web 应用中,开发者经常为 XML 的解析伤透了脑筋,无论是服务器端生成或处理 XML,还是客户端用 JavaScript 解析 XML,都常常导致复杂的代码,极低的开发效率。实际上,对于大多数 Web 应用来说,他们根本不需要复杂的 XML 来传输数据,XML 的扩展性很少具有优势,许多 AJAX 应用甚至直接返回 HTML 片段来构建动态 Web 页面。和返回 XML 并解析它相比,返回 HTML 片段大大降低了系统的复杂性,但同时缺少了一定的灵活性。

现在, JSON 为 Web 应用开发者提供了另一种数据交换格式。让我们来看看 JSON 到底是什么,同 XML 或 HTML 片段相比,JSON 提供了更好的简单性和灵活性。

JSON 数据格式解析

和 XML 一样,JSON 也是基于纯文本的数据格式。由于 JSON 天生是为 JavaScript 准备的,因此,JSON 的数据格式非常简单,您可以用 JSON 传输一个简单的 String,Number,Boolean,也可以传输一个数组,或者一个复杂的 Object 对象。

String,Number 和 Boolean 用 JSON 表示非常简单。例如,用 JSON 表示一个简单的 String “ abc ”,其格式为:

"abc"

这与绝大多数编程语言的表示方法一致,例如:

12345(整数)
-3.9e10(浮点数)

Boolean 类型表示为 truefalse 。此外,JavaScript 中的 null 被表示为 null,注意,truefalsenull 都没有双引号,否则将被视为一个 String 。

JSON 还可以表示一个数组对象,使用 [] 包含所有元素,每个元素用逗号分隔,元素可以是任意的 Value,例如,以下数组包含了一个 String,Number,Boolean 和一个 null:

["abc",12345,false,null]

Object 对象在 JSON 中是用 {} 包含一系列无序的 Key-Value 键值对表示的,实际上此处的 Object 相当于 Java 中的 Map<String, Object>,而不是 Java 的 Class 。注意 Key 只能用 String 表示。

例如,一个 Address 对象包含如下 Key-Value:

city:Beijing 
street:Chaoyang Road
postcode:100025(整数)

用 JSON 表示如下:

{"city":"Beijing","street":" Chaoyang Road ","postcode":100025}

其中 Value 也可以是另一个 Object 或者数组,因此,复杂的 Object 可以嵌套表示,例如,一个 Person 对象包含 name 和 address 对象,可以表示如下:

{"name":"Michael","address":
{"city":"Beijing","street":" Chaoyang Road ","postcode":100025}
}

JavaScript 处理 JSON 数据

上面介绍了如何用 JSON 表示数据,接下来,我们还要解决如何在服务器端生成 JSON 格式的数据以便发送到客户端,以及客户端如何使用 JavaScript 处理 JSON 格式的数据。

我们先讨论如何在 Web 页面中用 JavaScript 处理 JSON 数据。我们通过一个简单的 JavaScript 方法就能看到客户端如何将 JSON 数据表示给用户:

function handleJson() { 
var j={"name":"Michael","address":
{"city":"Beijing","street":" Chaoyang Road ","postcode":100025}
};
document.write(j.name);
document.write(j.address.city);
}

假定服务器返回的 JSON 数据是上文的:

{"name":"Michael","address":
{"city":"Beijing","street":" Chaoyang Road ","postcode":100025}
}

只需将其赋值给一个 JavaScript 变量,就可以立刻使用该变量并更新页面中的信息了,相比 XML 需要从 DOM 中读取各种节点而言,JSON 的使用非常容易。我们需要做的仅仅是发送一个 Ajax 请求,然后将服务器返回的 JSON 数据赋值给一个变量即可。有许多 Ajax 框架早已包含了处理 JSON 数据的能力,例如 Prototype(一个流行的 JavaScript 库:http://prototypejs.org)提供了 evalJSON() 方法,能直接将服务器返回的 JSON 文本变成一个 JavaScript 变量:

new Ajax.Request("http://url", { 
method: "get",
onSuccess: function(transport) {
var json = transport.responseText.evalJSON();
// TODO: document.write(json.xxx);
}
});

服务器端输出 JSON 格式数据

下面我们讨论如何在服务器端输出 JSON 格式的数据。以 Java 为例,我们将演示将一个 Java 对象编码为 JSON 格式的文本。

将 String 对象编码为 JSON 格式时,只需处理好特殊字符即可。另外,必须用 (") 而非 (') 表示字符串:


static String string2Json(String s) {
StringBuilder sb = new StringBuilder(s.length()+20);
sb.append('\"');
for (int i=0; i<s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '\"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '/':
sb.append("\\/");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
default:
sb.append(c);
}
}
sb.append('\"');
return sb.toString();
}

将 Number 表示为 JSON 就容易得多,利用 Java 的多态,我们可以处理 Integer,Long,Float 等多种 Number 格式:


static String number2Json(Number number) {
return number.toString();
}

Boolean 类型也可以直接通过 toString() 方法得到 JSON 的表示:


static String boolean2Json(Boolean bool) {
return bool.toString();
}

要将数组编码为 JSON 格式,可以通过循环将每一个元素编码出来:


static String array2Json(Object[] array) {
if (array.length==0)
return "[]";
StringBuilder sb = new StringBuilder(array.length << 4);
sb.append('[');
for (Object o : array) {
sb.append(toJson(o));
sb.append(',');
}
// 将最后添加的 ',' 变为 ']':
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}

最后,我们需要将 Map<String, Object> 编码为 JSON 格式,因为 JavaScript 的 Object 实际上对应的是 Java 的 Map<String, Object> 。该方法如下:


static String map2Json(Map<String, Object> map) {
if (map.isEmpty())
return "{}";
StringBuilder sb = new StringBuilder(map.size() << 4);
sb.append('{');
Set<String> keys = map.keySet();
for (String key : keys) {
Object value = map.get(key);
sb.append('\"');
sb.append(key);
sb.append('\"');
sb.append(':');
sb.append(toJson(value));
sb.append(',');
}
// 将最后的 ',' 变为 '}':
sb.setCharAt(sb.length()-1, '}');
return sb.toString();
}

为了统一处理任意的 Java 对象,我们编写一个入口方法 toJson(Object),能够将任意的 Java 对象编码为 JSON 格式:


public static String toJson(Object o) {
if (o==null)
return "null";
if (o instanceof String)
return string2Json((String)o);
if (o instanceof Boolean)
return boolean2Json((Boolean)o);
if (o instanceof Number)
return number2Json((Number)o);
if (o instanceof Map)
return map2Json((Map<String, Object>)o);
if (o instanceof Object[])
return array2Json((Object[])o);
throw new RuntimeException("Unsupported type: " + o.getClass().getName());
}

我们并未对 Java 对象作严格的检查。不被支持的对象(例如 List)将直接抛出 RuntimeException 。此外,为了保证输出的 JSON 是有效的,Map<String, Object> 对象的 Key 也不能包含特殊字符。细心的读者可能还会发现循环引用的对象会引发无限递归,例如,精心构造一个循环引用的 Map,就可以检测到 StackOverflowException


@Test(expected=StackOverflowError.class)
public void testRecurrsiveMap2Json() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("key", map);
JsonUtil.map2Json(map);
}

好在服务器处理的 JSON 数据最终都应该转化为简单的 JavaScript 对象,因此,递归引用的可能性很小。

最后,通过 Servlet 或 MVC 框架输出 JSON 时,需要设置正确的 MIME 类型(application/json)和字符编码。假定服务器使用 UTF-8 编码,则可以使用以下代码输出编码后的 JSON 文本:


response.setContentType("application/json;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter pw = response.getWriter();
pw.write(JsonUtil.toJson(obj));
pw.flush();

小结

JSON 已经是 JavaScript 标准的一部分。目前,主流的浏览器对 JSON 支持都非常完善。应用 JSON,我们可以从 XML 的解析中摆脱出来,对那些应用 Ajax 的 Web 2.0 网站来说,JSON 确实是目前最灵活的轻量级方案。

posted @ 2012-02-27 11:00 redcoatjk 阅读(315) | 评论 (0)编辑 收藏

2012年2月14日

JNDI是 Java 命名与目录接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之一,不少专家认为,没有透彻理解JNDI的意义和作用,就没有真正掌握J2EE特别是EJB的知识。
那么,JNDI到底起什么作用?

要了解JNDI的作用,我们可以从“如果不用JNDI我们怎样做?用了JNDI后我们又将怎样做?”这个问题来探讨。

没有JNDI的做法:
程序员开发时,知道要开发访问MySQL数据库的应用,于是将一个对 MySQL JDBC 驱动程序类的引用进行了编码,并通过使用适当的 JDBC URL 连接到数据库。
就像以下代码这样:

Connection conn=null;
try {Class.forName("com.mysql.jdbc.Driver",true, Thread.currentThread().getContextClassLoader());
conn=DriverManager.getConnection("jdbc:mysql://MyDBServer?user=qingfeng&password=mingyue");
/* 使用conn并进行SQL操作 */......
conn.close();
}
catch(Exception e)
{e.printStackTrace();}
finally {if(conn!=null)
{try {conn.close();}
catch(SQLException e) {
}}}

这是传统的做法,也是以前非Java程序员(如Delphi、VB等)常见的做法。这种做法一般在小规模的开发过程中不会产生问题,只要程序员熟悉Java语言、了解JDBC技术和MySQL,可以很快开发出相应的应用程序。

没有JNDI的做法存在的问题:
1、数据库服务器名称MyDBServer 、用户名和口令都可能需要改变,由此引发JDBC URL需要修改;
2、数据库可能改用别的产品,如改用DB2或者Oracle,引发JDBC驱动程序包和类名需要修改;
3、随着实际使用终端的增加,原配置的连接池参数可能需要调整;
4、......

解决办法:
程序员应该不需要关心“具体的数据库后台是什么?JDBC驱动程序是什么?JDBC URL格式是什么?访问数据库的用户名和口令是什么?”等等这些问题,程序员编写的程序应该没有对 JDBC 驱动程序的引用,没有服务器名称,没有用户名称或口令 —— 甚至没有数据库池或连接管理。而是把这些问题交给J2EE容器来配置和管理,程序员只需要对这些配置和管理进行引用即可。

由此,就有了JNDI。

用了JNDI之后的做法:
首先,在在J2EE容器中配置JNDI参数,定义一个数据源,也就是JDBC引用参数,给这个数据源设置一个名称;然后,在程序中,通过数据源名称引用数据源从而访问后台数据库。
具体操作如下(以JBoss为例):
1、配置数据源
在JBoss的 D:\jboss420GA\docs\examples\jca 文件夹下面,有很多不同数据库引用的数据源定义模板。将其中的 mysql-ds.xml 文件Copy到你使用的服务器下,如 D:\jboss420GA\server\default\deploy。
修改 mysql-ds.xml 文件的内容,使之能通过JDBC正确访问你的MySQL数据库,如下:
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
    <jndi-name>MySqlDS</jndi-name>
    <connection-url>jdbc:mysql://localhost:3306/lw</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password>rootpassword</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
    <metadata>
       <type-mapping>mySQL</type-mapping>
    </metadata>
</local-tx-datasource>
</datasources>

这里,定义了一个名为MySqlDS的数据源,其参数包括JDBC的URL,驱动类名,用户名及密码等。

2、在程序中引用数据源:

Connection conn=null;
try
{
Context ctx=new InitialContext();
Object datasourceRef=ctx.lookup("java:MySqlDS");
//引用数据源
DataSource ds=(Datasource)datasourceRef;
conn=ds.getConnection();
/* 使用conn进行数据库SQL操作 */......
c.close();
}
catch(Exception e)
{e.printStackTrace();}
finally {if(conn!=null)
{
try
{
conn.close();
}
catch(SQLException e)
{
}}}
直接使用JDBC或者通过JNDI引用数据源的编程代码量相差无几,但是现在的程序可以不用关心具体JDBC参数了。
在系统部署后,如果数据库的相关参数变更,只需要重新配置 mysql-ds.xml 修改其中的JDBC参数,只要保证数据源的名称不变,那么程序源代码就无需修改。

由此可见,JNDI避免了程序与数据库之间的紧耦合,使应用更加易于配置、易于部署。

JNDI的扩展:
JNDI在满足了数据源配置的要求的基础上,还进一步扩充了作用:所有与系统外部的资源的引用,都可以通过JNDI定义和引用。

所以,在J2EE规范中,J2EE 中的资源并不局限于 JDBC 数据源。引用的类型有很多,其中包括资源引用(已经讨论过)、环境实体和 EJB 引用。特别是 EJB 引用,它暴露了 JNDI 在 J2EE 中的另外一项关键角色:查找其他应用程序组件。

EJB 的 JNDI 引用非常类似于 JDBC 资源的引用。在服务趋于转换的环境中,这是一种很有效的方法。可以对应用程序架构中所得到的所有组件进行这类配置管理,从 EJB 组件到 JMS 队列和主题,再到简单配置字符串或其他对象,这可以降低随时间的推移服务变更所产生的维护成本,同时还可以简化部署,减少集成工作。 外部资源”。


总结:
J2EE 规范要求所有 J2EE 容器都要提供 JNDI 规范的实现。JNDI 在 J2EE 中的角色就是“交换机” —— J2EE 组件在运行时间接地查找其他组件、资源或服务的通用机制。在多数情况下,提供 JNDI 供应者的容器可以充当有限的数据存储,这样管理员就可以设置应用程序的执行属性,并让其他应用程序引用这些属性(Java 管理扩展(Java Management Extensions,JMX)也可以用作这个目的)。JNDI 在 J2EE 应用程序中的主要角色就是提供间接层,这样组件就可以发现所需要的资源,而不用了解这些间接性。

在 J2EE 中,JNDI 是把 J2EE 应用程序合在一起的粘合剂,JNDI 提供的间接寻址允许跨企业交付可伸缩的、功能强大且很灵活的应用程序。这是 J2EE 的承诺,而且经过一些计划和预先考虑,这个承诺是完全可以实现的。
posted @ 2012-02-14 10:24 redcoatjk 阅读(324) | 评论 (0)编辑 收藏
CALENDER
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(3)

随笔分类(22)

随笔档案(76)

文章分类(12)

文章档案(17)

搜索

  •  

积分与排名

  • 积分 - 249250
  • 排名 - 227

最新评论

评论排行榜


Powered By: 博客园
模板提供沪江博客