青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Error

C++博客 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
  217 Posts :: 61 Stories :: 32 Comments :: 0 Trackbacks

#

grant 權(quán)限 on 對(duì)象 to 用戶

一、grant 普通數(shù)據(jù)用戶,查詢、插入、更新、刪除 數(shù)據(jù)庫(kù)中所有表數(shù)據(jù)的權(quán)利。 
grant select on testdb.* to 
grant insert on testdb.* to 
grant update on testdb.* to 
grant delete on testdb.* to

或者,用一條 MySQL 命令來(lái)替代: 
grant select, insert, update, delete on testdb.* to

二、grant 數(shù)據(jù)庫(kù)開(kāi)發(fā)人員,創(chuàng)建表、索引、視圖、存儲(chǔ)過(guò)程、函數(shù)。。。等權(quán)限。 
grant 創(chuàng)建、修改、刪除 MySQL 數(shù)據(jù)表結(jié)構(gòu)權(quán)限。 
grant create on testdb.* to ;
grant alter  on testdb.* to ;
grant drop   on testdb.* to ;

grant 操作 MySQL 外鍵權(quán)限。 
grant references on testdb.* to ;

grant 操作 MySQL 臨時(shí)表權(quán)限。 
grant create temporary tables on testdb.* to ;

grant 操作 MySQL 索引權(quán)限。 
grant index on  testdb.* to ;

grant 操作 MySQL 視圖、查看視圖源代碼 權(quán)限。 
grant create view on testdb.* to ;
grant show   view on testdb.* to ;

grant 操作 MySQL 存儲(chǔ)過(guò)程、函數(shù) 權(quán)限。 
grant create routine on testdb.* to ;  -- now, can show procedure status
grant alter  routine on testdb.* to ;  -- now, you can drop a procedure
grant execute        on testdb.* to ;

三、grant 普通 DBA 管理某個(gè) MySQL 數(shù)據(jù)庫(kù)的權(quán)限。 
grant all privileges on testdb to

其中,關(guān)鍵字 “privileges” 可以省略。 
四、grant 高級(jí) DBA 管理 MySQL 中所有數(shù)據(jù)庫(kù)的權(quán)限。 
grant all on *.* to

五、MySQL grant 權(quán)限,分別可以作用在多個(gè)層次上。 
1. grant 作用在整個(gè) MySQL 服務(wù)器上: 
grant select on *.* to ; -- dba 可以查詢 MySQL 中所有數(shù)據(jù)庫(kù)中的表。
grant all    on *.* to ; -- dba 可以管理 MySQL 中的所有數(shù)據(jù)庫(kù)

2. grant 作用在單個(gè)數(shù)據(jù)庫(kù)上: 
grant select on testdb.* to ; -- dba 可以查詢 testdb 中的表。

3. grant 作用在單個(gè)數(shù)據(jù)表上: 
grant select, insert, update, delete on testdb.orders to ;

4. grant 作用在表中的列上: 
grant select(id, se, rank) on testdb.apache_log to ;

5. grant 作用在存儲(chǔ)過(guò)程、函數(shù)上: 
grant execute on procedure testdb.pr_add to 
grant execute on function  testdb.fn_add to

六、查看 MySQL 用戶權(quán)限 
查看當(dāng)前用戶(自己)權(quán)限: 
show grants;

查看其他 MySQL 用戶權(quán)限: 
show grants for ;

七、撤銷(xiāo)已經(jīng)賦予給 MySQL 用戶權(quán)限的權(quán)限。 
revoke 跟 grant 的語(yǔ)法差不多,只需要把關(guān)鍵字 “to” 換成 “from” 即可: 
grant  all on *.* to   ;
revoke all on *.* from ;

八、MySQL grant、revoke 用戶權(quán)限注意事項(xiàng) 
1. grant, revoke 用戶權(quán)限后,該用戶只有重新連接 MySQL 數(shù)據(jù)庫(kù),權(quán)限才能生效。 2. 如果想讓授權(quán)的用戶,也可以將這些權(quán)限 grant 給其他用戶,需要選項(xiàng) “grant option“ 
grant select on testdb.* to with grant option;

這個(gè)特性一般用不到。實(shí)際中,數(shù)據(jù)庫(kù)權(quán)限最好由 DBA 來(lái)統(tǒng)一管理。

posted @ 2014-11-14 19:29 Enic 閱讀(253) | 評(píng)論 (0)編輯 收藏

string傳值方式效率肯定是有問(wèn)題的,如果使用引用方式,則必須提供原生指針接口,否則會(huì)有異常

void Test(const std::string& strParam)
{
strParam.c_str();
}
void Test(const char* szParam)
{
}
void Test()
{
Test(nullptr);
int i = 0;
i++;
std::string strA = "---";
}
posted @ 2014-11-07 14:47 Enic 閱讀(1287) | 評(píng)論 (0)編輯 收藏

Jsp如何轉(zhuǎn)換為Servlet
jsp的底層技術(shù)是servlet,他們的生命周期是相同的。服務(wù)器負(fù)責(zé)實(shí)例化jsp/servlet,激活init()方法,準(zhǔn)備處理客戶端請(qǐng)求。可以通過(guò)編寫(xiě)service()方法處理自己的事物邏輯,或者自己編寫(xiě)doGet()、doPost()方法。服務(wù)器激活destroy()方法時(shí),jsp/servlet被銷(xiāo)毀,啟動(dòng)gc使用finalize()方法清理內(nèi)存。
jsp會(huì)被轉(zhuǎn)換到適當(dāng)?shù)膕ervlet代碼,即一個(gè).java文件。許多應(yīng)用服務(wù)器保存生成的.java文件,一旦他轉(zhuǎn)換到.java文件被編譯為字節(jié)碼.class。.class文件被支持輸出成html文檔返回給客戶端。
HttpServlet基本結(jié)構(gòu)
編寫(xiě)一個(gè)HttpServlet時(shí),通常需要許該的方法:
Void init(ServletConfig sc) throws ServletException;
Void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
Void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
Void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
html表單(form)擁有一種成為“method”屬性,用于定義如何想服務(wù)器發(fā)送數(shù)據(jù)。Get用于將數(shù)據(jù)追加入url的方式向服務(wù)器發(fā)送數(shù)據(jù)。Post用于將數(shù)據(jù)打包發(fā)送給服務(wù)器。
理解jsp應(yīng)用模型
什么是應(yīng)用模型:對(duì)jsp如何相互交互的一種描述。
1.簡(jiǎn)單模型:?jiǎn)我坏膉sp構(gòu)成。
2.N層模型:添加了類(lèi)似JavaBean的服務(wù)端資源。
3.松散耦合模型:允許位于遠(yuǎn)程系統(tǒng)的jsp做對(duì)等交互,或者擁有一種C/S關(guān)系。
通過(guò)html或者xml的http通訊,每個(gè)jsp應(yīng)用都與其他jsp應(yīng)用保存隔離。
4.包含請(qǐng)求模型:一個(gè)jsp可以負(fù)責(zé)請(qǐng)求和響應(yīng),但是包含其他jsp的輸出。通過(guò)include行為實(shí)現(xiàn)。
5.轉(zhuǎn)發(fā)請(qǐng)求模型:重定向,通過(guò)forward行為實(shí)現(xiàn)。
理解Jsp的布局
標(biāo)簽可以是html標(biāo)簽,也可以是jsp標(biāo)簽。
jsp標(biāo)簽可以有作用域 <jsp: useBean name="myClass" class="SimpleClass" scope="page" />
注釋:
1.html:<!-- -->
2.jsp: <%-- --%>
3.java: // or /**/
jsp解剖:
html代碼----負(fù)責(zé)頁(yè)面整個(gè)布局和外觀
jsp標(biāo)簽----負(fù)責(zé)scriptlet、表達(dá)式、聲明、行為和指令
jsp隱式對(duì)象----例如:request對(duì)象、response對(duì)象、session對(duì)象、config對(duì)象
JavaBean----實(shí)現(xiàn)事物邏輯
理解jsp標(biāo)簽元素
jsp有兩種形式:<%%>、<jsp:tagid/>
1.jsp聲明標(biāo)簽用法:(定義變量)
<%!
declaration_statement(s)
%>
<jsp:declaration>
</jsp:declaration>
2.jsp表達(dá)式標(biāo)簽用法:(引用變量)
<%=expression%>
<jsp: expression> expression </jsp: expression>
3.jsp scriptlet標(biāo)簽用法:(編寫(xiě)java代碼,差不多就是用標(biāo)簽把java代碼包起來(lái),標(biāo)簽會(huì)截?cái)鄻?biāo)簽)
<% 
boolean isPasswordAnyGood(String password)
{
return false;
}
%>
<%
if(isPasswordAnyGood("123"))
{
%>
<H1>Welcome<H1/>
<%
}
else
{
%>
<H1>Press Login</H1>
<%
}
%>
4.jsp指令標(biāo)簽:(預(yù)處理命令之類(lèi))
<%@ page import="com.macmilan.jspln24.*" %>
5.jsp行為標(biāo)簽(允許jsp使用java創(chuàng)建對(duì)象,包含jsp,轉(zhuǎn)發(fā)jsp,java交互)
六種:useBean setProperty getProperty include forward plugin
Jsp內(nèi)置對(duì)象用法:
內(nèi)置對(duì)象提供來(lái)自瀏覽器的請(qǐng)求并且動(dòng)態(tài)響應(yīng)的功能:
request out response pageContext session application config page
JavaBean規(guī)范(這是個(gè)大議題,據(jù)說(shuō)有兩種用法,一種可以直接無(wú)視,把javabean當(dāng)不同java類(lèi)在jsp中導(dǎo)入來(lái)用。一種是遵循javabean規(guī)范使用標(biāo)簽來(lái)訪問(wèn))
7
posted @ 2014-11-04 16:25 Enic 閱讀(186) | 評(píng)論 (0)編輯 收藏

