Pages

2013年8月16日 星期五

設定Windows Domain Name連結特定IP

檔案路徑: %windir%\System32\drivers\etc\hosts

功能: 要查詢一個主機名稱時,如果這個檔案沒定義的話,就會去查DNS

例如,若該檔案的內容有:
1.  1.2.3.4   ithelp.ithome.com.tw  


那麼您要連ithelp.ithome.com.tw時,
不會去向 DNS 查真正的 IP 是什麼,
而馬上往 1.2.3.4 來送。

過去一些病毒,就是把一堆的防毒軟體的官方網站,
都列到這個hosts檔案中,
統統都指向到 127.0.0.1 ,也就是電腦本身,
導致都無法更新病毒碼,也無法連到防毒軟體的網站;
只要把 hosts 這些的內容刪掉,
就會往 DNS 去查真正 IP 的位置;
這是病毒利用 hosts 的負面作法。

如果有一些常要連的目標,
DNS 常會有問題,或者很清楚其 IP
也可以手動去加上 IP 及其對應名稱;
或者若 DNS 還沒有設好,
而主機上有好幾個虛擬主機的話,
且是用 virtual name 來對應的話,
也可以利用 hosts 的功能,
這樣在這台電腦上 query 該名稱,
DNS 還沒有該記錄,但您電腦就可 query 到正確的 IP 所在,
而虛擬主機也可以由被 query hostname來做出回應;
這是 hosts 可以的正向作法。

chmod命令詳解

