買到蘋果新款MacBook Air后大家最想干的事是什么?體驗一下Mac OS X?事實告訴我們有幾乎一半的人第一件想要做的事是裝一個微軟的Windows系統(tǒng),但問題是新版的MBA已經(jīng)沒有光驅(qū)了,這可如何是好?其實只需一個4GB的U盤便能搞定了。
首先你要準(zhǔn)備的是一臺攜帶光驅(qū)的Windows 7電腦,另外需要準(zhǔn)備一張Windows 7系統(tǒng)光盤,還需要一個至少4GB的U盤(閃存+讀卡器不可),再準(zhǔn)備大概1個小時,恩,差不多就行了。
一,在U盤上安裝Windows 7的詳細(xì)步驟
1.先將U盤插到Windows 7電腦上,接著用管理員身份啟動CMD命令提示符。
(單擊開始-搜索區(qū)域鍵入“CMD”-對著CMD右鍵選擇以管理員身份運行)
2.打開Diskpart,這是因為平時我們看到的系統(tǒng)都是字母盤符,我們需要讓其變?yōu)樽钤嫉臄?shù)字。
(在CMD中輸入“diskpart”,然后按回車,切換為DISKPART>之后輸入“list disk”按回車)
3.現(xiàn)在屏幕上應(yīng)該會顯示出所有電腦上正在使用的儲存設(shè)備,根據(jù)容量就能看出哪一個是我們插入的U盤,3856 MB那個當(dāng)然就是4GB的U盤,讓我們選中它吧。
(在CMD中輸入“select disk 3”,U盤所在的位置)
接下來運行的每一個步驟都不能有錯,另外你還需要確保一件事,那就是在第3步中你已經(jīng)成功選擇了U盤所在位置,不然其他硬盤數(shù)據(jù)可就清空了哦。
(在CMD中輸入“clean”清空U盤,輸入“create partition primary”創(chuàng)建主分區(qū),輸入“select partition 1”選擇分區(qū)1,輸入“active”將選中分區(qū)標(biāo)記為活動分區(qū),輸入“format fs=ntfs”格式化U盤的分區(qū)1,輸入“assign”給所選分區(qū)分配一個驅(qū)動器號,輸入“exit”退出Diskpart)(輸入“assign”時U盤有可能斷開重新連接,這很正常,請不要驚慌)
4.我們需要將Windows 7的安裝內(nèi)容裝進U盤內(nèi),請將你的Windows 7光盤插入到光驅(qū)內(nèi)(本次案例光驅(qū)所在位置為E盤,U盤所在位置為H盤,諸君請自動替換適用盤符)
(插入光盤后在CMD中輸入“e: cd boot”改為光盤啟動,輸入“bootsect.exe /nt60 h:”使其安裝至U盤)
5.接下來電腦會將Windows 7的安裝內(nèi)容全部儲存到U盤內(nèi),這需要等待10分鐘左右,在那之后U盤就可以在任何電腦上安裝Windows 7了,不過首選當(dāng)然需要在BIOS中設(shè)置為U盤啟動。好了,U盤安裝完畢,接著讓我們拿出U盤,拿出等候已久的新款MacBook Air。
二,接著使用MacBook Air支持U盤啟動
雖然新款的MacBook Air支持用U盤安裝軟件,但這并不代表其可以直接在Mac中安裝Windows 7,畢竟你可不能直接在Mac中運行Setup.exe對吧。所以我們還需要一個軟件,那就是rEFIt引導(dǎo)工具,下載地址在這。下載完之后在Mac雙擊運行rEFIt.mpkg即可安裝。
安裝完畢后,下次你重新啟動MacBook Air的時候應(yīng)該就會出現(xiàn)如下畫面了,這樣就能選擇是使用Mac OS X啟動還是其他系統(tǒng)啟動了(當(dāng)然是Windows啦)。不過首先需要按住Option鍵在設(shè)置中將路徑改為U盤所在位置。
三,在MacBook Air上安裝Windows 7
要想在MacBook Air安裝Windows 7,我們還需要一個軟件,那就是Boot Camp Assistant,該軟件已經(jīng)在Mac OS X中自帶了,請各位同學(xué)自己尋找。運行它之后,會提示你需要一個光盤驅(qū)動器,忽略這條消息,點擊繼續(xù)。
下一步,你需要下載Windows支持的軟件,包括Boot Camp中的各種驅(qū)動以及遠(yuǎn)程CD/DVD支持,都保存在一個文件夾中吧,接下來你會用到它的。
接下來Boot Camp Assistant會要求你縮小現(xiàn)在的Mac OS X上的分區(qū)大小以騰出空間安裝Windows,請謹(jǐn)慎選擇分區(qū)大小,畢竟兩個分區(qū)的文件格式將會改變。
現(xiàn)在你可以在MacBook Air上插入剛才制作好的Windows 7啟動U盤,然后重新啟動MBA,按住Option鍵,確保路徑選擇是U盤啟動。USB圖標(biāo)應(yīng)該很容易辨認(rèn)。
接下來就會進入Windows 7的安裝過程,這一步相信大家都是熟門熟路了,只有一點需要注意的是,剛才通過 Boot Camp Assistant劃分的分區(qū)是FAT32格式的,而Windows 7不能使用FAT32的分區(qū),所以選擇的時候需要重新格式化改為NTFS格式。
這是目前為止安裝Windows最快的電腦,新款MacBook Air一共花了才7分鐘就能將Windows 7安裝完畢,是不是覺得有點不可思議?進入Windows 7后還有一件事需要干,那就是將剛才下載的Boot Camp中的Windows的驅(qū)動程序安裝一遍,接著你就能使用Windows 7了!
Sun號稱開源方面的領(lǐng)路人之一,其實Google擁有的開源項目也是十分豐富的。除了開發(fā)方面的項目外,也有MySQL等方面的內(nèi)容。在這其中還包括新出的Google Go!
Google是支持開源運動的最大公司之一,它們現(xiàn)在總共發(fā)布有超過500個的開源項目(大部分都是利用它們的API來完成),本文將列舉一些有趣的開源項目,其中很可能有不少你不知道的哦。
Google開源助Web2.0開發(fā) 不排斥專有深入了解Google開源框架GWT Google開源新舉動:Linux桌面1.1版上線(.. Mozilla、Google開源合作遭美國稅局質(zhì)疑微軟擔(dān)心Google和蘋果超越Windows 8 文本文件處理:
◆Google CRUSH (Custom Reporting Utilities for SHell)
CRUSH是為命令行或shell scripts處理特定文字?jǐn)?shù)據(jù)而制作的一系列工具,這里有指南。
C++庫和源代碼:
◆Google Breakpad
一個開源的多平臺崩潰報告系統(tǒng)。
◆Google GFlags
Gflags是一個命令行標(biāo)記的處理庫,它可以替代“getopt()”,其內(nèi)置對C++的支持比如string。指南在此。
◆Google Glog
Glog庫可執(zhí)行應(yīng)用級的登陸,提供基于C++式的登陸API,可用于Linux、BSD和Windows。指南見此。
◆Google PerfTools
這個工具可讓開發(fā)創(chuàng)建更強大的應(yīng)用程序,特別是那些用C++模版開發(fā)的多線程應(yīng)用程序,包括TCMalloc, heap-checker, heap-profiler 和cpu-profiler。指南見此還有這里。
◆Google Sparse Hash
非常節(jié)省內(nèi)存的hash-map。指南見此。
◆Omaha – Google Update
Omaha,也就是Google Update,它可以保證你的軟件隨時升級到最新版本,目前很多Windows下的Google軟件都是用Omaha升級的,包括Google Chrome和Google Earth,當(dāng)然你也可以用于自己的應(yīng)用程序。指南看這里還有這里。
◆Protocol Buffers
Protocol Buffers是一種可擴展編碼序列數(shù)據(jù)的方式,Google在幾乎所有內(nèi)部RPC協(xié)議和文件格式都使用了Protocol Buffers。指南見此。它可以用于很多語言而且被一些IDE所支持,比如NetBeans。
互聯(lián)網(wǎng):
◆Google Code Pretiffy
這是一個Javascript模塊和CSS文件,它可以讓HTML頁面里的部分源碼高亮顯示,支持C/C++, Java, Python, Ruby, PHP, VisualBasic, AWK, Bash, SQL, HTML, XML, CSS, JavaScript, Makefiles和部分Perl,不支持Smalltalk和所有的CAML。例子見此。
◆SpriteMe – easy “CSS spirtes”
SpriteMe使你可以更輕松的創(chuàng)造CSS Sprites(俗稱雪碧……)就是把網(wǎng)站要用到的圖片都堆在一張圖片里,用CSS控制調(diào)用哪個區(qū)域。它有一個自己的官網(wǎng)在這里。
◆Redacisaurus
Reducisaurus是一個壓縮CSS和JS文件的網(wǎng)絡(luò)服務(wù),基于YUI壓縮算法,運行于App Engine。
◆JaikuEngine
JaikuEngine是一個運行于App Engine的微博系統(tǒng),由jaiku.com運營。要查看移動客戶端的源碼可以看這里,這里還有介紹。
◆Selector Shell
Selector Shell是一個基于瀏覽器的測試工具,它可以讓你看到CSS在不同瀏覽器里的樣式,用Javascript寫的,你可以在這里測試。
◆Google Feed Server
Google Feed Server是一個開源Atom發(fā)布協(xié)議服務(wù),基于Apache Abdera框架,允許開發(fā)者快速為當(dāng)前數(shù)據(jù)源(比如數(shù)據(jù)庫)配置feed。指南見這里和這里。
◆Melange, the Spice of Creation
這個項目的目標(biāo)是創(chuàng)建出一個適合開源貢獻流程的框架,比如Google Summer of Code TM (GSoC)項目。使用這個框架你就可以用Google App Engine來運行Google Summer of Code項目,和其它類似項目比如Google Highly Open Participation TM Contest和GHOP。指南見此。
◆NameBench
它可以查找最快的DNS服務(wù)器給你的電腦用,在Mac OS X、Windows和UNIX系統(tǒng)下都有命令行也有用戶界面可以幫你測試,這是Google工程師用20%自由時間寫出來的。
◆Rat Proxy
一個半自動化的大型被動網(wǎng)絡(luò)應(yīng)用安全審查工具,專為精確的探測而優(yōu)化,文檔在此。
◆TopDraw
Top Draw是一個圖形生成程序,使用簡單的文字腳本,基于JavaScript編程語言,Top Draw可以創(chuàng)造出非常復(fù)雜和有趣的圖形。支持Mac OS 10.5以上系統(tǒng),使用XCode開發(fā)。
◆etherpad
開源的EtherPad,這是一個基于網(wǎng)絡(luò)的實時合作文檔編輯器,這個項目主要是為了演示代碼而開發(fā),幫助那些想在自己服務(wù)器部署Etherpad的人使用,這里有如何安裝的指南。EtherPad使用JavaScript、Java和Comet服務(wù)器來建造實時協(xié)作服務(wù)。
◆Chromium
Chromium是開源版的Chrome瀏覽器,Chromium的目標(biāo)是建立一個新一代的強大網(wǎng)絡(luò)應(yīng)用程序,它與Chrome有很多不同之處。這里有指導(dǎo)如何在Linux上編譯Chromium。
◆V8 Google’s open source JavaScript engine
V8是Google的開源JavaScript引擎,用C++寫成,用于Chrome瀏覽器之上。V8使用ECMAScript的ECMA-262第三版可運行于Windows XP、vista、Mac OS 10.5和使用IA-32或ARM處理器的Linux。V8可獨立運行也可嵌入到任何C++程序里使用,這里有指南。
◆Chromium OS
Chromium OS是開源版的Chrome OS操作系統(tǒng),提供快速、簡單而安全的網(wǎng)絡(luò)體驗,源碼在此。
◆Android
Android是第一個免費、開源而且可完全自定義的移動平臺,提供完整的堆棧:一個操作系統(tǒng)、中間件和重要的一用應(yīng)用,它包含豐富的API可以讓第三方開發(fā)者開發(fā)出強大的應(yīng)用程序。
MySQL工具:
◆Google MySQL Tools
各種管理、維護和改進MySQL數(shù)據(jù)庫性能的工具,由Google編寫,包括:
◆mypgrep.py:一個類似pgrep的工具來管理MySQL連接
compact_innodb.py:可導(dǎo)出和重載所有表格的密集型innodb數(shù)據(jù)文件
◆Google mMAIM
mMAIM的目標(biāo)是對MySQL的監(jiān)控和分析更簡單,且可以和任何環(huán)境整合使用。它可顯示主/從同步狀態(tài),一些性能狀態(tài),可以返回大量“show”命令的狀態(tài)等等。
其它:
◆Stressful Application Test (stressapptest)
Stressful Application Test試圖讓來自處理器和I/O到內(nèi)存的數(shù)據(jù)盡量隨機化,以創(chuàng)造出模擬現(xiàn)實的環(huán)境來測試現(xiàn)在的硬件設(shè)備是否穩(wěn)定,Google就在使用它,現(xiàn)在是Apache 2.0許可,這里有介紹、安裝向?qū)Ш椭改稀?/p>
◆Pop and IMAP Troubleshooter
它用于診斷并解決客戶端到郵件服務(wù)器的連接問題。
◆OpenDuckBill
Openduckbill是一個Linux下簡單的命令行備份工具,可用于監(jiān)視文件/目錄在有變化后是否標(biāo)記為備份,并傳輸這些變化到本地備份目錄、遠(yuǎn)程NFS導(dǎo)出分卷或是用rsync命令導(dǎo)出到遠(yuǎn)程SSH服務(wù)器。見安裝向?qū)А?/p>
◆ZXing
ZXing(發(fā)音類似Zebra crossing)是Java的開源多格式1D/2D條碼圖像處理庫,目的是使用內(nèi)置在手機上的攝像頭拍照并對條碼進行解碼,而不必與服務(wù)器通訊,它被用于Android系統(tǒng)。這里有向?qū)Ш椭С值脑O(shè)備列表。
◆Tesseract OCR Engine
Tesseract OCR引擎是1995年UNLV Accuracy測試的前三名之一,在1995和2006年之間它的進展不大,但依然是當(dāng)前精度最高的OCR引擎。這個源碼可讀取二進制、灰階或彩色圖片并輸出文字,內(nèi)置一個TIFF閱讀器可讀取非壓縮的TIFF文件,增加libtiff后也可讀取壓縮圖片。指南和問答。
◆Neatx – Open Source NX server
Neatx是一個開源NX服務(wù),類似NoMachine公司商業(yè)的NX服務(wù)。NX協(xié)議比VNX更強大,它們的區(qū)別主要在:
NX是X11客戶端所以不會發(fā)送位圖
NX可兼容X、VNC和Windows版的Remote Desktop
NX可緩存數(shù)據(jù)
NX安裝簡單
另外一個可選的項目可以看看Google的FreeNx。
◆PSVM
它是這個文件的代碼,這是一個SVM的“支持所有核心”的版本,可多機并行運行,實例見此。
◆Google GO
Google開發(fā)的新編程語言。
◆The Google Collections Library for Java
這是一系列與Java 5以及更高版本有關(guān)的庫,Google花錢給買過來了。
◆Google styleguIDE
每個主流的開源項目都有它自己的向?qū)问剑热缫幌盗械难菔敬a。如果這些代碼都按照“Style”的形式來演示,會更友好。
http://www.oulan.com/w/2009/12/29/google-opensource-project/
HTML5 canvas has changed the way javascript used to be. We're now able to achieve complex animation however we do need a powerful browser to interpret it. The following is 8 new HTML5 + Javascript animation effect you probably have not seen before! Play with each of them, you'll be blown away by the creativity and robustness of HTML5 canvas!
I like Tunnelers and Bomomo the most! You've to try Bomomo, it's fun!
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文適用于
SDL-1.2.13
vs2008
Windows XP
歡迎轉(zhuǎn)載,但請保留作者信息
SDL的設(shè)計并沒有考慮到要和MFC相結(jié)合,但是既然它要在windows的系統(tǒng)上運行,必然需要使用Windows提供的API。為了在MFC SDI中使用SDL,首先想到的就是替換SDL創(chuàng)建的窗口,改為使用MFC提供的窗口。
想想在Windows下要創(chuàng)建窗口需要使用的API必然是CreateWindow,在SDL代碼中搜,很容易發(fā)現(xiàn)了這樣一段代碼:
int DIB_CreateWindow(_THIS)
{
char *windowid = SDL_getenv("SDL_WINDOWID");
SDL_RegisterApp(NULL, 0, 0);
SDL_windowid = (windowid != NULL);
if ( SDL_windowid ) {
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
/* wince 2.1 does not have strtol */
wchar_t *windowid_t = SDL_malloc((SDL_strlen(windowid) + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, windowid, -1, windowid_t, SDL_strlen(windowid) + 1);
SDL_Window = (HWND)wcstol(windowid_t, NULL, 0);
SDL_free(windowid_t);
#else
SDL_Window = (HWND)SDL_strtoull(windowid, NULL, 0);
#endif
if ( SDL_Window == NULL ) {
SDL_SetError("Couldn't get user specified window");
return(-1);
}
/* DJM: we want all event's for the user specified
window to be handled by SDL.
*/
userWindowProc = (WNDPROCTYPE)GetWindowLongPtr(SDL_Window, GWLP_WNDPROC);
SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)WinMessage);
} else {
SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
(WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX),
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL);
if ( SDL_Window == NULL ) {
SDL_SetError("Couldn't create window");
return(-1);
}
ShowWindow(SDL_Window, SW_HIDE);
}
/* JC 14 Mar 2006
Flush the message loop or this can cause big problems later
Especially if the user decides to use dialog boxes or assert()!
*/
WIN_FlushMessageQueue();
return(0);
}
注意到前面的if條件判斷使用了SDL_windowid,如果這個變量不為0,那么SDL是不會創(chuàng)建新窗口的!而這個值直接來自于SDL_WINDOWID這個環(huán)境變量!以此推斷,只要在調(diào)用SDL_Init之前設(shè)置好SDL_WINDOWID這個環(huán)境變量,那么SDL將可以使用我們提供的窗口。
下面修改SDL提供的testwin示例,使之在MFC SDI環(huán)境下運行。
1.1 工程創(chuàng)建
直接使用VS2008的向?qū)梢粋€叫sdi_sdl的MFC工程,選擇SDI類型。
1.2 拋棄SDLmain.lib
在SDL提供的測試用例中,都要使用SDLmain.lib,這個lib文件實現(xiàn)了Winmain和main這兩個入口函數(shù),在這兩個函數(shù)中進行了一些SDL的初始化工作。而在MFC下,我們不需要自己寫WinMain,因此直接拋棄SDLmain.lib,將相關(guān)的代碼轉(zhuǎn)移到Csdi_sdlView的OnCreate函數(shù)中。之所以選擇Csdi_sdlView::OnCreate是因為此時窗口已經(jīng)創(chuàng)建,可以取到這個窗口的Handle,從而可以在SDL初始化之前設(shè)置好Window id。
int Csdi_sdlView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
char variable[256];
sprintf(variable, "SDL_WINDOWID=0x%lx", this->GetSafeHwnd());
SDL_putenv(variable);
SDL_WinMain(AfxGetApp()->m_hInstance, NULL, AfxGetApp()->m_lpCmdLine, SW_MAXIMIZE);
return 0;
}
1.3 SDL_WinMain
這個函數(shù)來源于SDLmain中的WinMain函數(shù),只是刪除了一些不必要的代碼:
/* This is where execution begins [windowed apps] */
int Csdi_sdlView::SDL_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
HINSTANCE handle;
char **argv;
int argc;
char *cmdline;
char *bufp;
size_t nLen;
/* Start up DDHELP.EXE before opening any files, so DDHELP doesn't
keep them open. This is a hack.. hopefully it will be fixed
someday. DDHELP.EXE starts up the first time DDRAW.DLL is loaded.
*/
handle = LoadLibrary(TEXT("DDRAW.DLL"));
if ( handle != NULL ) {
FreeLibrary(handle);
}
/* Grab the command line */
bufp = GetCommandLine();
nLen = SDL_strlen(bufp)+1;
cmdline = SDL_stack_alloc(char, nLen);
SDL_strlcpy(cmdline, bufp, nLen);
/* Parse it into argv and argc */
argc = ParseCommandLine(cmdline, NULL);
argv = SDL_stack_alloc(char*, argc+1);
ParseCommandLine(cmdline, argv);
/* Run the main program (after a little SDL initialization) */
SDL_PreMain(argc, argv);
/* Hush little compiler, don't you cry... */
return 0;
}
1.4 SDL_PreMain
這個函數(shù)來源于sdlmain.lib中的main函數(shù):
/* This is where execution begins [console apps] */
int Csdi_sdlView::SDL_PreMain(int argc, char *argv[])
{
size_t n;
char *bufp, *appname;
int status;
/* Get the class name from argv[0] */
appname = argv[0];
if ( (bufp=SDL_strrchr(argv[0], '\\')) != NULL ) {
appname = bufp+1;
} else
if ( (bufp=SDL_strrchr(argv[0], '/')) != NULL ) {
appname = bufp+1;
}
if ( (bufp=SDL_strrchr(appname, '.')) == NULL )
n = SDL_strlen(appname);
else
n = (bufp-appname);
bufp = SDL_stack_alloc(char, n+1);
SDL_strlcpy(bufp, appname, n+1);
appname = bufp;
///* Load SDL dynamic link library */
//if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) {
// ShowError("WinMain() error", SDL_GetError());
// return(FALSE);
//}
/* Sam:
We still need to pass in the application handle so that
DirectInput will initialize properly when SDL_RegisterApp()
is called later in the video initialization.
*/
SDL_SetModuleHandle(GetModuleHandle(NULL));
/* Run the application main() code */
status = SDL_main(argc, argv);
/* Hush little compiler, don't you cry... */
return 0;
}
1.5 SDL_main
這個函數(shù)來自于testwin示例中的main函數(shù),只是在末尾刪除了SDL_Quit這樣的退出語句。
int Csdi_sdlView::SDL_main(int argc, char *argv[])
{
SDL_Surface *screen;
/* Options */
int speedy, flip, nofade;
int delay;
int w, h;
int desired_bpp;
Uint32 video_flags;
/* Set default options and check command-line */
speedy = 0;
flip = 0;
nofade = 0;
delay = 1;
RECT rc;
this->GetWindowRect(&rc);
w = rc.right;
h = rc.bottom;
desired_bpp = 0;
video_flags = 0;
if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0 ) {
ShowError("Couldn't initialize SDL", SDL_GetError());
return(1);
}
/* Initialize the display */
screen = SDL_SetVideoMode(w, h, desired_bpp, video_flags);
if ( screen == NULL ) {
ShowError("Couldn't set %dx%dx%d video mode: %s\n", "");
return (1);
}
DrawPict(screen, argv[1], speedy, flip, nofade);
// SDL_Delay(delay*1000);
// SDL_Quit();
return(0);
}
至此,這個程序就可以正常運行了,但是它的大小還不能隨主窗口的變化而變化。為此還需要響應(yīng)WM_SIZE:
void Csdi_sdlView::OnSize(UINT nType, int cx, int cy)
{
SDL_Surface *screen;
screen = SDL_SetVideoMode(cx, cy, 0, 0);
DrawPict(screen, NULL, 0, 0, 0);
}
1.6 SDL_Quit
在程序退出的時候,需要調(diào)用SDL_Quit進行一些清理的工作,原來想將這個工作放在Cview::OnDestroy中完成,但是發(fā)現(xiàn)這樣有很多的內(nèi)存泄漏。最后將其放在Csdi_sdlApp:ExitInstance中完成:
BOOL Csdi_sdlApp::ExitInstance()
{
SDL_Quit();
return TRUE;
}
即便是這樣,仍然有一處內(nèi)存泄漏,原因不明:
Detected memory leaks!
Dumping objects ->
{98} normal block at 0x003D37C0, 21 bytes long.
Data: <0x40784 OWID 0x4> 30 78 34 30 37 38 34 00 4F 57 49 44 00 30 78 34
Object dump complete.
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/lights_joy/archive/2009/04/04/4049123.aspx
出處:http://www.zixundao.com/thread-1672-1-4.html
SDL是一種既是開源的,也是跨平臺的多媒體開發(fā)包,在各種平臺上應(yīng)用很廣,經(jīng)常和FFMPEG等解碼器同時使用。對于在windows mobile等缺乏通用播放器的平臺來說,是一種很好的選擇。
網(wǎng)上很多代碼,介紹SDL的用法,主要需要注意的情況有3種:
第一: 綁定播放窗口問題:
char sdl_var[128];
sprintf(sdl_var, "SDL_WINDOWID=0x%lx", m_hWnd );//主窗口句柄
SDL_putenv(sdl_var); char *myvalue = SDL_getenv("SDL_WINDOWID");
這端代碼,需要放在播放窗口初始化之前,否則,容易造成全屏。
第二:SDL本身響應(yīng)窗口菜單的問題
SDL官方提供以下代碼響應(yīng)窗口菜單:
while(1) {
SDL_WaitEvent(&event);
{
case
}
}
但也可以我們在程序里面重新初始化并顯示新菜單,就可以不用這種辦法,直接用我們自己的程序響應(yīng)菜單。
第三:關(guān)于縮放:
網(wǎng)上很多代碼容易誤導(dǎo)人。
把SDL_SetVideoMode和SDL_CreateYUVOverlay的參數(shù)都設(shè)置成一樣的,這種辦法導(dǎo)致屏幕圖象縮放顯示不正常,正確的方法應(yīng)該是:SDL_SetVideoMode的參數(shù)顯示新的顯示大小,而SDL_CreateYUVOverlay(只需建立一次,SDL_SetVideoMode更換時,不需要跟著更換)的參數(shù)則是圖片的原始大小 。
而在SDL_DisplayYUVOverlay中用到的SDL_Rect,大小則和SDL_SetVideoMode一樣,也就是新的顯示大小。
本文原創(chuàng),轉(zhuǎn)載請注明出處和作者,謝謝。
作者:藍梅居士
出處:http://www.zixundao.com/thread-1672-1-4.html
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/baishuren/archive/2009/10/13/4665153.aspx
sdl是開源的跨平臺多媒體開發(fā)包, 主要用在快速的視頻格式轉(zhuǎn)換和顯示,以及封裝了鍵盤/鼠標(biāo)/手機按鍵/觸屏等各個平臺的用戶交互響應(yīng),廣泛應(yīng)用在游戲,多媒體播放器等應(yīng)用中。目前支持windows,linux, wince,mac os,非正式地支持symbian os。
一般視頻解碼器輸出圖像的是yuv420格式,而屏幕顯示大都是rgb42規(guī)格。 mobile上畫面顯示一般經(jīng)由decode>>yuv2rgb>>scale>>directDraw直接寫屏。 采用SDL可以加速這一過程,且更方便響應(yīng)全屏縮放等用戶操作。
下面介紹mobile上用sdl來加速顯示視頻的全過程。
1. 把主對話框的窗口句柄傳給顯示類。
2. 初始化sdl,設(shè)置顯示視頻模式
SDL_Surface *screen;
SDL_Rect sdl_rect;
SDL_Overlay *bmp;
bool InitSdl()
{
char sdl_var[64];
sprintf(sdl_var, "SDL_WINDOWID=0x%lx", m_hWnd);//主窗口句柄
SDL_putenv(sdl_var);
char *myvalue = SDL_getenv("SDL_WINDOWID");
atexit(SDL_Quit);
//根據(jù)解碼后的視頻尺寸來初始化sdl
screen = SDL_SetVideoMode(ImageWidth, ImageHeight, 0,SDL_ANYFORMAT|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_HWSURFACE);//注意用到的參數(shù)flags
if(!screen)
{
TRACE(L"error SDL SetVideoMode!");
return false;
}
bmp = SDL_CreateYUVOverlay(ImageWidth, ImageHeight, ,SDL_YV12_OVERLAY,screen);
if(!bmp)
{
TRACE(L"error SDL CreateYUVOverlay!");
return false;
}
return TRUE;
}
3. 在屏幕上繪制像素
void SdlDisplayFrame()
{
AVPicture pict;
pict.data[0] = bmp->pixels[0];
pict.data[1] = bmp->pixels[2];
pict.data[2] = bmp->pixels[1];
pict.linesize[0] = bmp->pitches[0];
pict.linesize[1] = bmp->pitches[2];
pict.linesize[2] = bmp->pitches[1];
//pFrame是ffmpeg存放解碼后yuv數(shù)據(jù)的struct
img_convert(&pict, PIX_FMT_YUV420P, (AVPicture *)pFrame, pContext->pix_fmt, iImage_Width, iImage_Height);
SDL_LockSurface(screen);
SDL_LockYUVOverlay(bmp);
{
sdl_rect.x = 0;
sdl_rect.y = 0;
sdl_rect.w = m_width; //pContext->width;
sdl_rect.h = m_height; //pContext->height;
}
SDL_UnlockYUVOverlay(bmp);
SDL_UnlockSurface(screen);
SDL_DisplayYUVOverlay(bmp, &sdl_rect);//顯示圖片到屏幕
}
4. 事件輪詢和按鍵響應(yīng)
void SdlEvent()
{
SDL_Event event;
while ( SDL_PollEvent(&event))
{
TRACE(L"========SDL VIDEORESIZE EVENT START");
switch (event.type)
{
case SDL_VIDEORESIZE:
// 響應(yīng)圖像縮放事件
if (m_iImage_Width == Image_Primary_Width && m_iImage_Height == Image_Primary_Height)
{
TRACE(L"event.resize.w = %d",event.resize.w);
TRACE(L"event.resize.h = %d",event.resize.h);
m_width = event.resize.w;
m_height = event.resize.h;
SDL_FreeYUVOverlay(bmp);
bmp = NULL;
SDL_FreeSurface(screen);
screen = NULL;
if (!IsQcif)
{
m_height = m_height * 2;
m_width = m_width * 2;
screen = SDL_SetVideoMode(MobileFullScreenWidth,MobileFullScreenHeight,
0,SDL_ANYFORMAT|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_HWSURFACE);
if (screen == NULL)
{
TRACE(L"screen= NULL");
return;
}
bmp = SDL_CreateYUVOverlay(MobileFullScreenWidth,MobileFullScreenHeight,
SDL_YV12_OVERLAY,screen);
if (bmp == NULL)
{
TRACE(L"bm1 = NULL");
return;
}
IsQcif = true;
}
else
{
screen = SDL_SetVideoMode(Image_Primary_Width,Image_Primary_Height,
0,SDL_ANYFORMAT|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_HWSURFACE);
if (screen == NULL)
{
TRACE(L"screen1= NULL");
return;
}
bmp = SDL_CreateYUVOverlay(Image_Primary_Width,Image_Primary_Height,
SDL_YV12_OVERLAY,screen);
if (bmp == NULL)
{
TRACE(L"bm1 = NULL");
return;
}
IsQcif = false;
}
break;
}
case SDL_MOUSEBUTTONDOWN:
//響應(yīng)觸屏筆點擊事件
break;
}
case SDL_QUIT:
//響應(yīng)退出事件
break;
default:
break;
}
}
}
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/lius1984/archive/2009/08/07/4420786.aspx
讓游戲開發(fā)者不必為每一品牌的硬件來寫不同的驅(qū)動程序,也降低用戶安裝及設(shè)置硬件的復(fù)雜度。這樣說是不是有點不太明白,其實從字面意義上說,Direct就是直接
的意思,而后邊的X則代表了很多的意思,從這一點上我們就可以看出 DirectX的出現(xiàn)就是為了為眾多軟件提供直接服務(wù)的。
DirectX是由很多API組成的,按照性質(zhì)分類,可以分為四大部分,顯示部分、聲音部分、輸入部分和網(wǎng)絡(luò)部分。
顯示部分擔(dān)任圖形處理的關(guān)鍵,分為Direct Draw(DDraw)和Direct 3D(D3D),前者主要負(fù)責(zé)2D圖像加速。它包括很多方面:我們播放mpg、DVD電影、看圖、玩小游戲等等都是用的DDraw,你可以把它理解成所有劃線的部分都是用的DDraw。后者則主要負(fù)責(zé)3D效果的顯示,比如CS中的場景和人物、FIFA中的人物等等,都是使用了DirectX的Direct 3D。
聲音部分中最主要的API是DirectSound,除了播放聲音和處理混音之外,還加強了3d音效,并提供了錄音功能。我們前面所舉的聲卡兼容的例子,就是利用了DirectSound來解決的。
輸入部分Direct Input可以支持很多的游戲輸入設(shè)備,它能夠讓這些設(shè)備充分發(fā)揮最佳狀態(tài)和全部功能。除了鍵盤和鼠標(biāo)之外還可以連接手柄、搖桿、模擬器等。
網(wǎng)絡(luò)部分DirectPlay主要就是為了具有網(wǎng)絡(luò)功能游戲而開發(fā)的,提供了多種連接方式,TPC/IP,IPX,Modem,串口等等,讓玩家可以用各種連網(wǎng)方式來進行對戰(zhàn),此外也提供網(wǎng)絡(luò)對話功能及保密措施。
DirectX并不是一個單純的圖形API,它是由微軟公司開發(fā)的用途廣泛的API,它包含有Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多個組件,它提供了一整套的多媒體接口方案。只是其在3D圖形方面的優(yōu)秀表現(xiàn),讓它的其它方面顯得暗淡無光。DirectX開發(fā)之初是為了彌補Windows 3.1系統(tǒng)對圖形、聲音處理能力的不足,而今已發(fā)展成為對整個多媒體系統(tǒng)的各個方面都有決定性影響的接口。 DirectX 是一組低級“應(yīng)用程序編程接口 (API)”,可為 Windows 程序提供高性能的硬件加速多媒體支持。Windows 支持 DirectX 8.0,它能增強計算機的多媒體功能。使用 DirectX 可訪問顯卡與聲卡的功能,從而使程序可提供逼真的三維 (3D) 圖形與令人如醉如癡的音樂與聲音效果。 DirectX 使程序能夠輕松確定計算機的硬件性能,然后設(shè)置與之匹配的程序參數(shù)。該程序使得多媒體軟件程序能夠在基于 Windows 的具有 DirectX 兼容硬件與驅(qū)動程序的計算機上運行,同時可確保多媒體程序能夠充分利用高性能硬件。 DirectX 包含一組 API,通過它能訪問高性能硬件的高級功能,如三維圖形加速芯片和聲卡。這些 API 控制低級功能(其中包括二維 (2D) 圖形加速)、支持輸入設(shè)備(如游戲桿、鍵盤和鼠標(biāo))并控制著混音及聲音輸出。構(gòu)成 DirectX 的下列組件支持低級功能: Microsoft DirectDraw Microsoft DirectDraw API 支持快速訪問計算機視頻適配器的加速硬件功能。它支持在所有視頻適配器上顯示圖形的標(biāo)準(zhǔn)方法,并且使用加速驅(qū)動程序時可以更快更直接地訪問。DirectDraw 為程序(如游戲和二維圖形程序包)以及 Windows 系統(tǒng)組件(如數(shù)字視頻編解碼器)提供了一種獨立于設(shè)備之外的方法來訪問特定顯示設(shè)備的功能,而不要求用戶提供設(shè)備功能的其它信息。
Microsoft Direct3D Microsoft Direct3D API (Direct3D) :為大多數(shù)新視頻適配器內(nèi)置的 3-D 調(diào)色功能提供界面。Direct3D 是一種低級的 3-D API,它為軟件程序提供一種獨立于設(shè)備之外的方法以便與加速器硬件進行有效而強大的通信。Direct3D 包含專用 CPU 指令集支持,從而可為新型計算機提供進一步加速支持。
Microsoft DirectSound Microsoft DirectSound API :為程序和音頻適配器的混音、聲音播放和聲音捕獲功能之間提供了鏈接。DirectSound 為多媒體軟件程序提供低延遲混合、硬件加速以及直接訪問聲音設(shè)備等功能。維護與現(xiàn)有設(shè)備驅(qū)動程序的兼容性時提供該功能。
Microsoft DirectMusic Microsoft DirectMusic API :是 DirectX 的交互式音頻組件。與捕獲和播放數(shù)字聲音樣本的 DirectSound API 不同,DirectMusic 處理數(shù)字音頻以及基于消息的音樂數(shù)據(jù),這些數(shù)據(jù)是通過聲卡或其內(nèi)置的軟件合成器轉(zhuǎn)換成數(shù)字音頻的。DirectMusic API 支持以“樂器數(shù)字界面 (MIDI)”格式進行輸入,也支持壓縮與未壓縮的數(shù)字音頻格式。DirectMusic 為軟件開發(fā)人員提供了創(chuàng)建令人陶醉的動態(tài)音軌的能力,以響應(yīng)軟件環(huán)境中的各種更改,而不只是用戶直接輸入更改。
Microsoft DirectInput Microsoft DirectInput API :為游戲提供高級輸入功能并能處理游戲桿以及包括鼠標(biāo)、鍵盤和強力反饋游戲控制器在內(nèi)的其它相關(guān)設(shè)備的輸入。
Microsoft DirectPlay Microsoft DirectPlay API: 支持通過調(diào)制解調(diào)器、Internet 或局域網(wǎng)連接游戲。DirectPlay 簡化了對通信服務(wù)的訪問,并提供了一種能夠使游戲彼此通信的方法而不受協(xié)議或聯(lián)機服務(wù)的限制。DirectPlay 提供了多種游說服務(wù),可簡化多媒體播放器游戲的初始化,同時還支持可靠的通信協(xié)議以確保重要游戲數(shù)據(jù)在網(wǎng)絡(luò)上不會丟失。DirectPlay 8.0 的新功能即支持通過網(wǎng)絡(luò)進行語音通信,從而可大大提高基于多媒體播放器小組的游戲的娛樂性,同時該組件還通過提供與玩游戲的其他人對話的功能而使團體游戲更具魅力。
Microsoft DirectShow Microsoft DirectShow API: 提供了可在您的計算機與 Internet 服務(wù)器上進行高品質(zhì)捕獲與回放多媒體文件的功能。DirectShow 支持各種音頻與視頻格式,包括“高級流式格式 (ASF)”、“音頻-視頻交錯 (AVI)”、“數(shù)字視頻 (DV)”、“動畫專家組 (MPEG)”、“MPEG 音頻層 3 (MP3)”、 “Windows 媒體音頻/視頻 (WMA/WMV)”以及 WAV 文件。DirectShow 還具有視頻捕獲、DVD 回放、視頻編輯與混合、硬件加速視頻解碼以及調(diào)諧廣播模擬與數(shù)字電視信號等功能。
歐幾里德算法是計算兩個數(shù)最大公約數(shù)的傳統(tǒng)算法,他無論從理論還是從效率上都是很好的。但是他有一個致命的缺陷,這個缺陷只有在大素數(shù)時才會顯現(xiàn)出來。
考慮現(xiàn)在的硬件平臺,一般整數(shù)最多也就是64位,對于這樣的整數(shù),計算兩個數(shù)之間的模是很簡單的。對于字長為32位的平臺,計算兩個不超過32位的整數(shù)的模,只需要一個指令周期,而計算64位以下的整數(shù)模,也不過幾個周期而已。但是對于更大的素數(shù),這樣的計算過程就不得不由用戶來設(shè)計,為了計算兩個超過64位的整數(shù)的模,用戶也許不得不采用類似于多位數(shù)除法手算過程中的試商法,這個過程不但復(fù)雜,而且消耗了很多CPU時間。對于現(xiàn)代密碼算法,要求計算128位以上的素數(shù)的情況比比皆是,設(shè)計這樣的程序迫切希望能夠拋棄除法和取模。
Stein算法由J. Stein 1961年提出,這個方法也是計算兩個數(shù)的最大公約數(shù)。和歐幾里德算法 算法不同的是,Stein算法只有整數(shù)的移位和加減法,這對于程序設(shè)計者是一個福音。
為了說明Stein算法的正確性,首先必須注意到以下結(jié)論:
有了上述規(guī)律就可以給出Stein算法如下:
這個算法的原理很顯然,所以就不再證明了?,F(xiàn)在考察一下該算法和歐幾里德方法效率上的差別。
考慮歐幾里德算法,最惡劣的情況是,每次迭代a = 2b -1,這樣,迭代后,r= b-1。如果a小于2N,這樣大約需要 4N次迭代。而考慮Stein算法,每次迭代后,顯然AN+1BN+1≤ ANBN/2,最大迭代次數(shù)也不超過4N次。也就是說,迭代次數(shù)幾乎是相等的。但是,需要注意的是,對于大素數(shù),試商法將使每次迭代都更復(fù)雜,因此對于大素數(shù)Stein將更有優(yōu)勢。
外聯(lián)接可以是左向外聯(lián)接、右向外聯(lián)接或完整外部聯(lián)接。在 FROM 子句中指定外聯(lián)接時,可以由下列幾組關(guān)鍵字中的一組指定:LEFT JOIN 或 LEFT OUTER JOIN。
左向外聯(lián)接的結(jié)果集包括 LEFT OUTER 子句中指定的左表的所有行,而不僅僅是聯(lián)接列所匹配的行。如果左表的某行在右表中沒有匹配行,則在相關(guān)聯(lián)的結(jié)果集行中右表的所有選擇列表列均為空值。
RIGHT JOIN 或 RIGHT OUTER JOIN。
右向外聯(lián)接是左向外聯(lián)接的反向聯(lián)接。將返回右表的所有行。如果右表的某行在左表中沒有匹配行,則將為左表返回空值。
FULL JOIN 或 FULL OUTER JOIN。
完整外部聯(lián)接返回左表和右表中的所有行。當(dāng)某行在另一個表中沒有匹配行時,則另一個表的選擇列表列包含空值。如果表之間有匹配行,則整個結(jié)果集行包含基表的數(shù)據(jù)值。
僅當(dāng)至少有一個同屬于兩表的行符合聯(lián)接條件時,內(nèi)聯(lián)接才返回行。內(nèi)聯(lián)接消除與另一個表中的任何行不匹配的行。而外聯(lián)接會返回 FROM 子句中提到的至少一個表或視圖的所有行,只要這些行符合任何 WHERE 或 HAVING 搜索條件。將檢索通過左向外聯(lián)接引用的左表的所有行,以及通過右向外聯(lián)接引用的右表的所有行。完整外部聯(lián)接中兩個表的所有行都將返回。
Microsoft® SQL Server™ 2000 對在 FROM 子句中指定的外聯(lián)接使用以下 SQL-92 關(guān)鍵字:
LEFT OUTER JOIN 或 LEFT JOIN
RIGHT OUTER JOIN 或 RIGHT JOIN
FULL OUTER JOIN 或 FULL JOIN
SQL Server 支持 SQL-92 外聯(lián)接語法,以及在 WHERE 子句中使用 *= 和 =* 運算符指定外聯(lián)接的舊式語法。由于 SQL-92 語法不容易產(chǎn)生歧義,而舊式 Transact-SQL 外聯(lián)接有時會產(chǎn)生歧義,因此建議使用 SQL-92 語法。
使用左向外聯(lián)接
假設(shè)在 city 列上聯(lián)接 authors 表和 publishers 表。結(jié)果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。
若要在結(jié)果中包括所有的作者,而不管出版商是否住在同一個城市,請使用 SQL-92 左向外聯(lián)接。下面是 Transact-SQL 左向外聯(lián)接的查詢和結(jié)果:
USE pubs
SELECT a.au_fname, a.au_lname, p.pub_name
FROM authors a LEFT OUTER JOIN publishers p
ON a.city = p.city
ORDER BY p.pub_name ASC, a.au_lname ASC, a.au_fname ASC
下面是結(jié)果集:
au_fname au_lname pub_name |
不管是否與 publishers 表中的 city 列匹配,LEFT OUTER JOIN 均會在結(jié)果中包含 authors 表的所有行。注意:結(jié)果中所列的大多數(shù)作者都沒有相匹配的數(shù)據(jù),因此,這些行的 pub_name 列包含空值。
使用右向外聯(lián)接
假設(shè)在 city 列上聯(lián)接 authors 表和 publishers 表。結(jié)果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。SQL-92 右向外聯(lián)接運算符 RIGHT OUTER JOIN 指明:不管第一個表中是否有匹配的數(shù)據(jù),結(jié)果將包含第二個表中的所有行。
若要在結(jié)果中包括所有的出版商,而不管城市中是否還有出版商居住,請使用 SQL-92 右向外聯(lián)接。下面是 Transact-SQL 右向外聯(lián)接的查詢和結(jié)果:
USE pubs |
下面是結(jié)果集:
au_fname au_lname pub_name |
使用謂詞(如將聯(lián)接與常量比較)可以進一步限制外聯(lián)接。下例包含相同的右向外聯(lián)接,但消除銷售量低于 50 本的書籍的書名:
USE pubs
SELECT s.stor_id, s.qty, t.title
FROM sales s RIGHT OUTER JOIN titles t
ON s.title_id = t.title_id
AND s.qty > 50
ORDER BY s.stor_id ASC
下面是結(jié)果集:
stor_id qty title |
有關(guān)謂詞的更多信息,請參見 WHERE。
使用完整外部聯(lián)接
若要通過在聯(lián)接結(jié)果中包括不匹配的行保留不匹配信息,請使用完整外部聯(lián)接。Microsoft® SQL Server™ 2000 提供完整外部聯(lián)接運算符 FULL OUTER JOIN,不管另一個表是否有匹配的值,此運算符都包括兩個表中的所有行。
假設(shè)在 city 列上聯(lián)接 authors 表和 publishers 表。結(jié)果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。SQL-92 FULL OUTER JOIN 運算符指明:不管表中是否有匹配的數(shù)據(jù),結(jié)果將包括兩個表中的所有行。
若要在結(jié)果中包括所有作者和出版商,而不管城市中是否有出版商或者出版商是否住在同一個城市,請使用完整外部聯(lián)接。下面是 Transact-SQL 完整外部聯(lián)接的查詢和結(jié)果:
USE pubs |
下面是結(jié)果集:
|
設(shè)想網(wǎng)上購物的一次交易,其付款過程至少包括以下幾步數(shù)據(jù)庫操作:
· 更新客戶所購商品的庫存信息
· 保存客戶付款信息--可能包括與銀行系統(tǒng)的交互
· 生成訂單并且保存到數(shù)據(jù)庫中
· 更新用戶相關(guān)信息,例如購物數(shù)量等等
正常的情況下,這些操作將順利進行,最終交易成功,與交易相關(guān)的所有數(shù)據(jù)庫信息也成功地更新。但是,如果在這一系列過程中任何一個環(huán)節(jié)出了差錯,例如在更新商品庫存信息時發(fā)生異常、該顧客銀行帳戶存款不足等,都將導(dǎo)致交易失敗。一旦交易失敗,數(shù)據(jù)庫中所有信息都必須保持交易前的狀態(tài)不變,比如最后一步更新用戶信息時失敗而導(dǎo)致交易失敗,那么必須保證這筆失敗的交易不影響數(shù)據(jù)庫的狀態(tài)--庫存信息沒有被更新、用戶也沒有付款,訂單也沒有生成。否則,數(shù)據(jù)庫的信息將會一片混亂而不可預(yù)測。
數(shù)據(jù)庫事務(wù)正是用來保證這種情況下交易的平穩(wěn)性和可預(yù)測性的技術(shù)。
數(shù)據(jù)庫事務(wù)的ACID屬性
事務(wù)處理可以確保除非事務(wù)性單元內(nèi)的所有操作都成功完成,否則不會永久更新面向數(shù)據(jù)的資源。通過將一組相關(guān)操作組合為一個要么全部成功要么全部失敗的單元,可以簡化錯誤恢復(fù)并使應(yīng)用程序更加可靠。一個邏輯工作單元要成為事務(wù),必須滿足所謂的ACID(原子性、一致性、隔離性和持久性)屬性:
· 原子性
事務(wù)必須是原子工作單元;對于其數(shù)據(jù)修改,要么全都執(zhí)行,要么全都不執(zhí)行。通常,與某個事務(wù)關(guān)聯(lián)的操作具有共同的目標(biāo),并且是相互依賴的。如果系統(tǒng)只執(zhí)行這些操作的一個子集,則可能會破壞事務(wù)的總體目標(biāo)。原子性消除了系統(tǒng)處理操作子集的可能性。
· 一致性
事務(wù)在完成時,必須使所有的數(shù)據(jù)都保持一致狀態(tài)。在相關(guān)數(shù)據(jù)庫中,所有規(guī)則都必須應(yīng)用于事務(wù)的修改,以保持所有數(shù)據(jù)的完整性。事務(wù)結(jié)束時,所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如 B 樹索引或雙向鏈表)都必須是正確的。某些維護一致性的責(zé)任由應(yīng)用程序開發(fā)人員承擔(dān),他們必須確保應(yīng)用程序已強制所有已知的完整性約束。例如,當(dāng)開發(fā)用于轉(zhuǎn)帳的應(yīng)用程序時,應(yīng)避免在轉(zhuǎn)帳過程中任意移動小數(shù)點。
· 隔離性
由并發(fā)事務(wù)所作的修改必須與任何其它并發(fā)事務(wù)所作的修改隔離。事務(wù)查看數(shù)據(jù)時數(shù)據(jù)所處的狀態(tài),要么是另一并發(fā)事務(wù)修改它之前的狀態(tài),要么是另一事務(wù)修改它之后的狀態(tài),事務(wù)不會查看中間狀態(tài)的數(shù)據(jù)。這稱為可串行性,因為它能夠重新裝載起始數(shù)據(jù),并且重播一系列事務(wù),以使數(shù)據(jù)結(jié)束時的狀態(tài)與原始事務(wù)執(zhí)行的狀態(tài)相同。當(dāng)事務(wù)可序列化時將獲得最高的隔離級別。在此級別上,從一組可并行執(zhí)行的事務(wù)獲得的結(jié)果與通過連續(xù)運行每個事務(wù)所獲得的結(jié)果相同。由于高度隔離會限制可并行執(zhí)行的事務(wù)數(shù),所以一些應(yīng)用程序降低隔離級別以換取更大的吞吐量。
· 持久性
事務(wù)完成之后,它對于系統(tǒng)的影響是永久性的。該修改即使出現(xiàn)致命的系統(tǒng)故障也將一直保持。
DBMS的責(zé)任和我們的任務(wù)
企業(yè)級的數(shù)據(jù)庫管理系統(tǒng)(DBMS)都有責(zé)任提供一種保證事務(wù)的物理完整性的機制。就常用的SQL Server2000系統(tǒng)而言,它具備鎖定設(shè)備隔離事務(wù)、記錄設(shè)備保證事務(wù)持久性等機制。因此,我們不必關(guān)心數(shù)據(jù)庫事務(wù)的物理完整性,而應(yīng)該關(guān)注在什么情況下使用數(shù)據(jù)庫事務(wù)、事務(wù)對性能的影響,如何使用事務(wù)等等。
本文將涉及到在.net框架下使用C#語言操縱數(shù)據(jù)庫事務(wù)的各個方面。
+++@@@+++
體驗SQL語言的事務(wù)機制
作為大型的企業(yè)級數(shù)據(jù)庫,SQL Server2000對事務(wù)提供了很好的支持。我們可以使用SQL語句來定義、提交以及回滾一個事務(wù)。
如下所示的SQL代碼定義了一個事務(wù),并且命名為"MyTransaction"(限于篇幅,本文并不討論如何編寫SQL語言程序,請讀者自行參考相關(guān)書籍):
DECLARE @TranName VARCHAR(20)
Select @TranName = ''''MyTransaction''''
BEGIN TRANSACTION @TranNameGOUSE pubs
GO
Update roysched
SET royalty = royalty * 1.10
Where title_id LIKE ''''Pc%''''
GO
COMMIT TRANSACTION MyTransaction
GO
這里用到了SQL Server2000自帶的示例數(shù)據(jù)庫pubs,提交事務(wù)后,將為所有暢銷計算機書籍支付的版稅增加 10%。
打開SQL Server2000的查詢分析器,選擇pubs數(shù)據(jù)庫,然后運行這段程序,結(jié)果顯而易見。
可是如何在C#程序中運行呢?我們記得在普通的SQL查詢中,一般需要把查詢語句賦值給SalCommand.CommandText屬性,這里也就像普通的SQL查詢語句一樣,將這些語句賦給SqlCommand.CommandText屬性即可。要注意的一點是,其中的"GO"語句標(biāo)志著SQL批處理的結(jié)束,編寫SQL腳本是需要的,但是在這里是不必要的。我們可以編寫如下的程序來驗證這個想法:
//TranSql.csusing System;
using System.Data;
using System.Data.SqlClient;
namespace Aspcn
{
public class DbTranSql
{
file://將事務(wù)放到SQL Server中執(zhí)行
public void DoTran()
{
file://建立連接并打開
SqlConnection myConn=GetConn();myConn.Open();
SqlCommand myComm=new SqlCommand();
try
{
myComm.Connection=myConn;
myComm.CommandText="DECLARE @TranName VARCHAR(20) ";
myComm.CommandText+="Select @TranName = ''''MyTransaction'''' ";
myComm.CommandText+="BEGIN TRANSACTION @TranName ";
myComm.CommandText+="USE pubs ";
myComm.CommandText+="Update roysched SET royalty = royalty * 1.10 Where title_id LIKE ''''Pc%'''' ";
myComm.CommandText+="COMMIT TRANSACTION MyTransaction ";
myComm.ExecuteNonQuery();
}
catch(Exception err)
{
throw new ApplicationException("事務(wù)操作出錯,系統(tǒng)信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
file://獲取數(shù)據(jù)連接
private SqlConnection GetConn()
{
string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;password=";
SqlConnection myConn=new SqlConnection(strSql);
return myConn;
}
}
public class Test
{
public static void Main()
{
DbTranSql tranTest=new DbTranSql();
tranTest.DoTran();
Console.WriteLine("事務(wù)處理已經(jīng)成功完成。");
Console.ReadLine();
}
}
}
注意到其中的SqlCommand對象myComm,它的CommandText屬性僅僅是前面SQL代碼字符串連接起來即可,當(dāng)然,其中的"GO"語句已經(jīng)全部去掉了。這個語句就像普通的查詢一樣,程序?qū)QL文本事實上提交給DBMS去處理了,然后接收返回的結(jié)果(如果有結(jié)果返回的話)。
很自然,我們最后看到了輸出"事務(wù)處理已經(jīng)成功完成",再用企業(yè)管理器查看pubs數(shù)據(jù)庫的roysched表,所有title_id字段以"PC"開頭的書籍的royalty字段的值都增加了0.1倍。
這里,我們并沒有使用ADO.net的事務(wù)處理機制,而是簡單地將執(zhí)行事務(wù)的SQL語句當(dāng)作普通的查詢來執(zhí)行,因此,事實上該事務(wù)完全沒有用到.net的相關(guān)特性。
了解.net中的事務(wù)機制
如你所知,在.net框架中主要有兩個命名空間(namespace)用于應(yīng)用程序同數(shù)據(jù)庫系統(tǒng)的交互:System.Data.SqlClient和System.Data.OleDb。前者專門用于連接Microsoft公司自己的SQL Server數(shù)據(jù)庫,而后者可以適應(yīng)多種不同的數(shù)據(jù)庫。這兩個命名空間中都包含有專門用于管理數(shù)據(jù)庫事務(wù)的類,分別是System.Data.SqlClient.SqlTranscation類和System.Data.OleDb.OleDbTranscation類。
就像它們的名字一樣,這兩個類大部分功能是一樣的,二者之間的主要差別在于它們的連接機制,前者提供一組直接調(diào)用 SQL Server 的對象,而后者使用本機 OLE DB 啟用數(shù)據(jù)訪問。 事實上,ADO.net 事務(wù)完全在數(shù)據(jù)庫的內(nèi)部處理,且不受 Microsoft 分布式事務(wù)處理協(xié)調(diào)器 (DTC) 或任何其他事務(wù)性機制的支持。本文將主要介紹System.Data.SqlClient.SqlTranscation類,下面的段落中,除了特別注明,都將使用System.Data.SqlClient.SqlTranscation類。
+++@@@+++
事務(wù)的開啟和提交
現(xiàn)在我們對事務(wù)的概念和原理都了然于心了,并且作為已經(jīng)有一些基礎(chǔ)的C#開發(fā)者,我們已經(jīng)熟知編寫數(shù)據(jù)庫交互程序的一些要點,即使用SqlConnection類的對象的Open()方法建立與數(shù)據(jù)庫服務(wù)器的連接,然后將該連接賦給SqlCommand對象的Connection屬性,將欲執(zhí)行的SQL語句賦給它的CommandText屬性,于是就可以通過SqlCommand對象進行數(shù)據(jù)庫操作了。對于我們將要編寫的事務(wù)處理程序,當(dāng)然還需要定義一個SqlTransaction類型的對象。并且看到SqlCommand對象的Transcation屬性,我們很容易想到新建的SqlTransaction對象應(yīng)該與它關(guān)聯(lián)起來。
基于以上認(rèn)識,下面我們就開始動手寫我們的第一個事務(wù)處理程序。我們可以很熟練地寫出下面這一段程序:
//DoTran.csusing System;
using System.Data;
using System.Data.SqlClient;
namespace Aspcn
{
public class DbTran
{
file://執(zhí)行事務(wù)處理
public void DoTran()
{
file://建立連接并打開
SqlConnection myConn=GetConn();
myConn.Open();
SqlCommand myComm=new SqlCommand();
SqlTransaction myTran=new SqlTransaction();
try
{
myComm.Connection=myConn;
myComm.Transaction=myTran;
file://定位到pubs數(shù)據(jù)庫
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();
file://更新數(shù)據(jù)
file://將所有的計算機類圖書
myComm.CommandText="Update roysched SET royalty = royalty * 1.10 Where title_id LIKE ''''Pc%''''";
myComm.ExecuteNonQuery();//提交事務(wù)
myTran.Commit();
}
catch(Exception err)
{
throw new ApplicationException("事務(wù)操作出錯,系統(tǒng)信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
file://獲取數(shù)據(jù)連接
private SqlConnection GetConn()
{
string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;password=";
SqlConnection myConn=new SqlConnection(strSql);
return myConn;
}
}
public class Test{public static void Main()
{
DbTran tranTest=new DbTran();
tranTest.DoTran();
Console.WriteLine("事務(wù)處理已經(jīng)成功完成。");
Console.ReadLine();
}
}
}
顯然,這個程序非常簡單,我們非常自信地編譯它,但是,出乎意料的結(jié)果使我們的成就感頓時煙消云散:
error CS1501: 重載"SqlTransaction"方法未獲取"0"參數(shù)
是什么原因呢?注意到我們初始化的代碼:
SqlTransaction myTran=new SqlTransaction();
顯然,問題出在這里,事實上,SqlTransaction類并沒有公共的構(gòu)造函數(shù),我們不能這樣新建一個SqlTrancaction類型的變量。在事務(wù)處理之前確實需要有一個SqlTransaction類型的變量,將該變量關(guān)聯(lián)到SqlCommand類的Transcation屬性也是必要的,但是初始化方法卻比較特別一點。在初始化SqlTransaction類時,你需要使用SqlConnection類的BeginTranscation()方法:
SqlTransaction myTran; myTran=myConn.BeginTransaction();
該方法返回一個SqlTransaction類型的變量。在調(diào)用BeginTransaction()方法以后,所有基于該數(shù)據(jù)連接對象的SQL語句執(zhí)行動作都將被認(rèn)為是事務(wù)MyTran的一部分。同時,你也可以在該方法的參數(shù)中指定事務(wù)隔離級別和事務(wù)名稱,如:
SqlTransaction myTran;
myTran=myConn.BeginTransaction(IsolationLevel.ReadCommitted,"SampleTransaction");
關(guān)于隔離級別的概念我們將在隨后的內(nèi)容中探討,在這里我們只需牢記一個事務(wù)是如何被啟動,并且關(guān)聯(lián)到特定的數(shù)據(jù)鏈接的。
先不要急著去搞懂我們的事務(wù)都干了些什么,看到這一行:
myTran.Commit();
是的,這就是事務(wù)的提交方式。該語句執(zhí)行后,事務(wù)的所有數(shù)據(jù)庫操作將生效,并且為數(shù)據(jù)庫事務(wù)的持久性機制所保持--即使系統(tǒng)在這以后發(fā)生致命錯誤,該事務(wù)對數(shù)據(jù)庫的影響也不會消失。
對上面的程序做了修改之后我們可以得到如下代碼(為了節(jié)約篇幅,重復(fù)之處已省略,請參照前文):
//DoTran.cs……}
file://執(zhí)行事務(wù)處理
public void DoTran()
{
file://建立連接并打開
SqlConnection myConn=GetConn();
myConn.Open();
SqlCommand myComm=new SqlCommand();
file://SqlTransaction myTran=new SqlTransaction();
file://注意,SqlTransaction類無公開的構(gòu)造函數(shù)
SqlTransaction myTran;
file://創(chuàng)建一個事務(wù)
myTran=myConn.BeginTransaction();
try
{
file://從此開始,基于該連接的數(shù)據(jù)操作都被認(rèn)為是事務(wù)的一部分
file://下面綁定連接和事務(wù)對象
myComm.Connection=myConn;
myComm.Transaction=myTran; file://定位到pubs數(shù)據(jù)庫
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();//更新數(shù)據(jù)
file://將所有的計算機類圖書
myComm.CommandText="Update roysched SET royalty = royalty * 1.10 Where title_id LIKE ''''Pc%''''";
myComm.ExecuteNonQuery();
file://提交事務(wù)
myTran.Commit();
}
catch(Exception err)
{
throw new ApplicationException("事務(wù)操作出錯,系統(tǒng)信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
……
到此為止,我們僅僅掌握了如何開始和提交事務(wù)。下一步我們必須考慮的是在事務(wù)中可以干什么和不可以干什么。
該文章轉(zhuǎn)載自'大智の博客':http://www.csafe.cn/article.asp?id=271