首先一個(gè)原則是這樣:被用來(lái)delete的指針,一定是new出來(lái)的。
在設(shè)計(jì)智能指針的時(shí)候發(fā)現(xiàn),如果采用delete this機(jī)制,到最后可能會(huì)有嚴(yán)重的問(wèn)題。
假設(shè)有這樣的多重繼承:
class CA{};
class CB{};
class CC{};
class CABC : public CA, public CB, public CC
{};
CABC* pAbc = new CABC;
CA* pA = pAbc;
CB* pB = pAbc;
CC* pC = pAbc;
A B C指針的值都是不一樣的,如果是簡(jiǎn)單的使用delete 來(lái)刪除,問(wèn)題就大條了,pB pC的地址和new出來(lái)的pAbc不一樣,這樣就出現(xiàn)堆錯(cuò)誤。
如果設(shè)計(jì)入侵式RefObj問(wèn)題就大條了:
class Ref
{
public:
virtual void Test()
{
std::cout << this << std::endl;
}
int m_i;
};
class CA : public virtual Ref{};
class CB : public virtual Ref{};
class CC : public virtual Ref{};
class CABC : public CA, public CB, public CC{};
         C* pAbc = new CABC;
CA* pA = pAbc;
CB* pB = pAbc;
CC* pC = pAbc;
通過(guò)打印可以看到,雖然ABC 在基類(lèi)Test打印出來(lái)的this地址一致,但是和實(shí)際正確的delete指針(new出來(lái)的)是不一致的,這就準(zhǔn)備堆錯(cuò)誤了,,,
這基本意味著使用入侵式樣Ref的類(lèi),使用了多重繼承就是作死。除非和com的思想一樣,Ref不是作為基類(lèi)處理,而是作為純虛接口,但是又會(huì)使得編碼復(fù)雜化,基本上全部要用組合來(lái)替代繼承
class IXXX;
class CXXX;
class IYYY;
class CYYYXXX : public CXXX, public IYYY;
這樣的用法無(wú)法實(shí)現(xiàn),應(yīng)為沒(méi)有實(shí)現(xiàn)IXXX接口,是一個(gè)虛基類(lèi),實(shí)現(xiàn)了在調(diào)用的時(shí)候也是各種基類(lèi)未指定的錯(cuò)誤。

奇怪的是shared_ptr沒(méi)有這個(gè)限制,猜測(cè)是在第一次從裸指針構(gòu)造出來(lái)的時(shí)候,保留了原始地址,生成了一個(gè)析構(gòu)函數(shù),會(huì)在shared_ptr之間共享,直到最后一個(gè)對(duì)象析構(gòu)的時(shí)候調(diào)用.
實(shí)際觀察std::shared_ptr的實(shí)現(xiàn),發(fā)現(xiàn)其構(gòu)造函數(shù)不是控制一定要轉(zhuǎn)換成T指定的類(lèi)型,而是給入?yún)?shù)的實(shí)際類(lèi)型,后面的管理也分兩個(gè)部分,一層得到根據(jù)T轉(zhuǎn)換后的值,實(shí)際的生命周期管理得到仍然是實(shí)際類(lèi)型,所以他delete的時(shí)候還是當(dāng)初給定的值。
所以,感覺(jué)智能指針不是什么好東西,背后的細(xì)節(jié)太多,一個(gè)不小心就死翹翹



class RefObj
{
public:
RefObj() : m_i(0){}
public:
void Increate(){m_i++;}
void Decreate()
{
if(0 == --m_i)
{
delete this;
}
}
private: 
int m_i;
};
class BaseA : public virtual RefObj {public: int m_iA;};
class BaseB : public virtual RefObj {public: int m_iB;};
class BaseC : public virtual RefObj {public: int m_iC;};
class CBaseABC : public BaseA,
public BaseB,
public BaseC
{
};
void Test(BaseB* pB)
{
pB->Decreate();
}
int _tmain(int argc, _TCHAR* argv[])
{
ETcpSocket tcpSocket;
CBaseABC* pABC = new CBaseABC;
pABC->Increate();
BaseB* pB = pABC;
Test(pB);
return 0;
}



始終還是覺(jué)得相比shared_ptr,RefObj這種,還是有部分場(chǎng)景更加格式,至少不用擔(dān)心類(lèi)型轉(zhuǎn)換變得異常麻煩,,,
后發(fā)現(xiàn)如下實(shí)現(xiàn)方式:
class IRefObj
{
public:
virtual void __DecRef() = 0;
};
template<typename TType>
class TRefObj : public IRefObj
{
public:
void __DecRef()
{
delete reinterpret_cast<TType*>(this);
}
};
class CRefTest : public TRefObj<CRefTest>
{
};
class CRefTestA : public CRefTest
{
};
class CTestA {int i;};
class CTestB {int j;};
class CTestC : public CTestB, public CRefTestA, public  CTestA
{
};
int _tmain(int argc, _TCHAR* argv[])
{
CTestC* pTC = new CTestC;
CTestB* pTB = pTC;
CRefTestA* pRTA = pTC;
CTestA* pTA = pTC;
pRTA->__DecRef();

這個(gè)時(shí)候CRefTest是預(yù)期額值,懷疑可能和編譯器有關(guān),VS測(cè)試OK,gcc沒(méi)去實(shí)驗(yàn)。
分析了一下原因:C++保證單根繼承的時(shí)候基類(lèi)和派生類(lèi)地址是一樣的,如果是多重繼承,那么也保證和最深的根父類(lèi)地址樣,順便的,從最深的根節(jié)點(diǎn),選一路下來(lái)是安全的。
class CRefTest : public TRefObj<CRefTest>所以約定TRefObj<CRefTest>這玩意和永遠(yuǎn)和接口在一個(gè)級(jí)別,可以保證IRefObj永遠(yuǎn)是最深的根,就安全了?
目前只在控件設(shè)計(jì)的時(shí)候用RefObj吧,,,坑的比較深,,,
posted @ 2014-10-16 16:29 Enic 閱讀(781) | 評(píng)論 (2)編輯 收藏

技術(shù)路線的選擇重要但不具有決定性(轉(zhuǎn)載)

轉(zhuǎn)自 http://blog.csdn.net/myan/article/details/3247071  
 
孟巖 2008 年的文章,現(xiàn)在看來(lái)還是挺有啟發(fā), 送給大家,也送給自己。

最近微軟在技術(shù)上連續(xù)有大動(dòng)作,在PDC上發(fā)布了Windows Azure云計(jì)算平臺(tái),預(yù)告了Visual Studio 2010、.NET 4.0和C# 4.0。如果放在幾年前,我相信微軟粉絲們一定是歡聲雷動(dòng),不過(guò)這次情況有點(diǎn)不太一樣,在網(wǎng)上看到有人在抱怨微軟技術(shù)更新速度太快而且四面出擊,還有人揚(yáng)言要改弦更張,投奔Linux或者Java陣營(yíng)。我本人也收到一封來(lái)信,寫(xiě)信人大意是說(shuō)自己大學(xué)時(shí)選擇.NET路線,一路跟下來(lái)很辛苦,2.0還沒(méi)學(xué)好,人家已經(jīng)4.0預(yù)覽了,感到很困惑,問(wèn)我該怎么辦。老實(shí)講,這樣的問(wèn)題我無(wú)法回答,每個(gè)人具體情況不同,所應(yīng)該采取的態(tài)度和解決方案也不同。從我自己來(lái)講,其實(shí)技術(shù)路線問(wèn)題也曾長(zhǎng)時(shí)間地困擾我,所以我想把我現(xiàn)在的一些想法攤出來(lái)跟大家分享一下。羅列如下:

1. 根據(jù)我長(zhǎng)期的觀察,做開(kāi)發(fā)技術(shù)的人按照其人生路線設(shè)計(jì),可以分成幾類(lèi)。第一類(lèi)是把自己的命運(yùn)寄托在一項(xiàng)事業(yè)上。這樣的人知道自己想干什么,而且有能力把技術(shù)當(dāng)工具來(lái)實(shí)現(xiàn)自己的想法和事業(yè)。這里所說(shuō)的事業(yè)是廣義的,并不是說(shuō)你非要自己開(kāi)公司當(dāng)老板,而是說(shuō)你認(rèn)可一件事情,比如促進(jìn)人們交流和言論自由,帶給大家更多娛樂(lè),提升大眾身心健康水平,增強(qiáng)國(guó)家國(guó)防實(shí)力,或者提升某個(gè)行業(yè)的信息化水平,然后你能夠以技術(shù)為手段,在這個(gè)事情上做出成績(jī)。這種人做著自己認(rèn)為值得一生投入的事情,愿意領(lǐng)略這一追求帶來(lái)的人生起伏并且無(wú)怨無(wú)悔,我認(rèn)為這是做技術(shù)的最高層次。第二類(lèi)是把自己的命運(yùn)寄托在組織和團(tuán)隊(duì)上。這種人雖然不知道自己到底想干什么,但是技術(shù)水平出色,而且綜合素質(zhì)突出,勇于變化,能夠把技術(shù)當(dāng)敲門(mén)磚進(jìn)入某個(gè)優(yōu)秀的團(tuán)隊(duì),以團(tuán)隊(duì)的目標(biāo)為目標(biāo),依據(jù)團(tuán)隊(duì)的需求而轉(zhuǎn)型或者堅(jiān)持,跟團(tuán)隊(duì)一起干出一番成績(jī)。這類(lèi)人有令人羨慕的職業(yè)背景,在大公司里高薪厚祿,生活比較安定舒適,但是中年以后會(huì)經(jīng)常自問(wèn)到底做了什么自己想做的事情為自己過(guò)于風(fēng)平浪靜的人生感到惆悵。但總的來(lái)說(shuō),這個(gè)層次也是比較高的。第三種是把命運(yùn)寄托在技術(shù)上。這種人有能力成為技術(shù)的專家,然后就希望奇貨可居,待價(jià)而沽,把技能當(dāng)商品出售謀求富足人生。這種人沒(méi)有大的人生目標(biāo),不想把自己的命運(yùn)跟企業(yè)和組織綁定在一起,也不愿意做什么改變,只是滿足于技術(shù)高手的層面,寄希望于其技術(shù)專長(zhǎng)能夠長(zhǎng)期值錢(qián),有點(diǎn)投機(jī)主義者的意思。第四種是還處于出賣(mài)勞動(dòng)力的階段,在這里就不多說(shuō)了。

我想說(shuō)的是,在過(guò)去很多年里,很多技術(shù)人實(shí)際上是把自己定位在第三種人里。而實(shí)際上,只有成為第一類(lèi)和第二類(lèi)人,才算達(dá)到了比較成功的狀態(tài)。第三類(lèi)人實(shí)際上最危險(xiǎn),因?yàn)榧夹g(shù)的變遷不但是可能的,而且是一定的。他們要么馬上被淘汰,要么追得老了累了追不動(dòng)了以后被淘汰,被淘汰只是時(shí)間問(wèn)題。 因此,如果你認(rèn)為某個(gè)軟件技術(shù)的興起或者衰落對(duì)你個(gè)人的職業(yè)生涯構(gòu)成了決定性的影響,那么你可能正走在錯(cuò)誤的路線上,應(yīng)當(dāng)盡快改弦更張。

