<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆:93 文章:11 評論:22 引用:0
    首頁 發新隨筆
    發新文章 聯系 聚合管理

    2011年11月2日

    --查詢表空間、表空間大小及表空間對應物理路徑

    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 閱讀(345) | 評論 (0)編輯 收藏
     
    摘自: 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 閱讀(436) | 評論 (0)編輯 收藏
     
         摘要: 摘自http://zhangjunhd.blog.51cto.com/113473/20629/ 1.Servlet過濾器 1.1 什么是過濾器 過濾器是一個程序,它先于與之相關的servlet或JSP頁面運行在服務器上。過濾器可附加到一個或多個servlet或JSP頁面上,并且可以檢查進入這些資源的請求信息。在這之后,過濾器可以作如下的選擇: ①以常規的方式調用資源(即,調...  閱讀全文
    posted @ 2013-04-16 17:28 redcoatjk 閱讀(262) | 評論 (0)編輯 收藏
     
         摘要: 摘自 http://www.sandzhang.com/blog/2010/04/07/mysql-show-status-explained-detail/ 要查看MySQL運行狀態,要優化MySQL運行效率都少不了要運行show status查看各種狀態,下面是參考官方文檔及網上資料整理出來的中文詳細解釋:  如有問題,歡迎指正 狀態名 作用域 ...  閱讀全文
    posted @ 2012-09-05 15:33 redcoatjk 閱讀(2112) | 評論 (1)編輯 收藏
     
         摘要: 代碼中反復開關自動提交沒有必要. 其他方面寫得還是很不錯的.清晰.摘自 http://wangqinqin.iteye.com/blog/547277  PreparedStatement: 1) addBatch()將一組參數添加到PreparedStatement對象內部。 2) executeBatch()將一批參數提交給數據庫來執行,如果全部命令執行成功...  閱讀全文
    posted @ 2012-07-20 15:04 redcoatjk 閱讀(18633) | 評論 (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 閱讀(4418) | 評論 (2)編輯 收藏
     
    摘自: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 閱讀(326) | 評論 (0)編輯 收藏
     

    怎么查看端口占用情況?

           開始--運行--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 閱讀(256) | 評論 (0)編輯 收藏
     
    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 閱讀(337) | 評論 (0)編輯 收藏
     
    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 資源的引用。在服務趨于轉換的環境中,這是一種很有效的方法??梢詫贸绦蚣軜嬛兴玫降乃薪M件進行這類配置管理,從 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 閱讀(345) | 評論 (0)編輯 收藏
     

    在Oracle中,要按特定條件查詢前N條記錄,用個rownum就搞定了。
    select * from emp where rownum <= 5
    結果只查詢5條記錄, oracle會自動展現一個rownum的屬性表示記錄排序號

    而select * from emp where rownum > 5 ;則是失敗的。
    因為:rownum是oracle預處理字段,默認標序是1,只有記錄集已經滿足條件后才會進行后續編號。由于第一條記錄rownum默認是1,而你的條件是rownum>=6 對第一條記錄比較它的rownum肯定不大于6 所以不滿足條件 oracle舍棄第一條記錄將數據庫第二條記錄標序為1再進行比較  肯定都不滿足rownum>=6  這樣循環也就是說由于沒有記錄滿足rownum>=6所以記錄一直被舍棄,rownum一直是1 。

    解決方案: 利用查詢時,自動生成的rownum屬性.
    排序方法:
      select * from (
           select a1.*, rownum rwn  from emp a1   where rownum <=10
        ) where rwn >= 6;
      或者
      select * from (
        select qx.*,row_number() over(order by qx.empno) rwn from emp qx
      ) where rwn between 6 and 10
    -------------------------------------------------------------------------
    使用注意:

    1排序導致數據重復:


    table1中表有字段(其余字段省)
    ID  主鍵
    DATA_UPDATE_TIME 數據更新時間(只存儲了年月日)

    分頁查詢的語句如下
    select *
       from (
            select row_.*, rownum rownum_
               from ( select  p.id from table1 p
                 order by  p.DATA_UPDATE_TIME desc )
       row_ where rownum <= )
    where rownum_ >

    以每頁顯示10條為例
    第一次  rownum <= 10)   where rownum_ > 0
    第二次  rownum <= 20)   where rownum_ > 10

    發現有一條記錄在兩次查詢結果中重復出現,不知道問題出在哪里,請忙幫看看。

    另:
    DATA_UPDATE_TIME 的值有重復,不知道跟它有沒有關系。
    如果按ID排的話就不會出現這個問題


    解答:
    如果order by 不能唯一確定記錄的順序就會出現這個問題。
    解決的方法是把分頁部分全部拿到最外層進行。

    Java代碼 復制代碼 收藏代碼
    1. select * from (    
    2.   select row_.*, rownum rownum_    
    3.   from (   
    4.     select p.id from table1 p    
    5.     order by p.DATA_UPDATE_TIME desc    
    6.   ) row_   
    7. )    
    8. where rownum_ > ? and rownum_ <= ?   

    2 排序的id順序:
    Oracle中的rownum的是在取數據的時候產生的序號,所以想對指定排序的數據去指定的rowmun行數據就必須注意了。
    SQL> select rownum ,id,name from student order by name;
        ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
             3 200003 李三
             2 200002 王二
             1 200001 張一
             4 200004 趙四
    可以看出,rownum并不是按照name列來生成的序號。系統是按照記錄插入時的順序給記錄排的號,rowid也是順序分配的。為了解決這個問題,必須使用子查詢
    SQL> select rownum ,id,name from (select * from student order by name);
        ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
             1 200003 李三
             2 200002 王二
             3 200001 張一
             4 200004 趙四
    這樣就成了按name排序,并且用rownum標出正確序號(有小到大)


    ------------
    參考Oracle的rownum原理和使用  http://tenn.iteye.com/blog/99339

    在Oracle中,要按特定條件查詢前N條記錄,用個rownum就搞定了。
    select * from emp where rownum <= 5
    而且書上也告誡,不能對rownum用">",這也就意味著,如果你想用
    select * from emp where rownum > 5
    則是失敗的。要知道為什么會失敗,則需要了解rownum背后的機制:
    1 Oracle executes your query.

    2 Oracle fetches the first row and calls it row number 1.

    3 Have we gotten past row number meets the criteria? If no, then Oracle discards the row, If yes, then Oracle return the row.

    4 Oracle fetches the next row and advances the row number (to 2, and then to 3, and then to 4, and so forth).

    5 Go to step 3.

    了解了原理,就知道rownum>不會成功,因為在第三步的時候查詢出的行已經被丟棄,第四步查出來的rownum仍然是1,這樣永遠也不會成功。

    同樣道理,rownum如果單獨用=,也只有在rownum=1時才有用。

     

    對于rownum來說它是oracle系統順序分配為從查詢返回的行的編號,返回的第一行分配的是1,第二行是2,依此類推,這個偽字段可以用于限制查詢返回的總行數,而且rownum不能以任何表的名稱作為前綴。
     舉例說明:
    例如表:student(學生)表,表結構為:
    ID       char(6)      --學號
    name    VARCHAR2(10)   --姓名
    create table student (ID char(6), name VARCHAR2(100));
    insert into sale values('200001',‘張一’);
    insert into sale values('200002',‘王二’);
    insert into sale values('200003',‘李三’);
    insert into sale values('200004',‘趙四’);
    commit;
    (1) rownum 對于等于某值的查詢條件
    如果希望找到學生表中第一條學生的信息,可以使用rownum=1作為條件。但是想找到學生表中第二條學生的信息,使用rownum=2結果查不到數據。因為rownum都是從1開始,但是1以上的自然數在rownum做等于判斷是時認為都是false條件,所以無法查到rownum = n(n>1的自然數)。
    SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回記錄條數的地方,保證不出錯,如:隱式游標)
    SQL> select rownum,id,name from student where rownum=1;
        ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
             1 200001 張一
    SQL> select rownum,id,name from student where rownum =2;
        ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
    (2)rownum對于大于某值的查詢條件
       如果想找到從第二行記錄以后的記錄,當使用rownum>2是查不出記錄的,原因是由于rownum是一個總是從1開始的偽列,Oracle 認為rownum> n(n>1的自然數)這種條件依舊不成立,所以查不到記錄
    SQL> select rownum,id,name from student where rownum >2;
    ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
    那如何才能找到第二行以后的記錄呀??梢允褂靡韵碌淖硬樵兎椒▉斫鉀Q。注意子查詢中的rownum必須要有別名,否則還是不會查出記錄來,這是因為rownum不是某個表的列,如果不起別名的話,無法知道rownum是子查詢的列還是主查詢的列。
    SQL>select * from(select rownum no ,id,name from student) where no>2;
            NO ID     NAME
    ---------- ------ ---------------------------------------------------
             3 200003 李三
             4 200004 趙四
    SQL> select * from(select rownum,id,name from student)where rownum>2;
        ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
    (3)rownum對于小于某值的查詢條件
    如果想找到第三條記錄以前的記錄,當使用rownum<3是能得到兩條記錄的。顯然rownum對于rownum<n((n>1的自然數)的條件認為是成立的,所以可以找到記錄。
    SQL> select rownum,id,name from student where rownum <3;
        ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
    1 200001 張一
            2 200002 王二
    綜上幾種情況,可能有時候需要查詢rownum在某區間的數據,那怎么辦呀從上可以看出rownum對小于某值的查詢條件是人為true的,rownum對于大于某值的查詢條件直接認為是false的,但是可以間接的讓它轉為認為是true的。那就必須使用子查詢。例如要查詢rownum在第二行到第三行之間的數據,包括第二行和第三行數據,那么我們只能寫以下語句,先讓它返回小于等于三的記錄行,然后在主查詢中判斷新的rownum的別名列大于等于二的記錄行。但是這樣的操作會在大數據集中影響速度。
    SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
            NO ID     NAME
    ---------- ------ ---------------------------------------------------
             2 200002 王二
             3 200003 李三
    (4)rownum和排序
    Oracle中的rownum的是在取數據的時候產生的序號,所以想對指定排序的數據去指定的rowmun行數據就必須注意了。
    SQL> select rownum ,id,name from student order by name;
        ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
             3 200003 李三
             2 200002 王二
             1 200001 張一
             4 200004 趙四
    可以看出,rownum并不是按照name列來生成的序號。系統是按照記錄插入時的順序給記錄排的號,rowid也是順序分配的。為了解決這個問題,必須使用子查詢
    SQL> select rownum ,id,name from (select * from student order by name);
        ROWNUM ID     NAME
    ---------- ------ ---------------------------------------------------
             1 200003 李三
             2 200002 王二
             3 200001 張一
             4 200004 趙四
    這樣就成了按name排序,并且用rownum標出正確序號(有小到大)

    posted @ 2011-11-17 16:46 redcoatjk 閱讀(321) | 評論 (0)編輯 收藏
     
    僅為個人理解.請指正
    Hibernate Session, 其作用無需多言.
    運用中為避免資源消耗,一般都會手動封裝一個HibernateUtil類(未使用Spring管理的前提下).
    該類的作用使Hibernate加載配置文件config, 創建sessionFactory等只運行一次.
    際運用中,經常需要將當前線程和session綁定.一般的用法為使用ThreadLocal: 在HibernateUtil類中封裝hibernate的管理.通過openSession取得
    session,并將其放入ThreadLocal變量中. 這樣業務邏輯中僅需通過工具類取得當前線程對應的session.使用完畢后,調用工具類closeSession方法將
    session關閉,當前線程的ThreadLocal變量置為NULL. 保證線程歸還線程池復用后,ThreadLocal為空,以免出現導致其他線程訪問到本線程變量.
    后,Hibernate的SessionFactory提供獲取session的新方法getCurrentSession (獲得與當前線程綁定的session). 內部通過代理封裝,此方式得到的session
    不僅和當前線程綁定,也無需手動開關. 默認在事務提交之后,session自動關閉. 需注意的是,必須在事務開啟的前提之下才可使用此種方式獲得的session.
    此外hibernate.cfg.xml配置文件中也許配置
    <property name="current_session_context_class">thread</property> 基于線程
    了,引入Spring之后.sessionfactory的創建等都交給spring管理.Spring也提供了HibernateTemplate,HibernateDaoSupport這樣的封裝方法.
    用戶可以不再考慮session的管理,事務的開啟關閉.只需配置事務即可.
    而所謂session關閉后,因延遲加載導致前臺無法顯示的問題以往解決方式為強制全部加載,現在也可通過在web.xml中配置
    org.springframework.orm.hibernate3.support.OpenSessionInViewFilter來解決.



    ------------------------------以下內容為工地資料-------------------------------------------------------------------------------
    OpenSession : 手動打開,需手動關閉.[所以代碼中充斥著try catch --sf.openSession --打開事務,提交-回滾 finall關閉session的代碼]
    threadlocal : hibernate給出的提示. 在HibernateUtil工具類中,new出threadlocal ,放入opensession.這樣可以使當前線程綁定session.
    使用后需關閉session,將threadlocal中session變量置為null .
    3  getCurrentSession: hibernate3的新特性. 無需手動關閉session,自動獲取當前線程的session,若無則新建之. 需在配置文件中配置thread屬性.表明和當前線程綁定.
        參考網友資料,getCurrentSession模式,內部開啟了session自動提交的功能且使用getCurrentSession的session,及時做load操作,也需要打開事務.
    Title

    1 getCurrentSession創建的session會和綁定到當前線程,而openSession不會。

    2 getCurrentSession創建的線程會在事務回滾或事物提交后自動關閉,而openSession必須手動關閉

    這里getCurrentSession本地事務(本地事務:jdbc)時 要在配置文件里進行如下設置

     * 如果使用的是本地事務(jdbc事務)
     <property name="hibernate.current_session_context_class">thread</property>
     * 如果使用的是全局事務(jta事務)
     <property name="hibernate.current_session_context_class">jta</property>

    getCurrentSession () 使用當前的session
    openSession()         重新建立一個新的session

    在一個應用程序中,如果DAO 層使用Spring 的hibernate 模板,通過Spring 來控制session 的生命周期,則首選getCurrentSession ()。

    使用Hibernate的大多數應用程序需要某種形式的“上下文相關的” session,特定的session在整個特定的上下文范圍內始終有效。然而,對不同類型的應用程序而言,要為什么是組成這種“上下文”下一個定義通常 是困難的;不同的上下文對“當前”這個概念定義了不同的范圍。在3.0版本 之前,使用Hibernate的程序要么采用自行編寫的基于 ThreadLocal的上下文session,要么采用HibernateUtil這樣的輔助類,要么采用第三方框架(比如Spring或Pico), 它們提供了基于代理(proxy)或者基于攔截器(interception)的上下文相關session。從3.0.1版本開始,Hibernate增加了SessionFactory.getCurrentSession()方法。一 開始,它假定了采用JTA事務,JTA事務定義了當前session的范圍和上下文(scope and context)。Hibernate開發團隊堅信,因為有好幾個獨立的JTA TransactionManager實現穩定可用,不論是否被部署到一個J2EE容器中,大多數(假若不是所有的)應用程序都應該采用JTA事務管理。 基于這一點,采用JTA的上下文相關session可以滿足你一切需要。

    更好的是,從3.1開始,SessionFactory.getCurrentSession()的后臺實現是可拔插的。因此,我們引入了新的擴展 接口 (org.hibernate.context.CurrentSessionContext)和新的配置參數 (hibernate.current_session_context_class),以便對什么是“當前session”的范圍和上下文(scope and context)的定義進行拔插。

    請參閱 org.hibernate.context.CurrentSessionContext接口的Javadoc,那里有關于它的契約的詳細討論。它定義 了單一的方法,currentSession(),特定的實現用它來負責跟蹤當前的上下文session。Hibernate內置了此接口的兩種實現。

    org.hibernate.context.JTASessionContext - 當前session根據JTA來跟蹤和界定。這和以前的僅支持JTA的方法是完全一樣的。詳情請參閱Javadoc。

    org.hibernate.context.ThreadLocalSessionContext - 當前session通過當前執行的線程來跟蹤和界定。詳情也請參閱Javadoc。

    這兩種實現都提供了“每數據庫事務對應一個session”的編程模型,也稱作每次請求一個session。Hibernate session的起始和終結由數據庫事務的生存來控制。假若你采用自行編寫代碼來管理事務(比如,在純粹的J2SE,或者 JTA/UserTransaction/BMT),建議你使用Hibernate Transaction API來把底層事務實現從你的代碼中隱藏掉。如果你在支持CMT的EJB容器中執行,事務邊界是聲明式定義的,你不需要在代碼中進行任何事務或 session管理操作。請參閱第 11 章 事務和并發一節來閱讀更多的內容和示例代碼。

    hibernate.current_session_context_class 配置參數定義了應該采用哪個org.hibernate.context.CurrentSessionContext實現。注意,為了向下兼容,如果未 配置此參數,但是存在org.hibernate.transaction.TransactionManagerLookup的配 置,Hibernate會采用org.hibernate.context.JTASessionContext。一般而言,此參數的值指明了要使用的實 現類的全名,但那兩個內置的實現可以使用簡寫,即"jta"和"thread"。

    1、getCurrentSession()與openSession()的區別?

    * 采用getCurrentSession()創建的session會綁定到當前線程中,而采用openSession()
    創建的session則不會
    * 采用getCurrentSession()創建的session在commit或rollback時會自動關閉,而采用openSession()
    創建的session必須手動關閉
    2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
    * 如果使用的是本地事務(jdbc事務)
    <property name="hibernate.current_session_context_class">thread</property>
    * 如果使用的是全局事務(jta事務)
    <property name="hibernate.current_session_context_class">jta</property>

    利于ThreadLocal模式管理Session
       早在Java1.2推出之時,Java平臺中就引入了一個新的支持:java.lang.ThreadLocal,給我們在編寫多線程程序
       時提供了一種新的選擇。ThreadLocal是什么呢?其實ThreadLocal并非是一個線程的本地實現版本,它并不是一個Thread,
       而是thread local variable(線程局部變量)。也許把它命名為ThreadLocalVar更加合適。線程局部變量(ThreadLocal)
       其實的功用非常簡單,就是為每一個使用某變量的線程都提供一個該變量值的副本,是每一個線程都可以獨立地改變自己的副本,
       而不會和其它線程的副本沖突。從線程的角度看,就好像每一個線程都完全擁有一個該變量。
       ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現的思路很簡單,在ThreadLocal類中有一個Map,
       用于存儲每一個線程的變量的副本。比如下面的示例實現(為了簡單,沒有考慮集合的泛型):
    public class HibernateUtil {

    public static final ThreadLocal session =new ThreadLocal();

    public static final SessionFactory sessionFactory;
       static {
          try {
            sessionFactory = new Configuration().configure().buildSessionFactory();
          } catch (Throwable ex) {
               throw new ExceptionInInitializerError(ex);
          }   
    }

         public static Session currentSession() throws HibernateException {
            Session s = session.get();
            if(s == null) {
              s = sessionFactory.openSession();
              session.set(s);
               }
             return s;
           }

        public static void closeSession() throws HibernateException {
               Session s = session.get();
            if(s != null) {
                s.close();
            }
            session.set(null);
        }
    }

    以下為ThreadLocal的參考資料
    Title

     最近由于需要用到ThreadLocal,在網上搜索了一些相關資料,發現對ThreadLocal經常會有下面幾種誤解

     一、ThreadLocal是java線程的一個實現
          ThreadLocal的確是和java線程有關,不過它并不是java線程的一個實現,它只是用來維護本地變量。針對每個線程,提供自己的變量版本,主要是為了避免線程沖突,每個線程維護自己的版本。彼此獨立,修改不會影響到對方。

     二、ThreadLocal是相對于每個session的

            ThreadLocal顧名思義,是針對線程。在java web編程上,每個用戶從開始到會話結束,都有自己的一個session標識。但是ThreadLocal并不是在會話層上。其 實,Threadlocal是獨立于用戶session的。它是一種服務器端行為,當服務器每生成一個新的線程時,就會維護自己的 ThreadLocal。對于這個誤解,個人認為應該是開發人員在本地基于一些應用服務器測試的結果。眾所周知,一般的應用服務器都會維護一套線程池,也 就是說,對于每次訪問,并不一定就新生成一個線程。而是自己有一個線程緩存池。對于訪問,先從緩存池里面找到已有的線程,如果已經用光,才去新生成新的線 程。所以,由于開發人員自己在測試時,一般只有他自己在測,這樣服務器的負擔很小,這樣導致每次訪問可能是共用同樣一個線程,導致會有這樣的誤解:每個 session有一個ThreadLocal

     三、ThreadLocal是相對于每個線程的,用戶每次訪問會有新的ThreadLocal

      理論上來說,ThreadLocal是的確是相對于每個線程,每個線程會有自己的ThreadLocal。但是上面已經講到,一般的應用服 務器都會維護一套線程池。因此,不同用戶訪問,可能會接受到同樣的線程。因此,在做基于TheadLocal時,需要謹慎,避免出現 ThreadLocal變量的緩存,導致其他線程訪問到本線程變量 .[senngr:HibernateUtil工具類中,一般都是通過closesession的方法,里面將opensession對應的session關閉.并將ThreadLocal變量置為NULL.這樣線程池中如果再將這個線程分配給別人,對應的ThreadLocal是干凈的.]

     四、對每個用戶訪問,ThreadLocal可以多用
            可以說,ThreadLocal是一把雙刃劍,用得來的話可以起到非常好的效果。但是,ThreadLocal如果用得不好,就會跟全局變量一樣。代碼不 能重用,不能獨立測試。因為,一些本來可以重用的類,現在依賴于ThreadLocal變量。如果在其他沒有ThreadLocal場合,這些類就變得不 可用了。個人覺得ThreadLocal用得很好的幾個應用場合,值得參考

      1、存放當前session用戶:quake want的jert

      2、存放一些context變量,比如webwork的ActionContext

      3、存放session,比如Spring hibernate orm的session

    posted @ 2011-11-02 01:37 redcoatjk 閱讀(17698) | 評論 (3)編輯 收藏
    CALENDER
    <2011年11月>
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    常用鏈接

    留言簿(3)

    隨筆分類(22)

    隨筆檔案(76)

    文章分類(12)

    文章檔案(17)

    搜索

    •  

    積分與排名

    • 積分 - 250544
    • 排名 - 227

    最新評論

    評論排行榜


    Powered By: 博客園
    模板提供滬江博客

    主站蜘蛛池模板: 在线观看永久免费| 日韩国产欧美亚洲v片| 亚洲电影一区二区三区| 亚洲乱码中文字幕久久孕妇黑人| 国产jizzjizz视频免费看| 国产精品无码一区二区三区免费| 成年午夜视频免费观看视频| 国内免费高清在线观看| 免费人成在线视频| 在线播放免费播放av片| 国产无遮挡吃胸膜奶免费看视频| 麻豆国产精品入口免费观看| 日韩在线免费播放| xvideos亚洲永久网址| 亚洲午夜福利精品无码| 成人亚洲性情网站WWW在线观看| 久久精品国产精品亚洲人人 | kk4kk免费视频毛片| 国产免费一级高清淫曰本片 | 亚洲ts人妖网站| 国产成人亚洲综合一区| 亚洲Aⅴ在线无码播放毛片一线天 亚洲avav天堂av在线网毛片 | 天黑黑影院在线观看视频高清免费 | 亚洲精品国产成人片| 亚洲AV无码乱码国产麻豆| 亚洲综合无码一区二区| 亚洲一区二区三区四区视频| 中文字幕亚洲精品无码| 国产成人亚洲精品播放器下载| www.av在线免费观看| 美女被cao网站免费看在线看| h视频在线观看免费完整版| 成人毛片免费观看视频大全| 免费一级特黄特色大片在线| 中文亚洲AV片不卡在线观看| 亚洲一卡2卡三卡4卡有限公司| 亚洲精品天堂在线观看| 免费激情网站国产高清第一页| 国产免费网站看v片在线| 最近中文字幕完整版免费高清| 成人在线免费观看|