chmod用於改變檔或目錄的存取權限。使用者用它控制檔或目錄的存取權限。該命令有兩種用法。一種是包含字母和操作符運算式的文字設定法;另一種是包含數位的數位設定法。
1. 文字設定法
語法:chmod [who] [+ | - | =] [mode] 檔案名
命令中各選項的含義為:
操作物件who可是下述字母中的任一個或者它們的組合:
  表示使用者(user,即檔或目錄的所有者。
  表示同組(group)用戶,即與檔屬主有相同組ID的所有用戶。
  表示其他(others)用戶
  表示所有(all)用戶。它是系統預設值。
操作符號可以是:
  添加某個許可權。
  取消某個許可權。
  賦予給定許可權並取消其他所有權限(如果有的話)。
設置 mode 所表示的許可權可用下述字母的任意組合:
  可讀。
  可寫。
   可執行。
  只有目的檔案對某些用戶是可執行的或該目的檔案是目錄時才追加屬性。
  在檔執行時把進程的屬主或組ID置為該文件的文件屬主。
      方式us設置檔的用戶ID位,gs設置組ID位。
  保存程式的文本到交換設備上。
  與文件屬主擁有一樣的許可權。
  與和文件屬主同組的用戶擁有一樣的許可權。
  與其他用戶擁有一樣的許可權。
檔案名:以空格分開的要改變許可權的檔列表,支持萬用字元。
在一個命令列中可給出多個許可權方式,其間用逗號隔開。例如:
chmod g+ro+r example  % 使同組和其他用戶對文件example 有讀許可權。
2. 數字設定法
我們必須首先瞭解用數位表示的屬性的含義:0表示沒有許可權,1表示可執行許可權, 2表示可寫許可權,4表示可讀
許可權,然後將其相加。所以數位屬性的格式應為3個從07的八進位數,其順序是(u)(g)(o)。
例如,如果想讓某個檔的屬主有/二種許可權,需要把4(可讀)+2(可寫)=6(讀/寫)。
數位設定法的一般形式為:
語法:chmod [mode] 檔案名
指令實例:
chmod a+x sort   
即設定檔sort的屬性為:
 檔屬主(u 增加執行許可權
 與檔屬主同組用戶(g 增加執行許可權
 其他用戶(o 增加執行許可權
chmod ug+wo-x text
即設定檔text的屬性為:
 檔屬主(u 增加寫許可權
 與檔屬主同組用戶(g 增加寫許可權
 其他用戶(o 刪除執行許可權
chmod u+s a.out
假設執行chmoda.out的許可權為(可以用ls l a.out命令來看):
 rws--x--x 1 inin users 7192 Nov 4 14:22 a.out
 並且這個執行檔要用到一個文字檔shiyan1.c,其文件存取許可權為“–rw-------
  即該檔只有其屬主具有讀寫許可權。
   當其他用戶執行a.out這個程式時,他的身份因這個程式暫時變成inin(由於chmod
  命令中使用了s選項),所以他就能夠讀取shiyan1.c這個檔(雖然這個檔被設定為其他人不具備任何許可權),這就是s的功能。
  因此,在整個系統中特別是root本身,最好不要過多的設置這種類型的檔(除非必要)這樣可以保障系統的安全,避免因為某些程式的bug而使系統遭到入侵。
chmod ax mm.txt
chmod x mm.txt
chmod ugox mm.txt
以上這三個命令都是將檔mm.txt的執行許可權刪除,它設定的物件為所有使用者。

$ chmod 644 mm.txt
即設定文件mm.txt的屬性為:-rw-r--r--
 文件屬主(uinin 擁有讀、寫許可權
 與文件屬主同組人用戶(g 擁有讀許可權
 其他人(o 擁有讀許可權
chmod 750 wch.txt
即設定wchtxt這個檔的屬性為:-rwxr-x---
 檔主本人(uinin 可讀/可寫/可執行權
 與檔主同組人(g 可讀/可執行權
 其他人(o 沒有任何許可權



Linux nohup with out nohup.out

The command is below:

nohup some_command > /dev/null 2>&1&
for example:
nohup /jboss-eap-6.0/bin/standalone.sh -Djboss.server.base.dir=/jboss-eap-6.0/test -Djboss.server.log.dir=d:/webaplog/test > /dev/null 2>&1&

Linux下打包壓縮war、解壓war包和jar命令

把project_a文件夾下的文件打包成project.war

1. 打包
 jar -xvf project.war /project_a

-c   創建war包
-v   顯示過程信息
-f   指定 JAR 檔案名,通常這個參數是必須的
-M  不產生所有項的清單(MANIFEST〕檔,此參數會忽略 -m 參數
-0   這個是阿拉伯數字,只打包不壓縮的意思


2. 特定檔案加入JAR檔
jar uf efiling.jar BOOT-INF\classes\application-prod.yml


3. 解壓到當前目錄
  jar -cvfM0 project.war project


 

 

4. 解壓縮特定檔案

jar xf project.jar BOOT-INF\classes\application-prod.yml


  •  jar 命令詳解:


使用不帶任何的 jar 命令我們可以看到 jar 命令的用法如下:

jar {ctxu}[vfm0M] [jar-文件] [manifest-檔] [-C 目錄] 檔案名 ...

其中 {ctxu} 是 jar 命令的子命令,每次 jar 命令只能包含 ctxu 中的一個,它們分別表示:

-c 創建新的 JAR 檔包

-t 列出 JAR 文件包的內容列表

-x 展開 JAR 檔包的指定檔或者所有檔

-u 更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中)

特別注意,在參數的下達中, c/x/t/u 僅能存在一個!不可同時存在!
因為不可能同時壓縮與解壓縮。

-z :是否同時具有 gzip 的屬性?亦即是否需要用 gzip 壓縮?
-j :是否同時具有 bzip2 的屬性?亦即是否需要用 bzip2 壓縮?
-v :壓縮的過程中顯示文件!這個常用,但不建議用在背景執行過程!
-f 指定 JAR 檔案名,通常這個參數是必須的

請留意,在 f 之後要立即接檔名喔!不要再加參數!

   例如使用『 tar -zcvfP tfile sfile』就是錯誤的寫法,要寫成
   『 tar -zcvPf tfile sfile』才對喔!

-p :使用原文件的原來屬性(屬性不會依據使用者而變)
-P :可以使用絕對路徑來壓縮!
-N :比後面接的日期(yyyy/mm/dd)還要新的才會被打包進新建的檔中!
–exclude FILE:在壓縮的過程中,不要將 FILE 打包!

-m 指定需要包含的 MANIFEST 清單檔

-0 只存儲,不壓縮,這樣產生的 JAR 檔包會比不用該參數產生的體積大,但速度更快

-M 不產生所有項的清單(MANIFEST〕檔,此參數會忽略 -m 參數

[jar-檔] 即需要生成、查看、更新或者解開的 JAR 檔包,它是 -f 參數的附屬參數

[manifest-文件] 即 MANIFEST 清單文件,它是 -m 參數的附屬參數

[-C 目錄] 表示轉到指定目錄下去執行這個 jar 命令的操作。它相當於先使用 cd 命令轉該目錄下再執行不帶 -C 參數的 jar 命令,它只能在創建和更新 JAR 文件包的時候可用。  

檔案名 ... 指定一個檔/目錄列表,這些檔/目錄就是要添加到 JAR 檔包中的檔/目錄。如果指定了目錄,那麼 jar 命令打包的時候會自動把該目錄中的所有檔和子目錄打入包中。

Java Connection.setAutoCommit使用注意事項

setAutoCommit總的來說就是保持資料的完整性,一個系統的更新操作可能要涉及多張表,需多個SQL語句進行操作
迴圈裡連續的進行插入操作,如果你在開始時設置了:conn.setAutoCommit(false);
最後才進行conn.commit(),這樣你即使插入的時候報錯,修改的內容也不會提交到資料庫,
而如果你沒有手動的進行setAutoCommit(false);
出錯時就會造成,前幾條插入,後幾條沒有
會形成髒資料~~

setAutoCommit(false)的誤用
(設定setAutoCommit(false)沒有在catch中進行Connection的rollBack操作,操作的表就會被鎖住,造成資料庫鎖死):
誤用Connection.setAutoCommit導致的資料庫鎖死問題。
系統在發佈到使用者的的伺服器了,運行一段時間偶爾出現某些功能不能正常運行,甚至不能自動恢復,嚴重導致伺服器當機,表現為伺服器不回應使用者的請求,資料庫有大量的鎖。在伺服器重啟後才能恢復正常。今天通遍的查看了一下代碼,初步分析了原因,記錄了下來,跟大家交流交流。
先看下面一段有問題的代碼:
Connection con = null;  
try{  
 con = getConnection();  
 con.setAutoCommit(false);  
 /* 
 * update USER set name=’winson’ where id=’000001’; 
 */  
 con.commit();  
}
finally{  
 if(con!=null){  
  try {  
   con.close();  
  } catch (SQLException e) {  
   e.printStackTrace();  
  }  
 }  
} 

分析:問題就出現在第4行,寫代碼的人把資料庫連接con 設置成非自動提交,但沒有在執行出現異常的時候進行回滾。如果在執行第5行的時候出現異常,con既沒有提交也沒有回滾,表USER就會被鎖住(如果oracle資料庫就是行鎖),而這個鎖卻沒有機會釋放。有人會質疑,在執行con.close()的時候不會釋放鎖嗎?因為如果應用伺服器使用了資料庫連接池,連接不會被斷開。
附:在oracle上查看鎖的方法:select * from v$lock_object或者select * from v$lock.
JDBC的api文檔是這樣對setAutoCommit方法解釋的:
Sets the connection's auto-commit mode to enableAutoCommit.
Newly created Connection objects are in auto-commit mode by default, which means that individual SQL statements are committed automatically when the statement is completed. To be able to group SQL statements into transactions and commit them or roll them back as a unit, auto-commit must be disabled by calling the method setAutoCommit with false as its argument. When auto-commit is disabled, the user must call either the commit or rollback method explicitly to end a transaction.(一定不能大意哦,如果設置成非自動提交,在最後一定要調用commit或者rollback方法)
The commit occurs when the statement completes or the next execute occurs, whichever comes first. In the case of statements returning a ResultSet object, the statement completes when the last row of the result set has been retrieved or the ResultSet object has been closed. In advanced cases, a single statement may return multiple results as well as output parameter values. In this case, the commit may occur when all results and output parameter values have been retrieved, or the commit may occur after each result is retrieved.


參考正確的寫法應該是:
Connection con = null;  
try{  
    con = getConnection();  
    con.setAutoCommit(false);  
    /* 
     * do what you want here. 
     */  
    con.commit();  
}
catch(Throwable e){  
    if(con!=null){  
  try {
   con.rollback();  
  }
  catch (SQLException e1) {  
   e1.printStackTrace();  
  }  
 }  
 throw new RuntimeException(e);  
}
finally{  
    if(con!=null){  
  try {  
   con.close();  
  } catch (SQLException e) {  
   e.printStackTrace();  
  }  
    }  
}  

這種疏忽很容易出現,但又導致非常嚴重的運行問題。所以在這裡作個提醒,以後在處理外部資源的時候一定要格外小心。今天還發現代碼中一些地方濫用synchronized關鍵字,導致系統性能受到很大的影響,處理不當跟前面提到問題一起出現,那系統就是時候over了。
另外,如果不是自己來處理事務,可能在用hibernate或者ejb等,都一定要記住在處理完之後要提交或者回滾哦。
import java.sql.DriverManager;  
import java.sql.PreparedStatement;  
import java.sql.Connection;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
import java.util.List;  
  
/** 
 * 用於JDBC操作資料庫的公共類 
 */  
public class CommonSql {  
    /** 資料庫連線物件 */  
 private Connection conn;  
 /** 資料庫操作物件 */  
 private PreparedStatement ps;  
 /** 返回的資料結果集物件 */  
 private ResultSet rs;  
  
 /** 
  * 測試資料庫連接是否成功 
  * @param args 
  */  
 /** 
  * 打開資料庫連接並創建資料庫連線物件 
  * @return boolean true:連接成功,false:連接失敗 
  */  
 public boolean openConn() {  
  Boolean isPassed = false;  
  String driver = RWProperties.getProperty("driver", "com/test/config/db.properties");  
  String url = RWProperties.getProperty("url", "com/test/config/db.properties");  
  String user = RWProperties.getProperty("user", "com/test/config/db.properties");  
  String pwd = RWProperties.getProperty("pwd", "com/test/config/db.properties");  
  
  try {  
   Class.forName(driver);  
   conn = DriverManager.getConnection(url, user, pwd);  
   isPassed = true;  
  } catch (ClassNotFoundException e) {  
   closeAll();  
   e.printStackTrace();  
   System.out.println("資料庫連接失敗!");  
  } catch (Exception e) {  
   closeAll();  
   e.printStackTrace();  
   System.out.println("資料庫連接失敗!");  
  }  
  
  return isPassed;  
 }  
 /** 
  * 執行資料庫的新增和修改語句,只操作一張表 
  * @param sql 要執行的SQL語句 
  * @return boolean true:執行成功,false:執行失敗 
  */  
 /** 
     * 執行資料庫的新增和修改語句,同時操作多張表 
     * @param sql 要執行的SQL語句的字串陣列 
     * @return boolean true:執行成功,false:執行失敗 
     */  
 public boolean execUpdate(String[] sql) {  
  boolean isPassed = false;  
  // 判斷連接資料庫是否成功  
  if (openConn()) {  
   try {  
    conn.setAutoCommit(false);  
    for (int i = 0; i < sql.length; i++) {  
     ps = conn.prepareStatement(sql[i]);  
     ps.executeUpdate();  
    }  
    conn.commit();  
    isPassed = true;  
   } catch (SQLException e) {  
    try {  
     conn.rollback();  
    } catch (SQLException e1) {  
     e1.printStackTrace();  
    }  
    for (int i = 0; i < sql.length; i++) {  
     System.out.println("SQL:"+sql[i]);  
    }  
    e.printStackTrace();  
   } finally {  
    closeAll();  
   }  
  } else {  
   closeAll();  
   for (int i = 0; i < sql.length; i++) {  
    System.out.println(sql[i]);  
   }  
   System.out.println("資料庫連接失敗!");  
  }  
  
  return isPassed;  
 }  
    /** 
     * 執行資料庫的新增和修改語句,同時操作多張表 
     * @param sql 要執行的SQL語句的集合 
     * @return boolean true:執行成功,false:執行失敗 
     */  
 public boolean execUpdate(List<string> sql) {  
  boolean isPassed = false;  
  // 判斷連接資料庫是否成功  
  if (openConn()) {  
   try {  
    conn.setAutoCommit(false);  
    for (int i = 0; i < sql.size(); i++) {  
     ps = conn.prepareStatement(sql.get(i));  
     ps.executeUpdate();  
    }  
    conn.commit();  
    isPassed = true;  
   } catch (SQLException e) {  
    try {  
     conn.rollback();  
    } catch (SQLException e1) {  
     e1.printStackTrace();  
    }  
    for (int i = 0; i < sql.size(); i++) {  
     System.out.println("SQL:"+sql.get(i));  
    }  
    e.printStackTrace();  
   } finally {  
    closeAll();  
   }  
  } else {  
   closeAll();  
   for (int i = 0; i < sql.size(); i++) {  
    System.out.println(sql.get(i));  
   }  
   System.out.println("資料庫連接失敗!");  
  }  
  
  return isPassed;  
 }  
    /** 
     * 執行資料庫查詢操作 
     * @param sql 要執行的SQL語句 
     * @return ResultSet 返回查詢的結果集對象 
     */  
 public ResultSet execQuery(String sql) {  
     rs = null;  
     // 判斷連接資料庫是否成功  
  if (openConn()) {  
   try {  
    ps = conn.prepareStatement(sql);  
    rs = ps.executeQuery();  
   } catch (SQLException e) {  
    closeAll();  
    System.out.println("SQL:"+sql);  
    e.printStackTrace();  
   }  
  } else {  
   closeAll();  
   System.out.println("SQL:"+sql);  
   System.out.println("資料庫連接失敗!");  
  }  
  
  return rs;  
 }  
 /** 
  * 關閉所有資料庫連線物件 
  */  
 public void closeAll() {  
  if (conn != null) {  
   try {  
    conn.close();  
    conn = null;  
   } catch (SQLException e) {  
    e.printStackTrace();  
   }  
  }  
  if (ps != null) {  
   try {  
    ps.close();  
    ps = null;  
   } catch (SQLException e) {  
    e.printStackTrace();  
   }  
  }  
  if (rs != null) {  
   try {  
    rs.close();  
    rs = null;  
   } catch (SQLException e) {  
    e.printStackTrace();  
   }  
  }  
 }  
}  

T-SQL 取代Cursor操作

轉仔自 : RICO技術農場 自己在工作開發上(雖然很少開發...XD)遇到要執行一筆一筆的操作,
我會盡量避免使用Cursor來處理(效能會很差),而想其他方法來取代,
剛好看到網友詢問,這裡順手紀錄針對一筆一筆操作不使用Cursor做法。

需求:取得來源資料表col2欄位並依col1條件逐筆更新目的資料表c2欄位(@desttbl)

declare 
@step int,
@uplimit int,
@currentid int,
@maxcount int,
@nextrowid int,
@c1data int,
@c2data varchar(30);
set @uplimit=1000; 
set @step=1;
--建立來源資料表
declare @sourcetbl table 
(
col1 int identity(1,1) primary key not null,
col2 varchar(30) null
)  
--建立目的資料表
declare @desttbl table
(
c1 int not null, 
c2 varchar(30) null,
c3 datetime 
)

--新增資料
while(@step<@uplimit+1)
begin
set @c1data=FLOOR((@uplimit)*RAND());
insert into @sourcetbl values('rico'+convert(varchar,@step)); 
insert into @desttbl values(@c1data,'',getdate());
set @step=@step+1;
end
select @maxcount=count(1) from @sourcetbl; 
select @currentid=min(col1) from @sourcetbl; 
  
--取得來源資料表col2欄位並依col1條件更新目的資料表c2欄位(@desttbl)
while(@currentid<=@maxcount)
begin
select 
@currentid=col1,
@c2data=col2 
from @sourcetbl
where col1=@currentid;
update @desttbl set c2=@c2data where c1=@currentid;

-- 取得下一筆資料
SELECT @nextrowid = MIN(col1)
FROM @sourcetbl
WHERE col1 > @currentid ; 
set @currentid=@nextrowid; 
end
--查看結果
select * from @desttbl 

鎖的問題

SQL Server中使用加鎖的問題,我就以前的經驗和收集的一些資料簡單的提出我自己的一些看法,不知道對啟明星是否有所幫助:
一般而言,下面是個典型的打開資料庫的過程。
<%
游標類型
Const adOpenForwardOnly = 0
Const adOpenKeyset = 1
Const adOpenDynamic = 2
Const adOpenStatic = 3

加鎖類型
Const adLockReadOnly = 1
Const adLockPessimistic = 2
Const adLockOptimistic = 3
Const adLockBatchOptimistic = 4 
>%

<% set conn = server.createobject(’adodb.connection’) >%
<% set rsmov = server.createobject(’adodb.recordset’) >%
<% conn.open ’soc’, ’’, ’’ >%
<% rsmov.open sqlmov, conn, adopenkeyset, adlockreadonly >%
游標使用時是比較靈活的,它有時用來描述一個記錄集,有時又是用來描述目前記錄集中某一條記錄的指標。游標主要是用來建立一個關聯式資料庫中行/列關係的一種SQL可利用的訪問格。與游標有關係的技術術語還有一個叫Bookmark的。如果你選擇的游標方式支援Bookmarks。資料庫將提供有關記錄數目的強大功能。在上面寫出的那麼多游標方式中,adOpenDynamic是沒有太的用處的,雖然它提供即時顯示資料庫中的記錄的所有更新操作的功能,但是因為並不是所有的資料庫都支援該游標方式,沒有移植性的游標方式對當前錯綜複雜的資料庫來說真是用處不大。在實際的程式設計中,我相信大家使用得最頻繁的是adOpenStatic方式,當然這種方式的缺點是不能夠就、即時反應出資料庫中內容改變時的狀況。如果要想看到資料庫被其它使用者改變的狀況,可使用adOpenKeyse方式(但是它只能夠反應出被編輯的改變情況,也就是說不能夠反映出新增和刪除記錄的改變情況。)
其實上面的內容大家一般都可以在微軟的技術參考資料中找到,下面來說說在使用這些游標
方式和加鎖方式時要注意到的問題。
1。首先要注意到的是這兩種方式在混合使用時的問題,就是說你同時設置游標方式和加鎖方式。
除非你是在使用Access資料庫,一般而言當你混合使用時是並不能夠得到你預期想要的游標方式和加鎖方式的。例如,如果你同時將游標設置為adOpenStatic方式,而將加鎖設置為adLockOptimistic,你將得不到adOpenStatic方式的游標,你這時使用的游標方式將是
adOpenKeyset,也就是說你使用ADO的話,它將返回adOpenKeyset的游標。
2。其次,游標和加鎖的混合使用還會導致ADO返回的不是你想要的加鎖方式,ADO會改變你的加鎖
方式。例如,在預設狀態下游標方式是adOpenForwardOnly,在使用這種游標方式的同時如果
你使用的加鎖方式為-1(就是讓資料來源來判斷加鎖方式)或則adLockReadOnly,那麼這種混合方式基本上不支援RecordSet的任何方法,也就是說RecordSet的任何方法將返回False
(你的recordcount,absoultpage,addnew,delete,update等都會返回-1-1就是表示不支援該屬性),但是這時如果你使用的是adOpenForwardOnly游標方式和其它的加鎖方式混合,它反而
會支持填加,刪除和更新。 

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

          SELECT 語句中加鎖選項的功能說明 

SQL Server提供了強大而完備的鎖機制來幫助實現資料庫系統的併發性和高性能。用戶既能使用SQL Server的缺省設置也可以在select 語句中使用加鎖選項來實現預期的效果。 本文介紹了SELECT語句中的各項加鎖選項以及相應的功能說明。 
功能說明:   
NOLOCK(不加鎖)  
此選項被選中時,SQL Server 在讀取或修改資料時不加任何鎖。 在這種情況下,使用者有可能讀取到未完成事務(Uncommited Transaction)或回滾(Roll Back)中的資料即所謂的髒資料  

HOLDLOCK(保持鎖)  
此選項被選中時,SQL Server 會將此共用鎖保持至整個事務結束,而不會在途中釋放。  

UPDLOCK(修改鎖)  
此選項被選中時,SQL Server 在讀取資料時使用修改鎖來代替共用鎖,並將此鎖保持至整個事務或命令結束。使用此選項能夠保證多個進程能同時讀取資料但只有該進程能修改資料。  

TABLOCK(表鎖)  
此選項被選中時,SQL Server 將在整個表上置共用鎖直至該命令結束。 這個選項保證其他進程只能讀取而不能修改資料。  

PAGLOCK(頁鎖)  
此選項為預設選項, 當被選中時,SQL Server 使用共用頁鎖。  

TABLOCKX(排它表鎖)  
此選項被選中時,SQL Server 將在整個表上置排它鎖直至該命令或事務結束。這將防止其他進程讀取或修改表中的資料。  

使用這些選項將使系統忽略原先在SET語句設定的事務隔離級別(Transaction Isolation Level) 請查閱SQL Server 連線手冊獲取更多資訊。  
-------------------------------------------------------------------------------------------------------------

如何鎖一個表的某一行


連接中執行

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

begin tran

select * from tablename with (rowlock) where id=3

waitfor delay ’00:00:05’

commit tran

B連接中如果執行

update tablename set colname=’10’ where id=3 --則要等待5

update tablename set colname=’10’ where id<>3 --可立即執行

鎖定資料庫的一個表

SELECT * FROM table WITH (HOLDLOCK) 


注意鎖定資料庫的一個表的區別

SELECT * FROM table WITH (HOLDLOCK) 
其他事務可以讀取表,但不能更新刪除

SELECT * FROM table WITH (TABLOCKX) 
其他事務不能讀取表,更新和刪除

select * from table with (..)


SELECT 語句中加鎖選項的功能說明
  SQL Server提供了強大而完備的鎖機制來幫助實現資料庫系統的併發性和高性能。用戶既能使用SQL Server的缺省設置也可以在select 語句中使用加鎖選項來實現預期的效果。 本文介紹了SELECT語句中的各項加鎖選項以及相應的功能說明。
  功能說明:  
  NOLOCK(不加鎖) 
  此選項被選中時,SQL Server 在讀取或修改資料時不加任何鎖。 在這種情況下,使用者有可能讀取到未完成事務(Uncommited Transaction)或回滾(Roll Back)中的資料即所謂的髒資料 
   
  HOLDLOCK(保持鎖) 
  此選項被選中時,SQL Server 會將此共用鎖保持至整個事務結束,而不會在途中釋放。 
   
  UPDLOCK(修改鎖) 
  此選項被選中時,SQL Server 在讀取資料時使用修改鎖來代替共用鎖,並將此鎖保持至整個事務或命令結束。使用此選項能夠保證多個進程能同時讀取資料但只有該進程能修改資料。 
   
  TABLOCK(表鎖) 
  此選項被選中時,SQL Server 將在整個表上置共用鎖直至該命令結束。 這個選項保證其他進程只能讀取而不能修改資料。 
   
  PAGLOCK(頁鎖) 
  此選項為預設選項, 當被選中時,SQL Server 使用共用頁鎖。 
   
  TABLOCKX(排它表鎖) 
  此選項被選中時,SQL Server 將在整個表上置排它鎖直至該命令或事務結束。這將防止其他進程讀取或修改表中的資料。 
   
  使用這些選項將使系統忽略原先在SET語句設定的事務隔離級別(Transaction Isolation Level) 請查閱SQL Server 連線手冊獲取更多資訊。

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

什么是事務
事務(Transaction)是併發控制的基本單位。所謂事務,它是一個操作序列,這些操作要么都執行,要么都不執行,它是一個不可分割的工作單位。例如,銀行轉帳工作:從一個帳號扣款並使另一個帳號增款,這兩個操作要么都執行,要么都不執行。所以,應該把他們看成一個事務。事務是資料庫維護資料一致性的單位,在每個事務結束時,都能保持資料一致性。

資料一致性問題
多使用者併發存取同一資料將會導致以下的資料不一致性問題。
• 丟失修改( Lost Update
在下表中,T1T2T3T4表示順序的時間。
用戶T 1T 2T 3T 4
Ax = 40X = x-30
BX = 40X = x-20

假設用戶AB都讀取x ( x = 40 ) ,然後分別把x減少3020。用戶At3把改後的x ( x = 10 )寫入資料庫。隨後,用戶Bt4把改後的x ( x = 20 )寫入資料庫。於是,對用戶A而言,他的修改在t4
處丟失了。
• 髒讀數據( Dirty Read
請看下表,
用戶T1T2T3T4
Ax = 40X = x + 30X = x - 30rollback
BX = 70X = x-20
用戶At2x增加30(尚沒寫入資料庫),使用者Bt3由資料緩存讀出x = 70。但用戶At4時撤銷(Undo)了對x的修改,資料庫中仍維持x = 40。但使用者B已把改變的資料( x = 70)取走。
• 不能重複讀(Non-Repeatable Read
用戶T1T2T3T4T5T6
AX=40Y=30 X+Y=70Z=30 X+Y+Z=100
Bx=40X=X+20CommitX=x-20
用戶A、用戶B分別讀取x = 40後,在t 3用戶A取出y = 30並計算x + y = 70。在t4時用戶Bx增加20,並於t 5x ( x = 60 )寫入資料庫。在t6時,用戶A取出z ( z = 30 )並繼續計算x + y + z = 100。但如果用戶A為進行核算而把xyx重讀一次再進行計算,卻出現x + y + z = 120!(x已增加20)。

如何標識一個事務
SQL Server中,通常事務是指以BEGIN TRAN開始,到ROLLBACK或一個相匹配的COMMIT之間的所有語句序列。ROLLBACK表示要撤銷( U n d o)該事務已做的一切操作,回退到事務開始的狀態。COMMIT表示提交事務中的一切操作,使得對資料庫的改變生效。
SQL Server中,對事務的管理包含三個方面:
• 事務控制語句:它使程式師能指明把一系列操作( Transact - SQL命令)作為一個工作單
位來處理。
• 鎖機制( Locking):封鎖正被一個事務修改的資料,防止其它使用者訪問到不一致的資料。
• 事務日誌( Transaction Log):使事務具有可恢復性。

SQL Server的鎖機制
所謂封鎖,就是一個事務可向系統提出請求,對被操作的資料加鎖( Lock )。其它事務必須等到此事務解鎖( Unlock)之後才能訪問該資料。從而,在多個使用者併發訪問資料庫時,確保不互相干擾。可鎖定的單位是:行、頁、表、盤區和資料庫。
1. 鎖的類型
SQL Server支持三種基本的封鎖類型:共用( S)鎖,排它(X)鎖和更新(U)鎖。封鎖的基本細微性為行。
1) 共用(S)鎖:用於讀操作。
• 多個事務可封鎖一個共用單位的資料。
• 任何事務都不能修改加S鎖的資料。
• 通常是加S鎖的資料被讀取完畢,S鎖立即被釋放。
2) 獨佔(X)鎖:用於寫操作。
• 僅允許一個事務封鎖此共用資料。
• 其它任何事務必須等到X鎖被釋放才能對該資料進行訪問。
• X鎖一直到事務結束才能被釋放。
3) 更新(U)鎖。
• 用來預定要對此頁施加X鎖,它允許其它事務讀,但不允許再施加U

鎖或X鎖。
• 當被讀取資料頁將要被更新時,則升級為X鎖。
• U鎖一直到事務結束時才能被釋放。
2. 三種鎖的相容性
如下表簡單描述了三種鎖的相容性:
通常,讀操作(SELECT)獲得共用鎖,寫操作( INSERTDELETE)獲得獨佔鎖;而更新操作可分解為一個有更新意圖的讀和一個寫操作,故先獲得更新鎖,然後再升級為獨佔鎖。
執行的命令獲得鎖其它進程可以查詢?其它進程可以修改?
Select title_id from titlesSYesNo
delete titles where price>25XNoNo
insert titles values( ...)XNoNo
update titles set type=“general”UYesNo
where type=“business”然後XNONo

使用索引降低鎖併發性
我們為什么要討論鎖機制?如果使用者運算元據時盡可能鎖定最少的資料,這樣處理過程,就不會等待被鎖住的資料解鎖,從而可以潛在地提高SQL Server的性能。如果有200個使用者打算修改不同顧客的資料,僅對存儲單個顧客資訊的單一行進行加鎖要比鎖住整個表好得多。那么,用戶如何只鎖定行而不是表呢?當然是使用索引了。正如前面所提到的,對存有要修改資料的欄位使用索引可以提高性能,因為索引能直接找到資料所在的頁面,而不是搜索所有的資料頁面去找到所需的行。如果用戶直接找到表中對應的行並進行更新操作,只需鎖定該行即可,而不是鎖定多個頁面或者整個表。性能的提高不僅僅是因為在修改時讀取的頁面較少,而且鎖定較少的頁面潛在地避免了一個使用者在修改資料完成之前其它使用者一直等待解鎖的情況。

事務的隔離級別
ANSI標準為SQL事務定義了4個隔離級別(isolation level),隔離級別越高,出現資料不一致性的可能性就越小(併發度也就越低)。較高的級別中包含了較低級別中所規定了的限制。
• 隔離級別0:防止丟失修改,允許髒讀。
• 隔離級別1:防止髒讀。允許讀已提交的資料。
• 隔離級別2:防止不可重複讀
• 隔離級別3可序列化serializable)。其含義為,某組並行事務的一種交叉調度產生的結果和這些事務的某一串列調度的結果相同(可避免破壞資料一致性)。SQL Server支持四種隔離級別,級別1為缺省隔離級別,表中沒有隔離級別2 請參考表:
SQL Server支援的隔離級別封鎖方式資料一致性保證
X鎖施加於被修改的頁S鎖施加於被讀取的頁防止丟失修改防止讀髒資料可以重複讀取
級別0封鎖到事務結束是
級別1(缺省)封鎖到事務結束讀後立即釋放是是
級別3封鎖到事務結束封鎖到事務結束是是是
SQL Server也指定級別2,但級別3已包含級別2ANSI-92 SQL中要求把級別3作為所有事務的缺省隔離級別。
SQL Serverholdlock選項加強S鎖的限制,實現隔離級別3SQL Server的缺省隔離級別為級別1,共用讀鎖(S鎖)是在該頁被讀完後立即釋放。在select語句中加holdlock選項,則可使S鎖一直保持到事務結束才釋放。她符合了ANSI隔離級別3的標準─“可序列化

下面這個例子中,在同一事務中對avg ( advance )要讀取兩次,且要求他們取值不變─“可重複讀,為此要使用選項holdlock
BEGIN tran
DECLARE @avg-adv money
SELECT @avg-adv = avg(advance)
FROM titles holdlock
WHERE type = “business“
if @avg-adv > 5000
SELECT title from titles
WHERE type=“business“ and advance >@avg_adv
COMMIT tran
SQL Server中設定事務隔離級別的方法有三種:

• 工作階段層設定
語法如下:
SET TRANSACTION ISOLATION LEVEL
{
READ COMMITTED
| READ UNCOMMITTED
| REPEATABLE READ
| SERIALIZABLE
}
系統提供的系統存儲過程將在級別1下執行,它不受工作階段層設定的影響。
• 語法層設定
SELECTDECLARE cursorread text語句中增加選項。比如:
SELECT...at isolation{0|read uncommitted}
注意:語法層的設定將替代工作階段層的設定。
• 利用關鍵字設定
SELECT語句中,加選項holdlock則設定級別3
SELECT語句中,加noholdlock則設定級別0

如下程式清單中所列的腳本實例在authors表上持有一個共用鎖,它將用戶檢查伺服器當前活動的時間推遲兩分鐘。
程式清單測試事務隔離等級
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
BEGIN TRAN
SELECT *
FROM authors
WHERE au_lname = ’Green’
WAITFOR DELAY ’00:02:00’
ROLLBACK TRAN
GO
Activity Legend(活動圖示)表明:當SQL Server檢索資料時會去掉頁面表意向鎖。Current Activity視窗(見圖3 - 3 )顯示共用鎖一直被保持直到事務完成為止(也就是說,直到WAITFORROLLBACK TRAN語句完成)
使用鎖定優化程式提示
讓我們再深入考察程式清單的實例。通過改變優化程式提示,使用者可以令SQL Serverauthors表上設置一個獨佔表鎖(如程式所示)
BEGIN TRAN
SELECT *
FROM authors (tablockx)
WHERE au_lname = ’Green’
WAITFOR DELAY ’00:02:00’
ROLLBACK TRAN
GO