2. 對(duì)個(gè)體軟件人來(lái)說(shuō),什么是核心競(jìng)爭(zhēng)力?不是時(shí)間差,不是技術(shù),不是基本功,不是什么思想,也不是聰明腦瓜,而是你獨(dú)特的個(gè)性知識(shí)經(jīng)驗(yàn)組合。

有人看到新技術(shù)出來(lái)了,急急忙忙趕上去嘗鮮,以為自己快人一步,就能如何如何,實(shí)際上這種想法根本不靠譜,最多在論壇博客上風(fēng)光兩天,等這項(xiàng)技術(shù)投入實(shí)際應(yīng)用以后一點(diǎn)便宜也占不到。

有人把某個(gè)技術(shù)、框架、平臺(tái)研究得里外通透,以為這樣就能奇貨可居。實(shí)踐中,這種人能紅火一時(shí),但很難超過(guò)5年。這是現(xiàn)階段技術(shù)發(fā)展生命周期所決定的。此外,現(xiàn)在越來(lái)越多人意識(shí)到了,能夠靠讀書(shū)看文章讀代碼做練習(xí)學(xué)會(huì)的東西沒(méi)什么門(mén)檻,智力正常的人只要愿意花功夫,都不難達(dá)到你的程度。有的人認(rèn)為,自己有能力駕馭技術(shù)潮流,哪個(gè)紅學(xué)哪個(gè)。我在技術(shù)行業(yè)里不敢說(shuō)閱人無(wú)數(shù),見(jiàn)過(guò)的高手上百是有的,說(shuō)句不怕得罪人的話,能夠連續(xù)抓住兩個(gè)以上的潮流并且始終處于領(lǐng)先位置的人及其少見(jiàn),一只手就數(shù)的過(guò)來(lái)。更常見(jiàn)的情況是,上一個(gè)階段的成功會(huì)成為下一個(gè)階段的障礙,所謂隨機(jī)應(yīng)變屹立潮頭之說(shuō),往往只不過(guò)是當(dāng)紅小生給自己壯膽的狂言,時(shí)過(guò)境遷之后,他就只能聽(tīng)著新一代當(dāng)紅小生的豪言壯語(yǔ)而默默苦笑。

有人強(qiáng)調(diào)基本功,這是對(duì)的。在任何技術(shù)性行業(yè)里都一樣,基礎(chǔ)打得多深,上面就能造得多高。現(xiàn)實(shí)中,基本功扎實(shí)的人很少見(jiàn),這跟中國(guó)教育的弊病有關(guān),所以基本功好的人,一般應(yīng)變能力強(qiáng),學(xué)習(xí)速度快,比較受歡迎。但說(shuō)基本功是核心競(jìng)爭(zhēng)力,還是沒(méi)有抓住本質(zhì)。我們經(jīng)常能看到基本功差不多的兩個(gè)人,一個(gè)發(fā)展的很好,一個(gè)發(fā)展平平,這表明基本功成功職業(yè)生涯的是重要條件,但不是決定因素。

有人強(qiáng)調(diào)這個(gè)那個(gè)思想,實(shí)際上軟件行業(yè)里的偉大的思想就那么屈指可數(shù)的幾個(gè),窗戶紙一點(diǎn)就破,其他衍生出來(lái)的思想,就跟技術(shù)風(fēng)潮一樣,各領(lǐng)風(fēng)騷三五年,成不了你核心競(jìng)爭(zhēng)力。

還有人強(qiáng)調(diào)自己的智商,聰明腦瓜,覺(jué)得自己比別人聰明,自己的聰明是核心競(jìng)爭(zhēng)力。大學(xué)生、剛畢業(yè)的人持這個(gè)觀點(diǎn)的比較多,然而有過(guò)人生閱歷以后,自然會(huì)對(duì)這種觀點(diǎn)不以為然。本質(zhì)上這是因?yàn)樯鐣?huì)對(duì)于“聰明”的定義與學(xué)校不同,一個(gè)解題高手在學(xué)校里可能是受人仰慕的聰明腦瓜,但在職業(yè)人生中則可能是個(gè)大傻蛋。我們身邊很多人走了一條不盡如意的人生道路,往往不是因?yàn)樗麄儾粔?#8220;聰明”,而是因?yàn)樗麄兲?#8220;聰明”了,聰明反被聰明誤。我想這也是為什么人們要發(fā)明“智慧”這個(gè)詞以區(qū)別于“聰明”的原因。另外,關(guān)于這種觀點(diǎn),還有一點(diǎn)不得不指出,那就是在軟件這個(gè)行當(dāng)里,一般聰明就可以了,絕頂聰明占不到多少便宜。

那么核心競(jìng)爭(zhēng)力是什么?我觀察圈子里很多成功和不成功的技術(shù)人,提出一個(gè)觀點(diǎn),那就是個(gè)人的核心競(jìng)爭(zhēng)力是是他獨(dú)特的個(gè)性知識(shí)經(jīng)驗(yàn)組合。這個(gè)行業(yè)里擁擠著上百萬(wàn)聰明人,彼此之間真正的不同在哪里?不在于你學(xué)的是什么技術(shù),學(xué)得多深,IQ多少,而在于你身上有別人沒(méi)有的獨(dú)特的個(gè)性、背景、知識(shí)和經(jīng)驗(yàn)的組合。如果這種組合,1,絕無(wú)僅有;2,在實(shí)踐中有價(jià)值,3,具有可持續(xù)發(fā)展性,那你就具備核心競(jìng)爭(zhēng)力。因此,當(dāng)設(shè)計(jì)自己的發(fā)展路線時(shí),應(yīng)當(dāng)最大限度地加強(qiáng)和發(fā)揮自己獨(dú)特的組合,而不是尋求單項(xiàng)的超越。而構(gòu)建自己獨(dú)特組合的方式,主要是通過(guò)實(shí)踐,其次是要有意識(shí)地構(gòu)造。關(guān)于這個(gè)觀點(diǎn),話題太大,我不打算贅述。

3. 雖然技術(shù)路線的選擇不是核心競(jìng)爭(zhēng)力,也不應(yīng)該具有決定性,但對(duì)于個(gè)人職業(yè)路線還是具有比較重要的影響力。但這并不是說(shuō),我們應(yīng)該煞有介事地把自己歸于Java或者.NET技術(shù)陣營(yíng),整天捧本書(shū)吭哧吭哧啃。正確的態(tài)度應(yīng)該是著重于你要干的事情,然后認(rèn)真把這件事情做好,通過(guò)必要的學(xué)習(xí)將所需的知識(shí)體系構(gòu)筑完整,在整個(gè)過(guò)程中及時(shí)更新知識(shí)體系。只有心理沒(méi)譜的人,才會(huì)為新技術(shù)的推出感到惶恐,因?yàn)樗恢雷约阂墒裁矗簿筒恢雷约阂獙W(xué)什么,看到什么東西出來(lái)了都以為如果不學(xué)就會(huì)落伍,才會(huì)覺(jué)得是個(gè)壓力,日積月累,才會(huì)痛苦彷徨嚷嚷怎么辦。相反,如果你很清楚地知道自己要做什么,就會(huì)發(fā)現(xiàn),其實(shí)必須及時(shí)更新的知識(shí)變化并不頻繁,大多數(shù)新鮮玩意根本不在自己關(guān)注范圍內(nèi),任他三仙落地,五佛升天,與我何干?因此完全可以安步當(dāng)車(chē),穩(wěn)扎穩(wěn)打。

4. 幾年前我剛加入CSDN的時(shí)候,.NET和Java之爭(zhēng)是最熱門(mén)的話題。現(xiàn)在回過(guò)頭看,其實(shí)當(dāng)時(shí)無(wú)論你選擇那條路,如果認(rèn)真做下去,搞些實(shí)事,別玩虛活的話,現(xiàn)在都應(yīng)該有成就了。當(dāng)然,客觀上來(lái)說(shuō),這幾年微軟技術(shù)變化是比較快,彎彎繞得比較多,相比之下,如果當(dāng)時(shí)你選擇的是Java,可能這幾年過(guò)的比較幸福一些,這是事實(shí)。我對(duì)此并不是沒(méi)有自己的看法,但是這畢竟不是多么大的問(wèn)題,實(shí)際上Java這幾年折騰得也夠猛,只不過(guò)作為一個(gè)比較開(kāi)放的領(lǐng)域,Java為其追隨者保留了更多的自由度,而微軟的追隨者大多數(shù)有一種被驅(qū)趕的感覺(jué)而已。話說(shuō)回來(lái), 微軟的技術(shù)變革并不是沒(méi)有章法的,其今天的技術(shù)架構(gòu),早在2003年就已經(jīng)明明白白地公諸于眾,只不過(guò)因?yàn)槟承┪⒚畹脑颍恍┪④浉S者這幾年被帶著兜了一些圈子,浪費(fèi)了一些精力,比較辛苦。不過(guò),現(xiàn)在.NET技術(shù)體系的塵埃基本落定,從體系結(jié)構(gòu)上看,相對(duì)穩(wěn)定的時(shí)期已經(jīng)到來(lái),投資微軟技術(shù)可以放心。

5. 不過(guò)我相信未來(lái)不同技術(shù)流的應(yīng)用領(lǐng)域會(huì)出現(xiàn)一些明顯的分化。在中國(guó),涉及國(guó)防、國(guó)家安全、命脈產(chǎn)業(yè)和關(guān)鍵行業(yè)的服務(wù)端要害系統(tǒng),國(guó)產(chǎn)化改造是阻擋不住的潮流,長(zhǎng)期來(lái)看,開(kāi)源和Java將在這個(gè)領(lǐng)域占據(jù)主導(dǎo)低位。其他的領(lǐng)域,隨著微軟技術(shù)變革的的大勢(shì)確定,相信微軟的優(yōu)勢(shì)不可小覷。這里沒(méi)有考慮中國(guó)政府可能做出的產(chǎn)業(yè)調(diào)整政策。這次微軟黑屏事件,無(wú)論是否出于微軟本意,其最大的效果在于向有關(guān)部門(mén)展示了一下其信息戰(zhàn)力,中國(guó)政軍內(nèi)部有關(guān)機(jī)構(gòu)對(duì)此不可能不加以警惕,這是否會(huì)引起中國(guó)國(guó)內(nèi)IT產(chǎn)業(yè)政策的調(diào)整,現(xiàn)在還不得而知。但我相信,微軟系統(tǒng)恐怕將在不長(zhǎng)的時(shí)間里與中國(guó)關(guān)鍵要害領(lǐng)域的核心系統(tǒng)徹底說(shuō)拜拜。未來(lái)中國(guó)IT系統(tǒng)的格局,很有可能是居廟堂之高則清一色Linux/Java,處江湖之遠(yuǎn)則Windows占主導(dǎo)。

