買到蘋果新款MacBook Air后大家最想干的事是什么?體驗一下Mac OS X?事實告訴我們有幾乎一半的人第一件想要做的事是裝一個微軟的Windows系統,但問題是新版的MBA已經沒有光驅了,這可如何是好?其實只需一個4GB的U盤便能搞定了。
首先你要準備的是一臺攜帶光驅的Windows 7電腦,另外需要準備一張Windows 7系統光盤,還需要一個至少4GB的U盤(閃存+讀卡器不可),再準備大概1個小時,恩,差不多就行了。
一,在U盤上安裝Windows 7的詳細步驟
1.先將U盤插到Windows 7電腦上,接著用管理員身份啟動CMD命令提示符。
(單擊開始-搜索區域鍵入“CMD”-對著CMD右鍵選擇以管理員身份運行)
2.打開Diskpart,這是因為平時我們看到的系統都是字母盤符,我們需要讓其變為最原始的數字。
(在CMD中輸入“diskpart”,然后按回車,切換為DISKPART>之后輸入“list disk”按回車)
3.現在屏幕上應該會顯示出所有電腦上正在使用的儲存設備,根據容量就能看出哪一個是我們插入的U盤,3856 MB那個當然就是4GB的U盤,讓我們選中它吧。
(在CMD中輸入“select disk 3”,U盤所在的位置)
接下來運行的每一個步驟都不能有錯,另外你還需要確保一件事,那就是在第3步中你已經成功選擇了U盤所在位置,不然其他硬盤數據可就清空了哦。
(在CMD中輸入“clean”清空U盤,輸入“create partition primary”創建主分區,輸入“select partition 1”選擇分區1,輸入“active”將選中分區標記為活動分區,輸入“format fs=ntfs”格式化U盤的分區1,輸入“assign”給所選分區分配一個驅動器號,輸入“exit”退出Diskpart)(輸入“assign”時U盤有可能斷開重新連接,這很正常,請不要驚慌)
4.我們需要將Windows 7的安裝內容裝進U盤內,請將你的Windows 7光盤插入到光驅內(本次案例光驅所在位置為E盤,U盤所在位置為H盤,諸君請自動替換適用盤符)
(插入光盤后在CMD中輸入“e: cd boot”改為光盤啟動,輸入“bootsect.exe /nt60 h:”使其安裝至U盤)
5.接下來電腦會將Windows 7的安裝內容全部儲存到U盤內,這需要等待10分鐘左右,在那之后U盤就可以在任何電腦上安裝Windows 7了,不過首選當然需要在BIOS中設置為U盤啟動。好了,U盤安裝完畢,接著讓我們拿出U盤,拿出等候已久的新款MacBook Air。
二,接著使用MacBook Air支持U盤啟動
雖然新款的MacBook Air支持用U盤安裝軟件,但這并不代表其可以直接在Mac中安裝Windows 7,畢竟你可不能直接在Mac中運行Setup.exe對吧。所以我們還需要一個軟件,那就是rEFIt引導工具,下載地址在這。下載完之后在Mac雙擊運行rEFIt.mpkg即可安裝。
安裝完畢后,下次你重新啟動MacBook Air的時候應該就會出現如下畫面了,這樣就能選擇是使用Mac OS X啟動還是其他系統啟動了(當然是Windows啦)。不過首先需要按住Option鍵在設置中將路徑改為U盤所在位置。
三,在MacBook Air上安裝Windows 7
要想在MacBook Air安裝Windows 7,我們還需要一個軟件,那就是Boot Camp Assistant,該軟件已經在Mac OS X中自帶了,請各位同學自己尋找。運行它之后,會提示你需要一個光盤驅動器,忽略這條消息,點擊繼續。
下一步,你需要下載Windows支持的軟件,包括Boot Camp中的各種驅動以及遠程CD/DVD支持,都保存在一個文件夾中吧,接下來你會用到它的。
接下來Boot Camp Assistant會要求你縮小現在的Mac OS X上的分區大小以騰出空間安裝Windows,請謹慎選擇分區大小,畢竟兩個分區的文件格式將會改變。
現在你可以在MacBook Air上插入剛才制作好的Windows 7啟動U盤,然后重新啟動MBA,按住Option鍵,確保路徑選擇是U盤啟動。USB圖標應該很容易辨認。
接下來就會進入Windows 7的安裝過程,這一步相信大家都是熟門熟路了,只有一點需要注意的是,剛才通過 Boot Camp Assistant劃分的分區是FAT32格式的,而Windows 7不能使用FAT32的分區,所以選擇的時候需要重新格式化改為NTFS格式。
這是目前為止安裝Windows最快的電腦,新款MacBook Air一共花了才7分鐘就能將Windows 7安裝完畢,是不是覺得有點不可思議?進入Windows 7后還有一件事需要干,那就是將剛才下載的Boot Camp中的Windows的驅動程序安裝一遍,接著你就能使用Windows 7了!
Sun號稱開源方面的領路人之一,其實Google擁有的開源項目也是十分豐富的。除了開發方面的項目外,也有MySQL等方面的內容。在這其中還包括新出的Google Go!
Google是支持開源運動的最大公司之一,它們現在總共發布有超過500個的開源項目(大部分都是利用它們的API來完成),本文將列舉一些有趣的開源項目,其中很可能有不少你不知道的哦。
Google開源助Web2.0開發 不排斥專有深入了解Google開源框架GWT Google開源新舉動:Linux桌面1.1版上線(.. Mozilla、Google開源合作遭美國稅局質疑微軟擔心Google和蘋果超越Windows 8 文本文件處理:
◆Google CRUSH (Custom Reporting Utilities for SHell)
CRUSH是為命令行或shell scripts處理特定文字數據而制作的一系列工具,這里有指南。
C++庫和源代碼:
◆Google Breakpad
一個開源的多平臺崩潰報告系統。
◆Google GFlags
Gflags是一個命令行標記的處理庫,它可以替代“getopt()”,其內置對C++的支持比如string。指南在此。
◆Google Glog
Glog庫可執行應用級的登陸,提供基于C++式的登陸API,可用于Linux、BSD和Windows。指南見此。
◆Google PerfTools
這個工具可讓開發創建更強大的應用程序,特別是那些用C++模版開發的多線程應用程序,包括TCMalloc, heap-checker, heap-profiler 和cpu-profiler。指南見此還有這里。
◆Google Sparse Hash
非常節省內存的hash-map。指南見此。
◆Omaha – Google Update
Omaha,也就是Google Update,它可以保證你的軟件隨時升級到最新版本,目前很多Windows下的Google軟件都是用Omaha升級的,包括Google Chrome和Google Earth,當然你也可以用于自己的應用程序。指南看這里還有這里。
◆Protocol Buffers
Protocol Buffers是一種可擴展編碼序列數據的方式,Google在幾乎所有內部RPC協議和文件格式都使用了Protocol Buffers。指南見此。它可以用于很多語言而且被一些IDE所支持,比如NetBeans。
互聯網:
◆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使你可以更輕松的創造CSS Sprites(俗稱雪碧……)就是把網站要用到的圖片都堆在一張圖片里,用CSS控制調用哪個區域。它有一個自己的官網在這里。
◆Redacisaurus
Reducisaurus是一個壓縮CSS和JS文件的網絡服務,基于YUI壓縮算法,運行于App Engine。
◆JaikuEngine
JaikuEngine是一個運行于App Engine的微博系統,由jaiku.com運營。要查看移動客戶端的源碼可以看這里,這里還有介紹。
◆Selector Shell
Selector Shell是一個基于瀏覽器的測試工具,它可以讓你看到CSS在不同瀏覽器里的樣式,用Javascript寫的,你可以在這里測試。
◆Google Feed Server
Google Feed Server是一個開源Atom發布協議服務,基于Apache Abdera框架,允許開發者快速為當前數據源(比如數據庫)配置feed。指南見這里和這里。
◆Melange, the Spice of Creation
這個項目的目標是創建出一個適合開源貢獻流程的框架,比如Google Summer of Code TM (GSoC)項目。使用這個框架你就可以用Google App Engine來運行Google Summer of Code項目,和其它類似項目比如Google Highly Open Participation TM Contest和GHOP。指南見此。
◆NameBench
它可以查找最快的DNS服務器給你的電腦用,在Mac OS X、Windows和UNIX系統下都有命令行也有用戶界面可以幫你測試,這是Google工程師用20%自由時間寫出來的。
◆Rat Proxy
一個半自動化的大型被動網絡應用安全審查工具,專為精確的探測而優化,文檔在此。
◆TopDraw
Top Draw是一個圖形生成程序,使用簡單的文字腳本,基于JavaScript編程語言,Top Draw可以創造出非常復雜和有趣的圖形。支持Mac OS 10.5以上系統,使用XCode開發。
◆etherpad
開源的EtherPad,這是一個基于網絡的實時合作文檔編輯器,這個項目主要是為了演示代碼而開發,幫助那些想在自己服務器部署Etherpad的人使用,這里有如何安裝的指南。EtherPad使用JavaScript、Java和Comet服務器來建造實時協作服務。
◆Chromium
Chromium是開源版的Chrome瀏覽器,Chromium的目標是建立一個新一代的強大網絡應用程序,它與Chrome有很多不同之處。這里有指導如何在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操作系統,提供快速、簡單而安全的網絡體驗,源碼在此。
◆Android
Android是第一個免費、開源而且可完全自定義的移動平臺,提供完整的堆棧:一個操作系統、中間件和重要的一用應用,它包含豐富的API可以讓第三方開發者開發出強大的應用程序。
MySQL工具:
◆Google MySQL Tools
各種管理、維護和改進MySQL數據庫性能的工具,由Google編寫,包括:
◆mypgrep.py:一個類似pgrep的工具來管理MySQL連接
compact_innodb.py:可導出和重載所有表格的密集型innodb數據文件
◆Google mMAIM
mMAIM的目標是對MySQL的監控和分析更簡單,且可以和任何環境整合使用。它可顯示主/從同步狀態,一些性能狀態,可以返回大量“show”命令的狀態等等。
其它:
◆Stressful Application Test (stressapptest)
Stressful Application Test試圖讓來自處理器和I/O到內存的數據盡量隨機化,以創造出模擬現實的環境來測試現在的硬件設備是否穩定,Google就在使用它,現在是Apache 2.0許可,這里有介紹、安裝向導和指南。
◆Pop and IMAP Troubleshooter
它用于診斷并解決客戶端到郵件服務器的連接問題。
◆OpenDuckBill
Openduckbill是一個Linux下簡單的命令行備份工具,可用于監視文件/目錄在有變化后是否標記為備份,并傳輸這些變化到本地備份目錄、遠程NFS導出分卷或是用rsync命令導出到遠程SSH服務器。見安裝向導。
◆ZXing
ZXing(發音類似Zebra crossing)是Java的開源多格式1D/2D條碼圖像處理庫,目的是使用內置在手機上的攝像頭拍照并對條碼進行解碼,而不必與服務器通訊,它被用于Android系統。這里有向導和支持的設備列表。
◆Tesseract OCR Engine
Tesseract OCR引擎是1995年UNLV Accuracy測試的前三名之一,在1995和2006年之間它的進展不大,但依然是當前精度最高的OCR引擎。這個源碼可讀取二進制、灰階或彩色圖片并輸出文字,內置一個TIFF閱讀器可讀取非壓縮的TIFF文件,增加libtiff后也可讀取壓縮圖片。指南和問答。
◆Neatx – Open Source NX server
Neatx是一個開源NX服務,類似NoMachine公司商業的NX服務。NX協議比VNX更強大,它們的區別主要在:
NX是X11客戶端所以不會發送位圖
NX可兼容X、VNC和Windows版的Remote Desktop
NX可緩存數據
NX安裝簡單
另外一個可選的項目可以看看Google的FreeNx。
◆PSVM
它是這個文件的代碼,這是一個SVM的“支持所有核心”的版本,可多機并行運行,實例見此。
◆Google GO
Google開發的新編程語言。
◆The Google Collections Library for Java
這是一系列與Java 5以及更高版本有關的庫,Google花錢給買過來了。
◆Google styleguIDE
每個主流的開源項目都有它自己的向導形式,比如一系列的演示代碼。如果這些代碼都按照“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
歡迎轉載,但請保留作者信息
SDL的設計并沒有考慮到要和MFC相結合,但是既然它要在windows的系統上運行,必然需要使用Windows提供的API。為了在MFC SDI中使用SDL,首先想到的就是替換SDL創建的窗口,改為使用MFC提供的窗口。
想想在Windows下要創建窗口需要使用的API必然是CreateWindow,在SDL代碼中搜,很容易發現了這樣一段代碼:
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是不會創建新窗口的!而這個值直接來自于SDL_WINDOWID這個環境變量!以此推斷,只要在調用SDL_Init之前設置好SDL_WINDOWID這個環境變量,那么SDL將可以使用我們提供的窗口。
下面修改SDL提供的testwin示例,使之在MFC SDI環境下運行。
1.1 工程創建
直接使用VS2008的向導生成一個叫sdi_sdl的MFC工程,選擇SDI類型。
1.2 拋棄SDLmain.lib
在SDL提供的測試用例中,都要使用SDLmain.lib,這個lib文件實現了Winmain和main這兩個入口函數,在這兩個函數中進行了一些SDL的初始化工作。而在MFC下,我們不需要自己寫WinMain,因此直接拋棄SDLmain.lib,將相關的代碼轉移到Csdi_sdlView的OnCreate函數中。之所以選擇Csdi_sdlView::OnCreate是因為此時窗口已經創建,可以取到這個窗口的Handle,從而可以在SDL初始化之前設置好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
這個函數來源于SDLmain中的WinMain函數,只是刪除了一些不必要的代碼:
/* 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
這個函數來源于sdlmain.lib中的main函數:
/* 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
這個函數來自于testwin示例中的main函數,只是在末尾刪除了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);
}
至此,這個程序就可以正常運行了,但是它的大小還不能隨主窗口的變化而變化。為此還需要響應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
在程序退出的時候,需要調用SDL_Quit進行一些清理的工作,原來想將這個工作放在Cview::OnDestroy中完成,但是發現這樣有很多的內存泄漏。最后將其放在Csdi_sdlApp:ExitInstance中完成:
BOOL Csdi_sdlApp::ExitInstance()
{
SDL_Quit();
return TRUE;
}
即便是這樣,仍然有一處內存泄漏,原因不明:
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博客,轉載請標明出處:http://blog.csdn.net/lights_joy/archive/2009/04/04/4049123.aspx
出處:http://www.zixundao.com/thread-1672-1-4.html
SDL是一種既是開源的,也是跨平臺的多媒體開發包,在各種平臺上應用很廣,經常和FFMPEG等解碼器同時使用。對于在windows mobile等缺乏通用播放器的平臺來說,是一種很好的選擇。
網上很多代碼,介紹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本身響應窗口菜單的問題
SDL官方提供以下代碼響應窗口菜單:
while(1) {
SDL_WaitEvent(&event);
{
case
}
}
但也可以我們在程序里面重新初始化并顯示新菜單,就可以不用這種辦法,直接用我們自己的程序響應菜單。
第三:關于縮放:
網上很多代碼容易誤導人。
把SDL_SetVideoMode和SDL_CreateYUVOverlay的參數都設置成一樣的,這種辦法導致屏幕圖象縮放顯示不正常,正確的方法應該是:SDL_SetVideoMode的參數顯示新的顯示大小,而SDL_CreateYUVOverlay(只需建立一次,SDL_SetVideoMode更換時,不需要跟著更換)的參數則是圖片的原始大小 。
而在SDL_DisplayYUVOverlay中用到的SDL_Rect,大小則和SDL_SetVideoMode一樣,也就是新的顯示大小。
本文原創,轉載請注明出處和作者,謝謝。
作者:藍梅居士
出處:http://www.zixundao.com/thread-1672-1-4.html
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/baishuren/archive/2009/10/13/4665153.aspx
sdl是開源的跨平臺多媒體開發包, 主要用在快速的視頻格式轉換和顯示,以及封裝了鍵盤/鼠標/手機按鍵/觸屏等各個平臺的用戶交互響應,廣泛應用在游戲,多媒體播放器等應用中。目前支持windows,linux, wince,mac os,非正式地支持symbian os。
一般視頻解碼器輸出圖像的是yuv420格式,而屏幕顯示大都是rgb42規格。 mobile上畫面顯示一般經由decode>>yuv2rgb>>scale>>directDraw直接寫屏。 采用SDL可以加速這一過程,且更方便響應全屏縮放等用戶操作。
下面介紹mobile上用sdl來加速顯示視頻的全過程。
1. 把主對話框的窗口句柄傳給顯示類。
2. 初始化sdl,設置顯示視頻模式
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);
//根據解碼后的視頻尺寸來初始化sdl
screen = SDL_SetVideoMode(ImageWidth, ImageHeight, 0,SDL_ANYFORMAT|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_HWSURFACE);//注意用到的參數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數據的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. 事件輪詢和按鍵響應
void SdlEvent()
{
SDL_Event event;
while ( SDL_PollEvent(&event))
{
TRACE(L"========SDL VIDEORESIZE EVENT START");
switch (event.type)
{
case SDL_VIDEORESIZE:
// 響應圖像縮放事件
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:
//響應觸屏筆點擊事件
break;
}
case SDL_QUIT:
//響應退出事件
break;
default:
break;
}
}
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/lius1984/archive/2009/08/07/4420786.aspx
讓游戲開發者不必為每一品牌的硬件來寫不同的驅動程序,也降低用戶安裝及設置硬件的復雜度。這樣說是不是有點不太明白,其實從字面意義上說,Direct就是直接
的意思,而后邊的X則代表了很多的意思,從這一點上我們就可以看出 DirectX的出現就是為了為眾多軟件提供直接服務的。
DirectX是由很多API組成的,按照性質分類,可以分為四大部分,顯示部分、聲音部分、輸入部分和網絡部分。
顯示部分擔任圖形處理的關鍵,分為Direct Draw(DDraw)和Direct 3D(D3D),前者主要負責2D圖像加速。它包括很多方面:我們播放mpg、DVD電影、看圖、玩小游戲等等都是用的DDraw,你可以把它理解成所有劃線的部分都是用的DDraw。后者則主要負責3D效果的顯示,比如CS中的場景和人物、FIFA中的人物等等,都是使用了DirectX的Direct 3D。
聲音部分中最主要的API是DirectSound,除了播放聲音和處理混音之外,還加強了3d音效,并提供了錄音功能。我們前面所舉的聲卡兼容的例子,就是利用了DirectSound來解決的。
輸入部分Direct Input可以支持很多的游戲輸入設備,它能夠讓這些設備充分發揮最佳狀態和全部功能。除了鍵盤和鼠標之外還可以連接手柄、搖桿、模擬器等。
網絡部分DirectPlay主要就是為了具有網絡功能游戲而開發的,提供了多種連接方式,TPC/IP,IPX,Modem,串口等等,讓玩家可以用各種連網方式來進行對戰,此外也提供網絡對話功能及保密措施。
DirectX并不是一個單純的圖形API,它是由微軟公司開發的用途廣泛的API,它包含有Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多個組件,它提供了一整套的多媒體接口方案。只是其在3D圖形方面的優秀表現,讓它的其它方面顯得暗淡無光。DirectX開發之初是為了彌補Windows 3.1系統對圖形、聲音處理能力的不足,而今已發展成為對整個多媒體系統的各個方面都有決定性影響的接口。 DirectX 是一組低級“應用程序編程接口 (API)”,可為 Windows 程序提供高性能的硬件加速多媒體支持。Windows 支持 DirectX 8.0,它能增強計算機的多媒體功能。使用 DirectX 可訪問顯卡與聲卡的功能,從而使程序可提供逼真的三維 (3D) 圖形與令人如醉如癡的音樂與聲音效果。 DirectX 使程序能夠輕松確定計算機的硬件性能,然后設置與之匹配的程序參數。該程序使得多媒體軟件程序能夠在基于 Windows 的具有 DirectX 兼容硬件與驅動程序的計算機上運行,同時可確保多媒體程序能夠充分利用高性能硬件。 DirectX 包含一組 API,通過它能訪問高性能硬件的高級功能,如三維圖形加速芯片和聲卡。這些 API 控制低級功能(其中包括二維 (2D) 圖形加速)、支持輸入設備(如游戲桿、鍵盤和鼠標)并控制著混音及聲音輸出。構成 DirectX 的下列組件支持低級功能: Microsoft DirectDraw Microsoft DirectDraw API 支持快速訪問計算機視頻適配器的加速硬件功能。它支持在所有視頻適配器上顯示圖形的標準方法,并且使用加速驅動程序時可以更快更直接地訪問。DirectDraw 為程序(如游戲和二維圖形程序包)以及 Windows 系統組件(如數字視頻編解碼器)提供了一種獨立于設備之外的方法來訪問特定顯示設備的功能,而不要求用戶提供設備功能的其它信息。
Microsoft Direct3D Microsoft Direct3D API (Direct3D) :為大多數新視頻適配器內置的 3-D 調色功能提供界面。Direct3D 是一種低級的 3-D API,它為軟件程序提供一種獨立于設備之外的方法以便與加速器硬件進行有效而強大的通信。Direct3D 包含專用 CPU 指令集支持,從而可為新型計算機提供進一步加速支持。
Microsoft DirectSound Microsoft DirectSound API :為程序和音頻適配器的混音、聲音播放和聲音捕獲功能之間提供了鏈接。DirectSound 為多媒體軟件程序提供低延遲混合、硬件加速以及直接訪問聲音設備等功能。維護與現有設備驅動程序的兼容性時提供該功能。
Microsoft DirectMusic Microsoft DirectMusic API :是 DirectX 的交互式音頻組件。與捕獲和播放數字聲音樣本的 DirectSound API 不同,DirectMusic 處理數字音頻以及基于消息的音樂數據,這些數據是通過聲卡或其內置的軟件合成器轉換成數字音頻的。DirectMusic API 支持以“樂器數字界面 (MIDI)”格式進行輸入,也支持壓縮與未壓縮的數字音頻格式。DirectMusic 為軟件開發人員提供了創建令人陶醉的動態音軌的能力,以響應軟件環境中的各種更改,而不只是用戶直接輸入更改。
Microsoft DirectInput Microsoft DirectInput API :為游戲提供高級輸入功能并能處理游戲桿以及包括鼠標、鍵盤和強力反饋游戲控制器在內的其它相關設備的輸入。
Microsoft DirectPlay Microsoft DirectPlay API: 支持通過調制解調器、Internet 或局域網連接游戲。DirectPlay 簡化了對通信服務的訪問,并提供了一種能夠使游戲彼此通信的方法而不受協議或聯機服務的限制。DirectPlay 提供了多種游說服務,可簡化多媒體播放器游戲的初始化,同時還支持可靠的通信協議以確保重要游戲數據在網絡上不會丟失。DirectPlay 8.0 的新功能即支持通過網絡進行語音通信,從而可大大提高基于多媒體播放器小組的游戲的娛樂性,同時該組件還通過提供與玩游戲的其他人對話的功能而使團體游戲更具魅力。
Microsoft DirectShow Microsoft DirectShow API: 提供了可在您的計算機與 Internet 服務器上進行高品質捕獲與回放多媒體文件的功能。DirectShow 支持各種音頻與視頻格式,包括“高級流式格式 (ASF)”、“音頻-視頻交錯 (AVI)”、“數字視頻 (DV)”、“動畫專家組 (MPEG)”、“MPEG 音頻層 3 (MP3)”、 “Windows 媒體音頻/視頻 (WMA/WMV)”以及 WAV 文件。DirectShow 還具有視頻捕獲、DVD 回放、視頻編輯與混合、硬件加速視頻解碼以及調諧廣播模擬與數字電視信號等功能。
歐幾里德算法是計算兩個數最大公約數的傳統算法,他無論從理論還是從效率上都是很好的。但是他有一個致命的缺陷,這個缺陷只有在大素數時才會顯現出來。
考慮現在的硬件平臺,一般整數最多也就是64位,對于這樣的整數,計算兩個數之間的模是很簡單的。對于字長為32位的平臺,計算兩個不超過32位的整數的模,只需要一個指令周期,而計算64位以下的整數模,也不過幾個周期而已。但是對于更大的素數,這樣的計算過程就不得不由用戶來設計,為了計算兩個超過64位的整數的模,用戶也許不得不采用類似于多位數除法手算過程中的試商法,這個過程不但復雜,而且消耗了很多CPU時間。對于現代密碼算法,要求計算128位以上的素數的情況比比皆是,設計這樣的程序迫切希望能夠拋棄除法和取模。
Stein算法由J. Stein 1961年提出,這個方法也是計算兩個數的最大公約數。和歐幾里德算法 算法不同的是,Stein算法只有整數的移位和加減法,這對于程序設計者是一個福音。
為了說明Stein算法的正確性,首先必須注意到以下結論:
有了上述規律就可以給出Stein算法如下:
這個算法的原理很顯然,所以就不再證明了。現在考察一下該算法和歐幾里德方法效率上的差別。
考慮歐幾里德算法,最惡劣的情況是,每次迭代a = 2b -1,這樣,迭代后,r= b-1。如果a小于2N,這樣大約需要 4N次迭代。而考慮Stein算法,每次迭代后,顯然AN+1BN+1≤ ANBN/2,最大迭代次數也不超過4N次。也就是說,迭代次數幾乎是相等的。但是,需要注意的是,對于大素數,試商法將使每次迭代都更復雜,因此對于大素數Stein將更有優勢。
外聯接可以是左向外聯接、右向外聯接或完整外部聯接。在 FROM 子句中指定外聯接時,可以由下列幾組關鍵字中的一組指定:LEFT JOIN 或 LEFT OUTER JOIN。
左向外聯接的結果集包括 LEFT OUTER 子句中指定的左表的所有行,而不僅僅是聯接列所匹配的行。如果左表的某行在右表中沒有匹配行,則在相關聯的結果集行中右表的所有選擇列表列均為空值。
RIGHT JOIN 或 RIGHT OUTER JOIN。
右向外聯接是左向外聯接的反向聯接。將返回右表的所有行。如果右表的某行在左表中沒有匹配行,則將為左表返回空值。
FULL JOIN 或 FULL OUTER JOIN。
完整外部聯接返回左表和右表中的所有行。當某行在另一個表中沒有匹配行時,則另一個表的選擇列表列包含空值。如果表之間有匹配行,則整個結果集行包含基表的數據值。
僅當至少有一個同屬于兩表的行符合聯接條件時,內聯接才返回行。內聯接消除與另一個表中的任何行不匹配的行。而外聯接會返回 FROM 子句中提到的至少一個表或視圖的所有行,只要這些行符合任何 WHERE 或 HAVING 搜索條件。將檢索通過左向外聯接引用的左表的所有行,以及通過右向外聯接引用的右表的所有行。完整外部聯接中兩個表的所有行都將返回。
Microsoft® SQL Server™ 2000 對在 FROM 子句中指定的外聯接使用以下 SQL-92 關鍵字:
LEFT OUTER JOIN 或 LEFT JOIN
RIGHT OUTER JOIN 或 RIGHT JOIN
FULL OUTER JOIN 或 FULL JOIN
SQL Server 支持 SQL-92 外聯接語法,以及在 WHERE 子句中使用 *= 和 =* 運算符指定外聯接的舊式語法。由于 SQL-92 語法不容易產生歧義,而舊式 Transact-SQL 外聯接有時會產生歧義,因此建議使用 SQL-92 語法。
使用左向外聯接
假設在 city 列上聯接 authors 表和 publishers 表。結果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。
若要在結果中包括所有的作者,而不管出版商是否住在同一個城市,請使用 SQL-92 左向外聯接。下面是 Transact-SQL 左向外聯接的查詢和結果:
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
下面是結果集:
au_fname au_lname pub_name |
不管是否與 publishers 表中的 city 列匹配,LEFT OUTER JOIN 均會在結果中包含 authors 表的所有行。注意:結果中所列的大多數作者都沒有相匹配的數據,因此,這些行的 pub_name 列包含空值。
使用右向外聯接
假設在 city 列上聯接 authors 表和 publishers 表。結果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。SQL-92 右向外聯接運算符 RIGHT OUTER JOIN 指明:不管第一個表中是否有匹配的數據,結果將包含第二個表中的所有行。
若要在結果中包括所有的出版商,而不管城市中是否還有出版商居住,請使用 SQL-92 右向外聯接。下面是 Transact-SQL 右向外聯接的查詢和結果:
USE pubs |
下面是結果集:
au_fname au_lname pub_name |
使用謂詞(如將聯接與常量比較)可以進一步限制外聯接。下例包含相同的右向外聯接,但消除銷售量低于 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
下面是結果集:
stor_id qty title |
有關謂詞的更多信息,請參見 WHERE。
使用完整外部聯接
若要通過在聯接結果中包括不匹配的行保留不匹配信息,請使用完整外部聯接。Microsoft® SQL Server™ 2000 提供完整外部聯接運算符 FULL OUTER JOIN,不管另一個表是否有匹配的值,此運算符都包括兩個表中的所有行。
假設在 city 列上聯接 authors 表和 publishers 表。結果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。SQL-92 FULL OUTER JOIN 運算符指明:不管表中是否有匹配的數據,結果將包括兩個表中的所有行。
若要在結果中包括所有作者和出版商,而不管城市中是否有出版商或者出版商是否住在同一個城市,請使用完整外部聯接。下面是 Transact-SQL 完整外部聯接的查詢和結果:
USE pubs |
下面是結果集:
|
設想網上購物的一次交易,其付款過程至少包括以下幾步數據庫操作:
· 更新客戶所購商品的庫存信息
· 保存客戶付款信息--可能包括與銀行系統的交互
· 生成訂單并且保存到數據庫中
· 更新用戶相關信息,例如購物數量等等
正常的情況下,這些操作將順利進行,最終交易成功,與交易相關的所有數據庫信息也成功地更新。但是,如果在這一系列過程中任何一個環節出了差錯,例如在更新商品庫存信息時發生異常、該顧客銀行帳戶存款不足等,都將導致交易失敗。一旦交易失敗,數據庫中所有信息都必須保持交易前的狀態不變,比如最后一步更新用戶信息時失敗而導致交易失敗,那么必須保證這筆失敗的交易不影響數據庫的狀態--庫存信息沒有被更新、用戶也沒有付款,訂單也沒有生成。否則,數據庫的信息將會一片混亂而不可預測。
數據庫事務正是用來保證這種情況下交易的平穩性和可預測性的技術。
數據庫事務的ACID屬性
事務處理可以確保除非事務性單元內的所有操作都成功完成,否則不會永久更新面向數據的資源。通過將一組相關操作組合為一個要么全部成功要么全部失敗的單元,可以簡化錯誤恢復并使應用程序更加可靠。一個邏輯工作單元要成為事務,必須滿足所謂的ACID(原子性、一致性、隔離性和持久性)屬性:
· 原子性
事務必須是原子工作單元;對于其數據修改,要么全都執行,要么全都不執行。通常,與某個事務關聯的操作具有共同的目標,并且是相互依賴的。如果系統只執行這些操作的一個子集,則可能會破壞事務的總體目標。原子性消除了系統處理操作子集的可能性。
· 一致性
事務在完成時,必須使所有的數據都保持一致狀態。在相關數據庫中,所有規則都必須應用于事務的修改,以保持所有數據的完整性。事務結束時,所有的內部數據結構(如 B 樹索引或雙向鏈表)都必須是正確的。某些維護一致性的責任由應用程序開發人員承擔,他們必須確保應用程序已強制所有已知的完整性約束。例如,當開發用于轉帳的應用程序時,應避免在轉帳過程中任意移動小數點。
· 隔離性
由并發事務所作的修改必須與任何其它并發事務所作的修改隔離。事務查看數據時數據所處的狀態,要么是另一并發事務修改它之前的狀態,要么是另一事務修改它之后的狀態,事務不會查看中間狀態的數據。這稱為可串行性,因為它能夠重新裝載起始數據,并且重播一系列事務,以使數據結束時的狀態與原始事務執行的狀態相同。當事務可序列化時將獲得最高的隔離級別。在此級別上,從一組可并行執行的事務獲得的結果與通過連續運行每個事務所獲得的結果相同。由于高度隔離會限制可并行執行的事務數,所以一些應用程序降低隔離級別以換取更大的吞吐量。
· 持久性
事務完成之后,它對于系統的影響是永久性的。該修改即使出現致命的系統故障也將一直保持。
DBMS的責任和我們的任務
企業級的數據庫管理系統(DBMS)都有責任提供一種保證事務的物理完整性的機制。就常用的SQL Server2000系統而言,它具備鎖定設備隔離事務、記錄設備保證事務持久性等機制。因此,我們不必關心數據庫事務的物理完整性,而應該關注在什么情況下使用數據庫事務、事務對性能的影響,如何使用事務等等。
本文將涉及到在.net框架下使用C#語言操縱數據庫事務的各個方面。
+++@@@+++
體驗SQL語言的事務機制
作為大型的企業級數據庫,SQL Server2000對事務提供了很好的支持。我們可以使用SQL語句來定義、提交以及回滾一個事務。
如下所示的SQL代碼定義了一個事務,并且命名為"MyTransaction"(限于篇幅,本文并不討論如何編寫SQL語言程序,請讀者自行參考相關書籍):
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自帶的示例數據庫pubs,提交事務后,將為所有暢銷計算機書籍支付的版稅增加 10%。
打開SQL Server2000的查詢分析器,選擇pubs數據庫,然后運行這段程序,結果顯而易見。
可是如何在C#程序中運行呢?我們記得在普通的SQL查詢中,一般需要把查詢語句賦值給SalCommand.CommandText屬性,這里也就像普通的SQL查詢語句一樣,將這些語句賦給SqlCommand.CommandText屬性即可。要注意的一點是,其中的"GO"語句標志著SQL批處理的結束,編寫SQL腳本是需要的,但是在這里是不必要的。我們可以編寫如下的程序來驗證這個想法:
//TranSql.csusing System;
using System.Data;
using System.Data.SqlClient;
namespace Aspcn
{
public class DbTranSql
{
file://將事務放到SQL Server中執行
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("事務操作出錯,系統信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
file://獲取數據連接
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("事務處理已經成功完成。");
Console.ReadLine();
}
}
}
注意到其中的SqlCommand對象myComm,它的CommandText屬性僅僅是前面SQL代碼字符串連接起來即可,當然,其中的"GO"語句已經全部去掉了。這個語句就像普通的查詢一樣,程序將SQL文本事實上提交給DBMS去處理了,然后接收返回的結果(如果有結果返回的話)。
很自然,我們最后看到了輸出"事務處理已經成功完成",再用企業管理器查看pubs數據庫的roysched表,所有title_id字段以"PC"開頭的書籍的royalty字段的值都增加了0.1倍。
這里,我們并沒有使用ADO.net的事務處理機制,而是簡單地將執行事務的SQL語句當作普通的查詢來執行,因此,事實上該事務完全沒有用到.net的相關特性。
了解.net中的事務機制
如你所知,在.net框架中主要有兩個命名空間(namespace)用于應用程序同數據庫系統的交互:System.Data.SqlClient和System.Data.OleDb。前者專門用于連接Microsoft公司自己的SQL Server數據庫,而后者可以適應多種不同的數據庫。這兩個命名空間中都包含有專門用于管理數據庫事務的類,分別是System.Data.SqlClient.SqlTranscation類和System.Data.OleDb.OleDbTranscation類。
就像它們的名字一樣,這兩個類大部分功能是一樣的,二者之間的主要差別在于它們的連接機制,前者提供一組直接調用 SQL Server 的對象,而后者使用本機 OLE DB 啟用數據訪問。 事實上,ADO.net 事務完全在數據庫的內部處理,且不受 Microsoft 分布式事務處理協調器 (DTC) 或任何其他事務性機制的支持。本文將主要介紹System.Data.SqlClient.SqlTranscation類,下面的段落中,除了特別注明,都將使用System.Data.SqlClient.SqlTranscation類。
+++@@@+++
事務的開啟和提交
現在我們對事務的概念和原理都了然于心了,并且作為已經有一些基礎的C#開發者,我們已經熟知編寫數據庫交互程序的一些要點,即使用SqlConnection類的對象的Open()方法建立與數據庫服務器的連接,然后將該連接賦給SqlCommand對象的Connection屬性,將欲執行的SQL語句賦給它的CommandText屬性,于是就可以通過SqlCommand對象進行數據庫操作了。對于我們將要編寫的事務處理程序,當然還需要定義一個SqlTransaction類型的對象。并且看到SqlCommand對象的Transcation屬性,我們很容易想到新建的SqlTransaction對象應該與它關聯起來。
基于以上認識,下面我們就開始動手寫我們的第一個事務處理程序。我們可以很熟練地寫出下面這一段程序:
//DoTran.csusing System;
using System.Data;
using System.Data.SqlClient;
namespace Aspcn
{
public class DbTran
{
file://執行事務處理
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數據庫
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();
file://更新數據
file://將所有的計算機類圖書
myComm.CommandText="Update roysched SET royalty = royalty * 1.10 Where title_id LIKE ''''Pc%''''";
myComm.ExecuteNonQuery();//提交事務
myTran.Commit();
}
catch(Exception err)
{
throw new ApplicationException("事務操作出錯,系統信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
file://獲取數據連接
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("事務處理已經成功完成。");
Console.ReadLine();
}
}
}
顯然,這個程序非常簡單,我們非常自信地編譯它,但是,出乎意料的結果使我們的成就感頓時煙消云散:
error CS1501: 重載"SqlTransaction"方法未獲取"0"參數
是什么原因呢?注意到我們初始化的代碼:
SqlTransaction myTran=new SqlTransaction();
顯然,問題出在這里,事實上,SqlTransaction類并沒有公共的構造函數,我們不能這樣新建一個SqlTrancaction類型的變量。在事務處理之前確實需要有一個SqlTransaction類型的變量,將該變量關聯到SqlCommand類的Transcation屬性也是必要的,但是初始化方法卻比較特別一點。在初始化SqlTransaction類時,你需要使用SqlConnection類的BeginTranscation()方法:
SqlTransaction myTran; myTran=myConn.BeginTransaction();
該方法返回一個SqlTransaction類型的變量。在調用BeginTransaction()方法以后,所有基于該數據連接對象的SQL語句執行動作都將被認為是事務MyTran的一部分。同時,你也可以在該方法的參數中指定事務隔離級別和事務名稱,如:
SqlTransaction myTran;
myTran=myConn.BeginTransaction(IsolationLevel.ReadCommitted,"SampleTransaction");
關于隔離級別的概念我們將在隨后的內容中探討,在這里我們只需牢記一個事務是如何被啟動,并且關聯到特定的數據鏈接的。
先不要急著去搞懂我們的事務都干了些什么,看到這一行:
myTran.Commit();
是的,這就是事務的提交方式。該語句執行后,事務的所有數據庫操作將生效,并且為數據庫事務的持久性機制所保持--即使系統在這以后發生致命錯誤,該事務對數據庫的影響也不會消失。
對上面的程序做了修改之后我們可以得到如下代碼(為了節約篇幅,重復之處已省略,請參照前文):
//DoTran.cs……}
file://執行事務處理
public void DoTran()
{
file://建立連接并打開
SqlConnection myConn=GetConn();
myConn.Open();
SqlCommand myComm=new SqlCommand();
file://SqlTransaction myTran=new SqlTransaction();
file://注意,SqlTransaction類無公開的構造函數
SqlTransaction myTran;
file://創建一個事務
myTran=myConn.BeginTransaction();
try
{
file://從此開始,基于該連接的數據操作都被認為是事務的一部分
file://下面綁定連接和事務對象
myComm.Connection=myConn;
myComm.Transaction=myTran; file://定位到pubs數據庫
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();//更新數據
file://將所有的計算機類圖書
myComm.CommandText="Update roysched SET royalty = royalty * 1.10 Where title_id LIKE ''''Pc%''''";
myComm.ExecuteNonQuery();
file://提交事務
myTran.Commit();
}
catch(Exception err)
{
throw new ApplicationException("事務操作出錯,系統信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
……
到此為止,我們僅僅掌握了如何開始和提交事務。下一步我們必須考慮的是在事務中可以干什么和不可以干什么。
該文章轉載自'大智の博客':http://www.csafe.cn/article.asp?id=271