6. 幾年前還有一個(gè)熱烈爭(zhēng)論,就是Java和C#之爭(zhēng)。現(xiàn)在實(shí)際上塵埃已經(jīng)落定,兩個(gè)語(yǔ)言的定位已經(jīng)分道揚(yáng)鑣。Java實(shí)際上已經(jīng)落實(shí)了成為系統(tǒng)語(yǔ)言的諾言,在現(xiàn)在的計(jì)算機(jī)體系結(jié)構(gòu)上,Java與15年前的C一樣,可以成為構(gòu)造基礎(chǔ)設(shè)施的利器,而且其性能相當(dāng)不錯(cuò),完全突破了之前人們對(duì)虛擬機(jī)語(yǔ)言的認(rèn)識(shí)局限性。我相信在未來(lái),Java將有效地侵蝕C語(yǔ)言的一些曾經(jīng)以為千秋萬(wàn)代永不變色的地盤(pán)。雖然同時(shí)Java也在向上發(fā)展,但是其力度與C#不可同日而語(yǔ)。相反,C#主要是在往上發(fā)展,即將成為超級(jí)瑞士軍刀,微軟版十全大補(bǔ)膏,所有于應(yīng)用開(kāi)發(fā)有意義的特性都要加上,從編程語(yǔ)言發(fā)展來(lái)看,它將成為一株奇葩。作為一個(gè)編程語(yǔ)言的愛(ài)好者,我正饒有興致地注視著史上特性最豐富語(yǔ)言C#的發(fā)展動(dòng)向。但是,不得不指出,C#的弱點(diǎn)在腳跟。自從用它開(kāi)發(fā)Longhorn Avalon失敗以后,微軟暫時(shí)放棄了讓C#成為系統(tǒng)語(yǔ)言的努力,專心專意讓C#變成應(yīng)用開(kāi)發(fā)領(lǐng)域的超級(jí)無(wú)敵霸王3000,而在核心領(lǐng)域,仍然是C++、COM當(dāng)關(guān)。這就出現(xiàn)了有趣的局面,在可見(jiàn)的未來(lái),微軟體系內(nèi)真正的核心軟件基礎(chǔ)設(shè)施,還是將由微軟自己用C++來(lái)構(gòu)造,而組合裝配的應(yīng)用開(kāi)發(fā),則由C#完成。VB和CLR平臺(tái)上的其他動(dòng)態(tài)語(yǔ)言都不會(huì)有太多機(jī)會(huì),因?yàn)镃#將窮盡神智正常者一切關(guān)于語(yǔ)言的幻想。

以上幾點(diǎn),如果有人現(xiàn)在要選擇技術(shù)路線,可以參考一下。但切記,技術(shù)路線的選擇重要,但不具有決定意義。

posted @ 2014-10-14 10:16 Enic 閱讀(228) | 評(píng)論 (0)編輯 收藏

基于WinDbg的內(nèi)存泄漏分析
在前面C++中基于Crt的內(nèi)存泄漏檢測(cè)一文中提到的方法已經(jīng)可以解決我們的大部分內(nèi)存泄露問(wèn)題了,但是該方法是有前提的,那就是一定要有源代碼,而且還只能是Debug版本調(diào)試模式下。實(shí)際上很多時(shí)候我們的程序會(huì)用到第三方?jīng)]有源代碼的模塊,有些情況下我們甚至懷疑系統(tǒng)模塊有內(nèi)存泄露,但是有沒(méi)有證據(jù),我們?cè)撛趺崔k? 這時(shí)我們就要依靠無(wú)所不能的WinDbg了。

WinDbg的!heap命令非常強(qiáng)大,結(jié)合AppVerifier可以對(duì)堆(heap)內(nèi)存進(jìn)行詳細(xì)的跟蹤和分析, 我們接下來(lái)對(duì)下面的代碼進(jìn)行內(nèi)存泄漏的分析:
// MemLeakTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    char* p1 = new char;
    printf("%p\n", p1);

    char* pLargeMem = new char[40000];

    for(int i=0; i<1000; ++i)
    {
        char* p = new char[20];
    }
    
    system("pause");

    return 0;
}

首先下載安裝AppVerifier, 可到這里下載, 把我們需要測(cè)試的程序添加到AppVerifier的檢測(cè)列表中, 然后保存。

注: 我們這里用AppVerifier主要是為了打開(kāi)頁(yè)堆(page heap)調(diào)試功能,你也可以用系統(tǒng)工具 gflags.exe 來(lái)做同樣的事。 

雙擊運(yùn)行我們要調(diào)試的MemLeakTest.exe, 效果如下:


然后將WinDbg Attach上去, 輸入命令 !heap -p -a 0x02FC1FF8,結(jié)果如下:
0:001> !heap -p -a 0x02FC1FF8
    address 02fc1ff8 found in
    _DPH_HEAP_ROOT @ 2f01000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 2f02548:          2fc1ff8                1 -          2fc1000             2000
    5a8c8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77485c4e ntdll!RtlDebugAllocateHeap+0x00000030
    77447e5e ntdll!RtlpAllocateHeap+0x000000c4
    774134df ntdll!RtlAllocateHeap+0x0000023a
    5b06a65d vrfcore!VfCoreRtlAllocateHeap+0x00000016
    5a92f9ea vfbasics!AVrfpRtlAllocateHeap+0x000000e2
    72893db8 MSVCR90!malloc+0x00000079
    72893eb8 MSVCR90!operator new+0x0000001f
    012c1008 MemLeakTest!wmain+0x00000008 [f:\test\memleaktest\memleaktest\memleaktest.cpp @ 11]
    77331114 kernel32!BaseThreadInitThunk+0x0000000e
    7741b429 ntdll!__RtlUserThreadStart+0x00000070
    7741b3fc ntdll!_RtlUserThreadStart+0x0000001b

怎么樣, 神奇吧?我們當(dāng)分配該地址內(nèi)存時(shí)的堆棧(stack)被完整地打印了出來(lái)。

當(dāng)然有人很快會(huì)說(shuō):這是你知道內(nèi)存地址的情況, 很多情況下我們是不知道該地址的,該如何分析?

對(duì)于這種情況, 我們首先需要明確一些概念, 我們new出來(lái)的內(nèi)存是分配在堆上, 那一個(gè)進(jìn)程里究竟有多少個(gè)堆, 每個(gè)模塊都有自己?jiǎn)为?dú)的堆嗎?實(shí)際上一個(gè)進(jìn)程可以有任意多個(gè)堆,我們可以通過(guò)CreateHeap創(chuàng)建自己?jiǎn)为?dú)的堆, 然后通過(guò)HeapAlloc分配內(nèi)存。 我們new出來(lái)的內(nèi)存是crt(C運(yùn)行庫(kù))分配的, 那就涉及到crt究竟有多少個(gè)堆了? crt有多少個(gè)堆由你編譯每個(gè)模塊(Dll/Exe)時(shí)的編譯選項(xiàng)決定, 如果你運(yùn)行庫(kù)選項(xiàng)用的是/MD, 那就和其他模塊共享一個(gè)堆; 如果用/MT, 那就是自己?jiǎn)为?dú)的堆。大部分情況下我們會(huì)用/MD,這樣我們?cè)谝粋€(gè)模塊里new內(nèi)存, 另一個(gè)模塊里delete不會(huì)有問(wèn)題, 因?yàn)榇蠹夜蚕硪粋€(gè)堆。

明確這些概念之后, 我們看看我們的測(cè)試程序有多少個(gè)堆, 輸入!heap -p
0:001> !heap -p

    Active GlobalFlag bits:
        vrf - Enable application verifier
        hpa - Place heap allocations at ends of pages

    StackTraceDataBase @ 00160000 of size 01000000 with 00000034 traces

    PageHeap enabled with options:
        ENABLE_PAGE_HEAP
        COLLECT_STACK_TRACES

    active heaps:

    + 1160000
        ENABLE_PAGE_HEAP COLLECT_STACK_TRACES 
      NormalHeap - 1300000
          HEAP_GROWABLE 
    + 1400000
        ENABLE_PAGE_HEAP COLLECT_STACK_TRACES 
      NormalHeap - 16b0000
          HEAP_GROWABLE HEAP_CLASS_1 
    + 2360000
        ENABLE_PAGE_HEAP COLLECT_STACK_TRACES 
      NormalHeap - 1280000
          HEAP_GROWABLE HEAP_CLASS_1 
    + 2f00000
        ENABLE_PAGE_HEAP COLLECT_STACK_TRACES 
      NormalHeap - 31d0000
          HEAP_GROWABLE HEAP_CLASS_1 
可以看到我們的測(cè)試程序一共有4 個(gè)堆。

接下來(lái)我們的問(wèn)題就是確定哪個(gè)是我們的crt堆, 也就是我們需要分析每個(gè)堆創(chuàng)建時(shí)的堆棧(stack)情況.

我們接下來(lái)分析最后一個(gè)堆, handle是2f00000, 輸入!heap -p -h 02f00000 分析該堆的內(nèi)存分配情況
0:001> !heap -p -h 02f00000
    _DPH_HEAP_ROOT @ 2f01000
    Freed and decommitted blocks
      DPH_HEAP_BLOCK : VirtAddr VirtSize
        02f01f04 : 02f09000 00002000
        02f02e38 : 02f69000 00002000
        037e2548 : 03892000 00002000
        037e2514 : 03894000 00002000
    Busy allocations
      DPH_HEAP_BLOCK : UserAddr  UserSize - VirtAddr VirtSize
        02f01f6c : 02f05de8 00000214 - 02f05000 00002000
        02f01f38 : 02f07800 00000800 - 02f07000 00002000
        02f01ed0 : 02f0bde0 00000220 - 02f0b000 00002000
        02f01e9c : 02f0df50 000000ac - 02f0d000 00002000
        02f01e68 : 02f0ffe0 0000001f - 02f0f000 00002000
        02f01e34 : 02f11fd8 00000028 - 02f11000 00002000
        02f01e00 : 02f13fe0 0000001d - 02f13000 00002000
        02f01dcc : 02f15fc0 0000003a - 02f15000 00002000
        ....

可以看到該堆 _DPH_HEAP_ROOT 結(jié)構(gòu)的地址是 2f01000,通過(guò)dt命令打印該結(jié)構(gòu)地址
0:001> dt ntdll!_DPH_HEAP_ROOT CreateStackTrace 2f01000
   +0x0b8 CreateStackTrace : 0x0017cbe4 _RTL_TRACE_BLOCK

可以看到StackTrace的地址是 0x0017cbe4, 通過(guò)dds命令打印該地址內(nèi)的符號(hào)
0:001> dds 0x0017cbe4 
0017cbe4  00178714
0017cbe8  00007001
0017cbec  000f0000
0017cbf0  5a8c8969 verifier!AVrfDebugPageHeapCreate+0x439
0017cbf4  7743a9e8 ntdll!RtlCreateHeap+0x41
0017cbf8  5a930109 vfbasics!AVrfpRtlCreateHeap+0x56
0017cbfc  755fdda2 KERNELBASE!HeapCreate+0x55
0017cc00  72893a4a MSVCR90!_heap_init+0x1b
0017cc04  72852bb4 MSVCR90!__p__tzname+0x2a
0017cc08  72852d5e MSVCR90!_CRTDLL_INIT+0x1e
0017cc0c  5a8dc66d verifier!AVrfpStandardDllEntryPointRoutine+0x99
0017cc10  5b069164 vrfcore!VfCoreStandardDllEntryPointRoutine+0x121
0017cc14  5a92689c vfbasics!AVrfpStandardDllEntryPointRoutine+0x9f
0017cc18  7741af58 ntdll!LdrpCallInitRoutine+0x14
0017cc1c  7741fd6f ntdll!LdrpRunInitializeRoutines+0x26f
0017cc20  774290c6 ntdll!LdrpInitializeProcess+0x137e
0017cc24  77428fc8 ntdll!_LdrpInitialize+0x78
0017cc28  7741b2f9 ntdll!LdrInitializeThunk+0x10
0017cc2c  00000000
0017cc30  00009001

現(xiàn)在我們可以看到該堆被Create時(shí)的完整堆棧了, 通過(guò)堆棧,我們可以看到該堆正是由crt創(chuàng)建的, 也就是說(shuō)我們new的內(nèi)存都分配在該堆內(nèi)。

如果你覺(jué)得上面跟蹤堆創(chuàng)建的過(guò)程太復(fù)雜,可以先忽略, 下面我們分析堆狀態(tài), 輸入!heap -stat -h 0,它會(huì)分析所有堆的當(dāng)前使用狀態(tài), 我們著重關(guān)注我們的crt堆02f00000:
Allocations statistics for
 heap @ 02f00000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    9c40 1 - 9c40  (52.66)
    14 3ea - 4e48  (26.38)
    1000 1 - 1000  (5.39)
    800 2 - 1000  (5.39)
    490 1 - 490  (1.54)
    248 1 - 248  (0.77)
    220 1 - 220  (0.72)
    214 1 - 214  (0.70)
    ac 2 - 158  (0.45)
    82 2 - 104  (0.34)
    6a 2 - d4  (0.28)
    50 2 - a0  (0.21)
    28 4 - a0  (0.21)
    98 1 - 98  (0.20)
    94 1 - 94  (0.19)
    8a 1 - 8a  (0.18)
    2e 3 - 8a  (0.18)
    41 2 - 82  (0.17)
    80 1 - 80  (0.17)
    7c 1 - 7c  (0.16)

我們可以看到排在第一位的是大小為0x9c40 (0n40000)的內(nèi)存,分配了1次, 第二位的是大小為 0x14 (0n20) 的內(nèi)存,分配了3ea (0n1002)次.
 回頭再看我們的測(cè)試程序,怎么樣? 是不是感覺(jué)很熟悉了。

輸入!heap -flt s 0x9c40, 讓W(xué)inDbg列出所有大小為0x9c40的內(nèi)存:
0:001> !heap -flt s 0x9c40
    _DPH_HEAP_ROOT @ 1161000
    Freed and decommitted blocks
      DPH_HEAP_BLOCK : VirtAddr VirtSize
    Busy allocations
      DPH_HEAP_BLOCK : UserAddr  UserSize - VirtAddr VirtSize
    _HEAP @ 1300000
    _DPH_HEAP_ROOT @ 1401000
    Freed and decommitted blocks
      DPH_HEAP_BLOCK : VirtAddr VirtSize
    Busy allocations
      DPH_HEAP_BLOCK : UserAddr  UserSize - VirtAddr VirtSize
    _HEAP @ 16b0000
    _DPH_HEAP_ROOT @ 2361000
    Freed and decommitted blocks
      DPH_HEAP_BLOCK : VirtAddr VirtSize
    Busy allocations
      DPH_HEAP_BLOCK : UserAddr  UserSize - VirtAddr VirtSize
    _HEAP @ 1280000
    _DPH_HEAP_ROOT @ 2f01000
    Freed and decommitted blocks
      DPH_HEAP_BLOCK : VirtAddr VirtSize
    Busy allocations
      DPH_HEAP_BLOCK : UserAddr  UserSize - VirtAddr VirtSize
        02f024e0 : 02fc63c0 00009c40 - 02fc6000 0000b000
    _HEAP @ 31d0000

可以看到, WinDbg幫我們找到了一個(gè)符合要求的分配, 它的UserAddr是02fc63c0, 該地址實(shí)際上就是代碼char* pLargeMem = new char[40000]分配的地址, 按照開(kāi)頭的方法, 輸入!heap -p -a 02fc63c0 
0:001> !heap -p -a 02fc63c0
    address 02fc63c0 found in
    _DPH_HEAP_ROOT @ 2f01000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 2f024e0:          2fc63c0             9c40 -          2fc6000             b000
    5a8c8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77485c4e ntdll!RtlDebugAllocateHeap+0x00000030
    77447e5e ntdll!RtlpAllocateHeap+0x000000c4
    774134df ntdll!RtlAllocateHeap+0x0000023a
    5b06a65d vrfcore!VfCoreRtlAllocateHeap+0x00000016
    5a92f9ea vfbasics!AVrfpRtlAllocateHeap+0x000000e2
    72893db8 MSVCR90!malloc+0x00000079
    72893eb8 MSVCR90!operator new+0x0000001f
    012c101e MemLeakTest!wmain+0x0000001e [f:\test\memleaktest\memleaktest\memleaktest.cpp @ 13]
    77331114 kernel32!BaseThreadInitThunk+0x0000000e
    7741b429 ntdll!__RtlUserThreadStart+0x00000070
    7741b3fc ntdll!_RtlUserThreadStart+0x0000001b

可以看到該堆棧就是我們
new char[40000]的堆棧, 用同樣的方法, 我們可以分析出上面代碼for循環(huán)中的1000次內(nèi)存泄漏。

最后, 總結(jié)一下, 通過(guò)WinDbg結(jié)合AppVerifier, 我們可以詳細(xì)的跟蹤堆中new出來(lái)的每一塊內(nèi)存。 很多時(shí)候在沒(méi)有源代碼的Release版本中,在程序運(yùn)行一段時(shí)間后,如果我們發(fā)現(xiàn)有大塊內(nèi)存或是大量同樣大小的小內(nèi)存一直沒(méi)有釋放,  我們就可以用上面的方法進(jìn)行分析。有些情況下,我們甚至可以將 _CrtDumpMemoryLeaks()和WinDbg的!heap -p -a [address]命令結(jié)合起來(lái)使用, 由前者打印泄漏地址,后者分析調(diào)用堆棧,以便快速的定位問(wèn)題。

posted @ 2014-10-14 09:57 Enic 閱讀(275) | 評(píng)論 (0)編輯 收藏

客戶端架構(gòu)設(shè)計(jì)的簡(jiǎn)單總結(jié)
我們知道,客戶端是相對(duì)服務(wù)端而言的,客戶端程序相對(duì)普通應(yīng)用程序,主要是增加了網(wǎng)絡(luò)通訊功能。在這個(gè)移動(dòng)和云存儲(chǔ)的年代,大部分終端應(yīng)用程序都有網(wǎng)絡(luò)通訊功能, 所以都可以稱為客戶端。常見(jiàn)的客戶端如瀏覽器,IM客戶端, 網(wǎng)絡(luò)會(huì)議客戶端,郵件客戶端,微博和微信客戶端等...

通過(guò)觀察,我們會(huì)發(fā)現(xiàn)所有的客戶端基本是大同小異,都會(huì)包括一些相同的功能組件, 下面簡(jiǎn)單例舉下:
通訊協(xié)議層

既然客戶端都有網(wǎng)絡(luò)功能,就會(huì)涉及到通訊方式和數(shù)據(jù)格式以及協(xié)議, 這三者不是完全獨(dú)立,而是有機(jī)統(tǒng)一的。

首先說(shuō)通訊方式,常見(jiàn)的通訊方式包括TCP,UDP, P2P和http(s), 很多時(shí)候我們不會(huì)用單一的通訊方式,而是多種通訊方式的結(jié)合。比如說(shuō)TCP端口被封,走不通時(shí),我們會(huì)轉(zhuǎn)成嘗試http(s)。IM中聊天文本走的是TCP, 由服務(wù)器轉(zhuǎn)發(fā),但是2個(gè)客戶端之間的文件傳輸我們可能走的又是P2P了, 多個(gè)人之間的語(yǔ)音聊天, 我們走的又是UDP了。

其次說(shuō)數(shù)據(jù)格式,常見(jiàn)的數(shù)據(jù)格式包括二進(jìn)制編碼,開(kāi)源序列化協(xié)議和文本格式。
二進(jìn)制一般是自定義的私有格式,通常對(duì)數(shù)值,我們會(huì)轉(zhuǎn)成大頭端,對(duì)字符串我們會(huì)用UTF8 編碼,因?yàn)闆](méi)有冗余數(shù)據(jù),它的優(yōu)點(diǎn)是不會(huì)浪費(fèi)帶寬;主要缺點(diǎn)是有硬編碼的味道,不好擴(kuò)充。
開(kāi)源序列化協(xié)議這里主要是指google的protocal buffer,  現(xiàn)在很多公司都在用, 很多人基于它開(kāi)發(fā)了自己的RPC框架。主要優(yōu)點(diǎn)是數(shù)據(jù)小,使用簡(jiǎn)單而高效。
文本格式主要是指xml和json. 相對(duì)來(lái)說(shuō)xml比較清晰和容易擴(kuò)充,但是冗余數(shù)據(jù)比較多。json借助javascript對(duì)它語(yǔ)言層次的支持,感覺(jué)主要是前端人員使用的比較多。

最后再說(shuō)協(xié)議,  協(xié)議和我們的應(yīng)用相關(guān)聯(lián)。比如郵件客戶端,當(dāng)然是走SMTP和POP3了; IM客戶端的話,一般走XMPP了;  網(wǎng)絡(luò)會(huì)議的話,可以走ITU的T.120協(xié)議, 也可以RFC 6501定義的XCON, 信令走SIP, 數(shù)據(jù)走RTP等。

通信協(xié)議層是整個(gè)客戶端網(wǎng)絡(luò)事件驅(qū)動(dòng)的引擎,它可能會(huì)比較簡(jiǎn)單,也可能會(huì)很復(fù)雜。如果是基于XMPP的IM, 它可能會(huì)比較簡(jiǎn)單,因?yàn)榛旧现恍枰粚游谋緟f(xié)議的封包和解包就可以了。 當(dāng)如果是基于T.120網(wǎng)絡(luò)會(huì)議客戶端,就會(huì)比較復(fù)雜,它數(shù)據(jù)包走的自定義的二機(jī)制格式,按照T.120協(xié)議的建議, 在通訊協(xié)議層又分了3層:TP, MCS和GCC。TP層主要封裝數(shù)據(jù)傳輸?shù)姆绞? 可以讓上層無(wú)差別的區(qū)分TCP和http(s)。 MCS層主要提供多點(diǎn)傳輸功能, 它抽象出通道(channel)這個(gè)概念, 讓不同session的數(shù)據(jù)進(jìn)行邏輯隔離, 上層用戶可以同時(shí)加入不同的通道來(lái)進(jìn)行一對(duì)一和一對(duì)多的數(shù)據(jù)收發(fā),并且通道中的數(shù)據(jù)有不同的優(yōu)先級(jí), 還有令牌這個(gè)機(jī)制。我們也可以在MCS層對(duì)數(shù)據(jù)進(jìn)行加密和壓縮, 還可以對(duì)上層的大數(shù)據(jù)包進(jìn)行切包等。 GCC層主要封裝會(huì)議的最基本邏輯,比如創(chuàng)建會(huì)議和加入session數(shù)據(jù)包的格式封裝等, 讓上層可以通過(guò)API調(diào)用而不用關(guān)心協(xié)議要求的數(shù)據(jù)包格式。不同的數(shù)據(jù)包會(huì)工作在不同的層次, 比如心跳包可能在底層TP層就被攔截了,它不要再往上層發(fā),因?yàn)樯厦娌挥藐P(guān)心這個(gè); 而有些數(shù)據(jù)包,則需要從底層往上層按照整個(gè)協(xié)議棧層層轉(zhuǎn)發(fā),當(dāng)然每層都會(huì)剝離掉自己的協(xié)議頭, 直至上層用戶數(shù)據(jù)到達(dá)它的最終用戶。

總之,通訊協(xié)議層封裝了客戶端和服務(wù)端的通訊方式及協(xié)議格式, 讓上層用戶不用關(guān)心底層的通信機(jī)制, 而只關(guān)注應(yīng)用的接口事件。理論上我們可以在上層應(yīng)用不做大調(diào)整的前提下,直接將網(wǎng)絡(luò)會(huì)議客戶端中的T.120協(xié)議成基于SIP的XCON。
功能組件

一個(gè)客戶端程序通常是由很多功能模塊組成,模塊按功能來(lái)說(shuō)可以分為基礎(chǔ)組件和應(yīng)用組件。

基礎(chǔ)組件為應(yīng)用組件提供的基礎(chǔ)設(shè)施,基礎(chǔ)組件是可以在不同的項(xiàng)目中重復(fù)使用的(比如界面控件庫(kù),2D渲染引擎Skia, 跨平臺(tái)的網(wǎng)絡(luò)和線程庫(kù)等)。 
應(yīng)用組件通常和我們當(dāng)前的特定應(yīng)用程序相關(guān),比如我們的網(wǎng)絡(luò)會(huì)議客戶端包含的桌面共享模塊, 文檔共享模塊,視頻音頻模塊,文本聊天模塊等。

應(yīng)用模塊本身分為帶界面和無(wú)界面兩種情況, 帶界面的情況下我們通常會(huì)給組件提供一個(gè)容器窗口的句柄, 讓組件自己在內(nèi)部組織自己的界面。這種帶界面的組件通常會(huì)為邏輯和界面的分離帶來(lái)麻煩,在Window上實(shí)現(xiàn)一些半透明和動(dòng)畫(huà)效果也很難。 比如我們想提供跨平臺(tái)的SDK來(lái)封裝邏輯,這時(shí)我們會(huì)更傾向讓?xiě)?yīng)用組件采用無(wú)界面的模式,組件在跨平臺(tái)層只封裝邏輯和提供數(shù)據(jù), 而把數(shù)據(jù)發(fā)到最上層界面層后再統(tǒng)一處理。

對(duì)功能組件我們的設(shè)計(jì)原則是盡量保持獨(dú)立和可復(fù)用,最好能以仿COM方式動(dòng)態(tài)升級(jí)而不用重新編譯, 另外組件之間要保持層次性,避免雙向或是循環(huán)依賴。
數(shù)據(jù)存儲(chǔ)

客戶端本身是處理和收發(fā)網(wǎng)絡(luò)數(shù)據(jù), 這里就涉及到對(duì)這些數(shù)據(jù)如何組織和存儲(chǔ)的問(wèn)題。這個(gè)通常會(huì)根據(jù)客戶端的類(lèi)型采用不同的處處理方式:
對(duì)于永久存儲(chǔ)的數(shù)據(jù),當(dāng)然是保存成文件或是存入數(shù)據(jù)庫(kù),文件如xml, 數(shù)據(jù)庫(kù)如ACCESS,  SQL server, mysql等。
臨時(shí)數(shù)據(jù)當(dāng)然是存入內(nèi)存了,根據(jù)需要采用不同的數(shù)據(jù)結(jié)構(gòu), 組織格式如array,list, map, hashmap等。
還有一種是常見(jiàn)的數(shù)據(jù)保存方式是內(nèi)存數(shù)據(jù)庫(kù),最常見(jiàn)是SQLite了, 內(nèi)存數(shù)據(jù)庫(kù)既能高效的分類(lèi)保存大量數(shù)據(jù), 又可以直接用基于SQL語(yǔ)句進(jìn)行查詢和處理, 比如foxmail客戶端就是用SQLite存儲(chǔ)的郵件信息。
還有一種是跨進(jìn)程共享的數(shù)據(jù),我們一般當(dāng)然是內(nèi)存映射文件了。比如我們有一個(gè)實(shí)時(shí)顯示log的工具, 我們通常會(huì)在對(duì)方應(yīng)用程序里分配共享內(nèi)存的內(nèi)存映射文件,所有的log都寫(xiě)到里面,然后在log工具程序里讀取和顯示。
當(dāng)然還有一些數(shù)據(jù)可能存到網(wǎng)上去的, 常見(jiàn)的比如我們的云筆記, 這時(shí)數(shù)據(jù)分服務(wù)端數(shù)據(jù)和本地cache。

對(duì)于數(shù)據(jù)存儲(chǔ)我們的設(shè)計(jì)原則是根據(jù)需要,選擇簡(jiǎn)單高效的方式。比如我們?cè)谠O(shè)計(jì)網(wǎng)絡(luò)會(huì)議客戶端時(shí)曾討論要不要引入SQLite, 理想情況是引入內(nèi)存數(shù)據(jù)庫(kù)后各個(gè)組件和上層應(yīng)用的數(shù)據(jù)都可以統(tǒng)一存儲(chǔ),采用數(shù)據(jù)驅(qū)動(dòng)的方式,可以很方便的跟蹤整個(gè)客戶端的運(yùn)行情況。但后來(lái)發(fā)現(xiàn)這種設(shè)計(jì)會(huì)把本來(lái)各自獨(dú)立的組件通過(guò)數(shù)據(jù)庫(kù)耦合在了一起,而且各組件的數(shù)據(jù)格式本身都很不要一樣, 很難統(tǒng)一存儲(chǔ), 另外很多數(shù)據(jù)實(shí)際也只是臨時(shí)數(shù)據(jù), 沒(méi)必要把簡(jiǎn)單的時(shí)間做復(fù)雜了。
客戶端框架

客戶端框架一般有兩個(gè)作用:一是把所有的功能組件組織起來(lái),進(jìn)行統(tǒng)一的管理和展現(xiàn); 二是實(shí)現(xiàn)整個(gè)客戶端的主界面。客戶端框架在協(xié)調(diào)各個(gè)組件時(shí), 要注意避免讓組件之間產(chǎn)生雙向依賴, 而是應(yīng)該讓組件把事件通知給框架后由框架統(tǒng)一協(xié)調(diào)和處理, 所以客戶端框架通常是整個(gè)客戶端邏輯最復(fù)雜的部分。 一個(gè)好的客戶端框架,通常會(huì)采用插件方式設(shè)計(jì),可以動(dòng)態(tài)插拔需要的組件。最好是可以根據(jù)服務(wù)端的配置, 動(dòng)態(tài)下載和更新所需要的插件。

對(duì)于客戶端框架, 我們的設(shè)計(jì)原則是低耦合和可擴(kuò)展。基本上所有下層組件的改動(dòng)都會(huì)影響到我們的客戶端框架,客戶的很多新需求和新組件也會(huì)導(dǎo)致框架產(chǎn)生壞味道, 這里我們?cè)O(shè)計(jì)時(shí)就要考慮如何讓客戶端框架能及時(shí)的適應(yīng)這些變化。
界面庫(kù)

客戶端肯定會(huì)有界面,在Windows平臺(tái)上,現(xiàn)在的界面大致分為以下幾類(lèi):
基于Windows原始窗口控件句柄的C++ native 客戶端, 基于.net的winform客戶端,基于.net的WPF客戶端,基于C++的DirectUI客戶端, 以嵌入瀏覽器(如webkit)方式實(shí)現(xiàn)的客戶端, 還有一類(lèi)是基于Xaml的Metro客戶端。

對(duì)于企業(yè)級(jí)大型安裝應(yīng)用,主要考慮的是開(kāi)發(fā)效率,所以客戶端還是以.net為主; 但是對(duì)于互聯(lián)網(wǎng)企業(yè), 更多的是要求客戶端精簡(jiǎn)而高效, 所以還是以C++為主。 這里就設(shè)及到C++的兩種界面庫(kù), 一種是基于windows窗口句柄和控件自繪機(jī)制的界面庫(kù),還有一中是基于DirectUI的界面庫(kù), 現(xiàn)在大一點(diǎn)的公司基本上都有自己的DirectUI界面庫(kù)。基于修改Webkit方式實(shí)現(xiàn)的界面庫(kù)可以通過(guò)Canvas和SVG動(dòng)畫(huà)等方式實(shí)現(xiàn)一些很炫的效果, 但是它和標(biāo)準(zhǔn)程序的用戶體驗(yàn)還是有一定差距:一來(lái)web實(shí)現(xiàn)的控件跟Windows標(biāo)準(zhǔn)控件有很大不同, 二來(lái)web的流式布局和應(yīng)用程序的網(wǎng)格布局也不一樣。

對(duì)于界面,個(gè)人覺(jué)得這個(gè)東西變化實(shí)在太快了,所以我覺(jué)得應(yīng)該盡量用界面和邏輯相分離的方式組織代碼。
總結(jié)

對(duì)于客戶端架構(gòu)設(shè)計(jì),個(gè)人覺(jué)得最大的原則就分層設(shè)計(jì), 每層都封裝一個(gè)概念并保持獨(dú)立, 同時(shí)根據(jù)依賴倒置的原則, 站在上層客戶的角度提供接口。軟件工程里面的一條黃金定律:“任何問(wèn)題都可以通過(guò)增加一個(gè)間接層來(lái)解決。

 


http://m.shnenglu.com/weiym
posted @ 2014-10-14 09:46 Enic 閱讀(269) | 評(píng)論 (0)編輯 收藏

最近有機(jī)會(huì)看號(hào)稱是公司最核心的代碼, 因?yàn)檫@個(gè)代碼以前一直是美國(guó)那邊保密的, 這么重要的代碼會(huì)是啥樣子?
真正拿到手大致看了一下后卻挺失望的,因?yàn)樵摯a風(fēng)格基本上是我剛畢業(yè)時(shí)的C++風(fēng)格----帶類(lèi)的C,單從代碼上看寫(xiě)的挺濫,里面沒(méi)啥設(shè)計(jì)模式, 也沒(méi)有用模板, 代碼里面甚至一個(gè)函數(shù)可以寫(xiě)上近千行。
這么重要的代碼, 竟然是這種風(fēng)格,挺郁悶, 由此思考好的C++程序應(yīng)該是什么風(fēng)格?

C++因?yàn)楸旧碇С侄喾N范型設(shè)計(jì)(面向過(guò)程, 基于對(duì)象,面向?qū)ο螅胀ǚ盒停0逶幊痰?, 使得C++的程序風(fēng)格和其他語(yǔ)言相比更加多種多樣。所以有人評(píng)價(jià)C++像一把瑞士軍刀, 什么功能都有, 你想拿它當(dāng)什么刀使,它就能成為什么刀, 所以它很強(qiáng)大,強(qiáng)大的同時(shí)也意味著復(fù)雜。其他語(yǔ)言,比如Java/C#主要只支持面向?qū)ο螅@樣他們的風(fēng)格就很統(tǒng)一, 無(wú)論是標(biāo)準(zhǔn)庫(kù),框架還是應(yīng)用,都是以對(duì)象,接口和模式為主導(dǎo)。 但是C++程序就不一樣了, 可以說(shuō)C++程序風(fēng)格沒(méi)有固定的標(biāo)準(zhǔn), 每個(gè)人根據(jù)他的經(jīng)歷和使用的框架,會(huì)有完全不一樣的風(fēng)格, 網(wǎng)上別人總結(jié)了一些C++程序風(fēng)格:

1. 經(jīng)典C++流:類(lèi)是核心,例程多用C Runtime的,很少用模版,一般是正統(tǒng)教育的結(jié)果。
2. 古典C流:基本上當(dāng)C用,偶爾用用對(duì)象,不使用異常,喜歡懷舊。
3. MFC流:秉承MFC的風(fēng)格,主要使用MFC/ATL對(duì)象和Win32 API,不喜歡STL,用很多的宏把IDE的語(yǔ)法提示模塊折磨到崩潰。
4. Portable流:以C Runtime和STL為主要工具,使用類(lèi)和模版,不跨平臺(tái)毋寧死。
5. Functional流:以模版和STL為主要武器,大量使用函數(shù)式語(yǔ)言的設(shè)計(jì)方法,并號(hào)稱這才是真正的C++。
6. Win32流:多使用全局函數(shù),偏愛(ài)Win32 API,但不排斥C Runtime,通常喜歡輕量級(jí)的程序,所以身材也比較苗條。
7. Java流:全面使用Java的風(fēng)格,不能容許任何全局成員,但允許使用STL的集合類(lèi),寫(xiě)很多叫Factory的類(lèi)。
8. COM流:喜歡AddRef()和Release(),大量使用接口,隱藏一切可以隱藏的東西,誦經(jīng)的時(shí)候要把上帝替換成COM。
9. 戒律流:追求完美的C++程序,計(jì)較每一個(gè)const和throw(),極力避免不安全的cast,隨身一定要帶一本ISO C++手冊(cè)。
10. 混沌流:其程序無(wú)常形,無(wú)恒道,變幻莫測(cè),吾不知其名。 

上面確實(shí)總結(jié)了我們常見(jiàn)的一些C++程序風(fēng)格,相信大部分C++程序員都可以再里面找到自己曾經(jīng)或現(xiàn)在的影子。另外每個(gè)人C++程序風(fēng)格不是一成不變的,隨著他的項(xiàng)目經(jīng)歷會(huì)不斷的變化。比如一般人剛畢業(yè)時(shí)的風(fēng)格都是帶類(lèi)的C,代碼風(fēng)格偏向面向過(guò)程; 后來(lái)隨著對(duì)面向?qū)ο蟮纳钊耄?慢慢地會(huì)使用模式和接口來(lái)設(shè)計(jì),此時(shí)代碼風(fēng)格偏向面向?qū)ο螅? 再后面可能會(huì)深入STL和泛型,甚至模板元編程, 此時(shí)代碼風(fēng)格使用模板泛型; 最后有些人可能會(huì)覺(jué)得過(guò)度的關(guān)注面向?qū)ο蟮脑O(shè)計(jì)模式和模板的泛型設(shè)計(jì), 會(huì)讓人偏離對(duì)要解決的問(wèn)題本身的關(guān)注, 最后他的風(fēng)格又回到了原始的C或是剛畢業(yè)時(shí)帶類(lèi)的C的風(fēng)格。

從上面可以看到,對(duì)于C++程序風(fēng)格,我們很難定出一個(gè)比較統(tǒng)一的標(biāo)準(zhǔn),但是我想我們可以根據(jù)我們要解決的問(wèn)題不同而使用不同的風(fēng)格。下面是我個(gè)人的一些看法:

(1)C++底層語(yǔ)言基礎(chǔ)庫(kù)(STL, Boost)以泛型為主導(dǎo), 以高效和通用為設(shè)計(jì)原則, 這方面我想大家已經(jīng)達(dá)成共識(shí)

(2)C++應(yīng)用基礎(chǔ)庫(kù)和框架以面向?qū)ο蠛头盒蜑橹鲗?dǎo)。基礎(chǔ)框架一般對(duì)擴(kuò)展性和性能都有一定要求,對(duì)于框架一般我們是大量實(shí)踐經(jīng)驗(yàn)的總結(jié),所以我們基本上已經(jīng)知道它的所有可變情況, 所以理論上我們可以進(jìn)行精致的設(shè)計(jì),然后通過(guò)模板參數(shù)的Traits和Policy來(lái)分離所有可能的情況,框架本身也有一定的復(fù)雜性,需要面向?qū)ο髞?lái)封裝和解耦, ATL是這方面作為COM組件開(kāi)發(fā)基礎(chǔ)庫(kù)的成功例子。基礎(chǔ)框架以高效,專用和擴(kuò)展性為設(shè)計(jì)原則。

(3)C++應(yīng)用層以面向?qū)ο鬄橹鲗?dǎo)。應(yīng)用層邏輯是多變的, 理論上你也可以采用模板參數(shù)的方式來(lái)應(yīng)對(duì)變化, 但是應(yīng)用層的變化非常復(fù)雜, 很多事不可預(yù)測(cè)的, 所以你不可能以模板參數(shù)的方式預(yù)測(cè)到所有可能的情況。另外C++現(xiàn)在還沒(méi)有對(duì)泛型Concepts的描述機(jī)制, 導(dǎo)致模板代碼比較難懂。在多變的應(yīng)用層大量采用模板顯然不是一個(gè)好的選擇。 另外模板在應(yīng)用層的大量使用也沒(méi)有比較成熟的經(jīng)驗(yàn), 而面向?qū)ο蠛湍J揭呀?jīng)是非常成熟。應(yīng)用層以低耦合,靈活應(yīng)對(duì)變化為設(shè)計(jì)原則。

(4)C++模塊(DLL)間的交互則以C方式API或是仿COM(Interface+Factory)為主導(dǎo), 模塊接口和交互以簡(jiǎn)潔和二進(jìn)制兼容為設(shè)計(jì)原則。

總之, 我們應(yīng)該靈活應(yīng)用C++各種風(fēng)格和范型的特點(diǎn), 采用 ”多范型“ 程序設(shè)計(jì)的思路來(lái)解決問(wèn)題, 而不是采用單一風(fēng)格。

最后,回到我最初的公司核心代碼, 該代碼是用來(lái)解決某個(gè)特定問(wèn)題, 顯然與通用性和可擴(kuò)展性關(guān)系都不大, 也就不需要所謂的模式和模板了, 實(shí)際上你越往操作系統(tǒng)底層, 你離這些抽象的東西就越遠(yuǎn), 所以Linux之父才會(huì)給C++差評(píng)。


http://m.shnenglu.com/weiym
posted @ 2014-10-14 09:45 Enic 閱讀(358) | 評(píng)論 (0)編輯 收藏

SQL連接可以分為內(nèi)連接、外連接、交叉連接。

 

數(shù)據(jù)庫(kù)數(shù)據(jù):

           

book表                                          stu表

 

1.內(nèi)連接

1.1.等值連接:在連接條件中使用等于號(hào)(=)運(yùn)算符比較被連接列的列值,其查詢結(jié)果中列出被連接表中的所有列,包括其中的重復(fù)列。

1.2.不等值連接:在連接條件使用除等于運(yùn)算符以外的其它比較運(yùn)算符比較被連接的列的列值。這些運(yùn)算符包括>、>=、<=、<、!>、!<和<>。

1.3.自然連接:在連接條件中使用等于(=)運(yùn)算符比較被連接列的列值,但它使用選擇列表指出查詢結(jié)果集合中所包括的列,并刪除連接表中的重復(fù)列。

內(nèi)連接:內(nèi)連接查詢操作列出與連接條件匹配的數(shù)據(jù)行,它使用比較運(yùn)算符比較被連接列的列值。

select * from book as a,stu as b where a.sutid = b.stuid  select * from book as a inner join stu as b on a.sutid = b.stuid

內(nèi)連接可以使用上面兩種方式,其中第二種方式的inner可以省略。

其連接結(jié)果如上圖,是按照a.stuid = b.stuid進(jìn)行連接。

 

2.外連接

2.1.左聯(lián)接:是以左表為基準(zhǔn),將a.stuid = b.stuid的數(shù)據(jù)進(jìn)行連接,然后將左表沒(méi)有的對(duì)應(yīng)項(xiàng)顯示,右表的列為NULL

select * from book as a left join stu as b on a.sutid = b.stuid

2.2.右連接:是以右表為基準(zhǔn),將a.stuid = b.stuid的數(shù)據(jù)進(jìn)行連接,然以將右表沒(méi)有的對(duì)應(yīng)項(xiàng)顯示,左表的列為NULL

select * from book as a right join stu as b on a.sutid = b.stuid

2.3.全連接:完整外部聯(lián)接返回左表和右表中的所有行。當(dāng)某行在另一個(gè)表中沒(méi)有匹配行時(shí),則另一個(gè)表的選擇列表列包含空值。如果表之間有匹配行,則整個(gè)結(jié)果集行包含基表的數(shù)據(jù)值。

select * from book as a full outer join stu as b on a.sutid = b.stuid

 

3.交叉連接

交叉連接:交叉聯(lián)接返回左表中的所有行,左表中的每一行與右表中的所有行組合。交叉聯(lián)接也稱作笛卡爾積。

select * from book as a cross join stu as b order by a.id

posted @ 2014-10-05 11:09 Enic 閱讀(160) | 評(píng)論 (0)編輯 收藏

     摘要: C++11與Unicode及使用標(biāo)準(zhǔn)庫(kù)進(jìn)行UTF-8、UTF-16、UCS2、UCS4/UTF-32編碼轉(zhuǎn)換作者: 破曉 日期: 2014年2月28日發(fā)表評(píng)論 (0)查看評(píng)論UnicodeUnicode是計(jì)算機(jī)領(lǐng)域的一項(xiàng)行業(yè)標(biāo)準(zhǔn),它對(duì)世界上絕大部分的文字的進(jìn)行整理和統(tǒng)一編碼,Unicode的編碼空間可以劃分為17個(gè)平面(plane),每個(gè)平面包含2的16次方(655...  閱讀全文
posted @ 2014-09-25 14:53 Enic 閱讀(10976) | 評(píng)論 (0)編輯 收藏

僅列出標(biāo)題
共22頁(yè): First 5 6 7 8 9 10 11 12 13 Last 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲永久精品国产| 亚洲自拍偷拍色片视频| 欧美国产日韩亚洲一区| 99热精品在线观看| 久久高清一区| 香蕉成人久久| 亚洲精品国产精品国自产在线| 欧美日韩国产丝袜另类| 久久视频在线视频| 免费看成人av| 亚洲国产精品成人va在线观看| 欧美一区二区精品在线| 99精品国产高清一区二区| 国产一区二区三区在线播放免费观看| 麻豆精品视频在线| 亚洲网站啪啪| 国产美女精品免费电影| 久久久女女女女999久久| 亚洲欧美在线免费观看| 欧美在线91| 久久一区二区三区超碰国产精品| 久久久久久999| 欧美日韩国产美| 国产女人aaa级久久久级| 一区二区三区亚洲| 在线亚洲一区观看| 久久综合九九| 一区二区不卡在线视频 午夜欧美不卡在| 中文国产成人精品| 老鸭窝毛片一区二区三区| 欧美日韩福利视频| 好吊色欧美一区二区三区视频| 亚洲精品在线二区| 久久久久久色| 一区二区三区国产精品| 久热精品在线| 国产欧美精品日韩区二区麻豆天美 | 久久网站免费| 亚洲美女精品一区| 久久精品国产久精国产一老狼| 欧美精品乱码久久久久久按摩| 国产性猛交xxxx免费看久久| 亚洲免费大片| 欧美国产日韩在线| 久久成人免费电影| 国产精品久线观看视频| 一区二区成人精品| 欧美黄色aaaa| 欧美一级午夜免费电影| 国产精品狠色婷| 亚洲精品欧美在线| 欧美激情91| 久久久久在线观看| 国产欧美一区二区三区视频| 亚洲最新视频在线| 亚洲国产mv| 久久久国产视频91| 国产香蕉97碰碰久久人人| 午夜精品视频一区| 亚洲五月六月| 欧美午夜精品| 亚洲欧美一级二级三级| 在线性视频日韩欧美| 欧美精品一区在线播放| 亚洲精品乱码久久久久久| 牛牛国产精品| 麻豆国产精品一区二区三区 | 久久久久久国产精品mv| 亚洲韩国青草视频| 欧美国产高清| 一区二区三区日韩欧美| 最新国产成人av网站网址麻豆 | 在线一区日本视频| 国产精品播放| 欧美亚洲视频在线观看| 欧美亚洲一区二区在线观看| 国产日韩欧美精品综合| 久久影视三级福利片| 久久蜜臀精品av| 亚洲国产欧美一区| 亚洲精品视频在线看| 国产精品电影网站| 久久www成人_看片免费不卡| 欧美一区二区在线视频| 国产在线不卡| 欧美成人嫩草网站| 毛片一区二区| 亚洲精品三级| 久久人91精品久久久久久不卡| 亚洲老板91色精品久久| 亚洲欧美国产精品桃花| 99热在线精品观看| 麻豆精品视频在线观看视频| 久久国产乱子精品免费女| 欧美噜噜久久久xxx| 久久国产88| 欧美成人高清| 男女激情视频一区| 在线亚洲欧美专区二区| 亚洲欧美日韩国产综合精品二区| 国产日韩精品视频一区| 欧美福利精品| 国产精品久久久久一区二区三区| 久久久激情视频| 欧美国产日韩免费| 久久国产一区| 欧美成人视屏| 久久精品色图| 欧美日韩午夜激情| 久久三级视频| 欧美四级剧情无删版影片| 久久亚洲精品网站| 欧美三级日韩三级国产三级| 久久青青草综合| 国产精品丝袜久久久久久app| 欧美搞黄网站| 国产亚洲欧美aaaa| 一区二区三区视频观看| 亚洲欧洲在线一区| 久久国产黑丝| 午夜视频在线观看一区二区| 欧美.www| 欧美激情欧美激情在线五月| 国产精品天天摸av网| 99亚洲视频| 欧美大片一区| 亚洲欧美视频一区| 亚洲精品欧美一区二区三区| 欧美日韩一区自拍| 久久噜噜亚洲综合| 久久国产精品高清| 欧美成人a∨高清免费观看| 欧美精品激情blacked18| 午夜欧美不卡精品aaaaa| 欧美电影美腿模特1979在线看| 久久精品99国产精品| 欧美日韩亚洲国产精品| 亚洲欧洲三级| 亚洲老司机av| 欧美国产日韩亚洲一区| 亚洲国产精品传媒在线观看| 亚洲国产日韩精品| 模特精品在线| 亚洲国产欧美一区二区三区丁香婷| 亚洲第一中文字幕在线观看| 久久精品欧洲| 欧美电影在线播放| 亚洲精选一区| 欧美日韩一区二区三区免费看| 亚洲东热激情| 99视频在线观看一区三区| 欧美国产高潮xxxx1819| 亚洲韩国日本中文字幕| 一二三四社区欧美黄| 欧美另类一区二区三区| 亚洲精品视频在线观看网站| 亚洲午夜影视影院在线观看| 欧美特黄一级| 91久久夜色精品国产九色| 99精品国产福利在线观看免费| 欧美视频一区二区三区…| 亚洲免费影视| 美女精品在线观看| 狠狠网亚洲精品| 欧美激情视频在线播放 | 免费欧美高清视频| 欧美国产视频在线观看| 欧美日韩日本网| 一区二区三区高清在线观看| 亚洲一二三区在线观看| 亚洲欧美一区二区三区久久| 国产亚洲视频在线观看| 蜜臀91精品一区二区三区| 亚洲乱码一区二区| 久久视频一区| 亚洲视频免费在线观看| 国产视频一区在线| 国产一区三区三区| 午夜一区二区三区在线观看| 葵司免费一区二区三区四区五区| 亚洲成色999久久网站| 亚洲最黄网站| 国产精品入口尤物| 亚洲一二区在线| 亚洲精品国产无天堂网2021| 久久免费精品视频| 在线欧美不卡| 欧美成人精品1314www| 美国成人毛片| 亚洲人成网站色ww在线| 亚洲一区二区三区四区五区午夜| 国产精品久久久久av免费| 久久精品首页| 亚洲午夜精品国产| 久久久91精品国产一区二区三区| 亚洲二区在线| 欧美精品久久一区| 亚洲午夜久久久久久久久电影网| 欧美丝袜第一区| 欧美福利在线观看|