Java面試題集(71-85)
分享一下我的偶像大神的人工智慧教程!http://blog.csdn.net/jiangjunshow
Java程式設計師面試題集(71-85)
摘要:這一部分主要包括了UML(統一建模語言)、面向物件的設計原則(六原則一法則)、GoF設計模式、企業級設計模式、JDBC(Java資料庫連線)、XML(可擴充套件標記語言)等知識。
71、UML是什麼?UML中有哪些圖?
答:UML是統一建模語言(Unified Modeling Language)的縮寫,它發表於1997年,綜合了當時已經存在的面向物件的建模語言、方法和過程,是一個支援模型化和軟體系統開發的圖形化語言,為軟體開發的所有階段提供模型化和視覺化支援。使用UML可以幫助溝通與交流,輔助應用設計和文件的生成,還能夠闡釋系統的結構和行為。UML定義了多種圖形化的符號來描述軟體系統部分或全部的靜態結構和動態結構,包括:用例圖(use case diagram)、類圖(class diagram)、時序圖(sequence diagram)、協作圖(collaboration diagram)、狀態圖(statechart diagram)、活動圖(activity diagram)、構件圖(component diagram)、部署圖(deployment diagram)等。在這些圖形化符號中,有三種圖最為重要,分別是:用例圖(用來捕獲需求,描述系統的功能,通過該圖可以迅速的瞭解系統的功能模組及其關係)、類圖(描述類以及類與類之間的關係,通過該圖可以快速瞭解系統)、時序圖(描述執行特定任務時物件之間的互動關係以及執行順序,通過該圖可以瞭解物件能接收的訊息也就是說物件能夠向外界提供的服務)。
用例圖:
類圖:
時序圖:
72、寫一個單例類。
答:單例模式主要作用是保證在Java應用程式中,一個類只有一個例項存在。下面給出兩種不同形式的單例:
第一種形式:餓漢式單例
-
public
class Singleton {
-
private Singleton(){}
-
private
static Singleton instance =
new Singleton();
-
public static Singleton getInstance(){
-
return instance;
-
}
-
}
第二種形式:懶漢式單例
-
public
class Singleton {
-
private
static Singleton instance =
null;
-
private Singleton() {}
-
public static synchronized Singleton getInstance(){
-
if (instance==
null) instance=newSingleton();
-
return instance;
-
}
-
}
單例的特點:外界無法通過構造器來建立物件,該類必須提供一個靜態方法向外界提供該類的唯一例項。
【補充】用Java進行伺服器端程式設計時,使用單例模式的機會還是很多的,伺服器上的資源都是很寶貴的,對於那些無狀態的物件其實都可以單例化或者靜態化(在記憶體中僅有唯一拷貝),如果使用了Spring這樣的框架來進行物件託管,Spring的IoC容器在預設情況下對所有託管物件都是進行了單例化處理的。
73、說說你所熟悉或聽說過的設計模式以及你對設計模式的看法。
答:在GoF的《Design Patterns: Elements of Reusable Object-Oriented Software》中給出了三類(建立型[對類的例項化過程的抽象化]、結構型[描述如何將類或物件結合在一起形成更大的結構]、行為型[對在不同的物件之間劃分責任和演算法的抽象化])共23種設計模式,包括:Abstract Factory(抽象工廠模式),Builder(建造者模式),Factory Method(工廠方法模式),Prototype(原始模型模式),Singleton(單例模式);Facade(門面模式),Adapter(介面卡模式),Bridge(橋樑模式),Composite(合成模式),Decorator(裝飾模式),Flyweight(享元模式),Proxy(代理模式);Command(命令模式),Interpreter(直譯器模式),Visitor(訪問者模式),Iterator(迭代子模式),Mediator(調停者模式),Memento(備忘錄模式),Observer(觀察者模式),State(狀態模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibility(責任鏈模式)。
所謂設計模式,就是一套被反覆使用的程式碼設計經驗的總結(情境中一個問題經過證實的一個解決方案)。使用設計模式是為了可重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性。設計模式使人們可以更加簡單方便的複用成功的設計和體系結構。將已證實的技術表述成設計模式也會使新系統開發者更加容易理解其設計思路。
【補充】設計模式並不是像某些地方吹噓的那樣是遙不可及的程式設計理念,說白了設計模式就是對面向物件的程式設計原則的實踐,面向物件的程式設計原則包括:
- 單一職責原則:一個類只做它該做的事情。(單一職責原則想表達的就是“高內聚”,寫程式碼最終極的原則只有六個字“高內聚、低耦合”,就如同葵花寶典或辟邪劍譜的中心思想就八個字“欲練此功必先自宮”,所謂的高內聚就是一個程式碼模組只完成一項功能,在面向物件中,如果只讓一個類完成它該做的事,而不涉及與它無關的領域就是踐行了高內聚的原則,這個類就只有單一職責。我們都知道一句話叫“因為專注,所以專業”,一個物件如果承擔太多的職責,那麼註定它什麼都做不好。這個世界上任何好的東西都有兩個特徵,一個是功能單一,好的相機絕對不是電視購物裡面賣的那種一個機器有一百多種功能的,它基本上只能照相;另一個是模組化,好的自行車是組裝車,從減震叉、剎車到變速器,所有的部件都是可以拆卸和重新組裝的,好的乒乓球拍也不是成品拍,一定是底板和膠皮可以拆分和自行組裝的,一個好的軟體系統,它裡面的每個功能模組也應該是可以輕易的拿到其他系統中使用的,這樣才能實現軟體複用的目標。)
- 開閉原則:軟體實體應當對擴充套件開放,對修改關閉。(在理想的狀態下,當我們需要為一個軟體系統增加新功能時,只需要從原來的系統派生出一些新類就可以,不需要修改原來的任何一行程式碼。要做到開閉有兩個要點:①抽象是關鍵,一個系統中如果沒有抽象類或介面系統就沒有擴充套件點;②封裝可變性,將系統中的各種可變因素封裝到一個繼承結構中,如果多個可變因素混雜在一起,系統將變得複雜而換亂,如果不清楚如何封裝可變性,可以參考《設計模式精解》一書中對橋樑模式的講解的章節。)
- 依賴倒轉原則:面向介面程式設計。(該原則說得直白和具體一些就是宣告方法的引數型別、方法的返回型別、變數的引用型別時,儘可能使用抽象型別而不用具體型別,因為抽象型別可以被它的任何一個子型別所替代,請參考下面的里氏替換原則。)
- 里氏替換原則:任何時候都可以用子型別替換掉父型別。(關於里氏替換原則的描述,Barbara Liskov女士的描述比這個要複雜得多,但簡單的說就是能用父型別的地方就一定能使用子型別。里氏替換原則可以檢查繼承關係是否合理,如果一個繼承關係違背了里氏替換原則,那麼這個繼承關係一定是錯誤的,需要對程式碼進行重構。例如讓貓繼承狗,或者狗繼承貓,又或者讓正方形繼承長方形都是錯誤的繼承關係,因為你很容易找到違反里氏替換原則的場景。需要注意的是:子類一定是增加父類的能力而不是減少父類的能力,因為子類比父類的能力更多,把能力多的物件當成能力少的物件來用當然沒有任何問題。)
- 介面隔離原則:介面要小而專,絕不能大而全。(臃腫的介面是對介面的汙染,既然介面表示能力,那麼一個介面只應該描述一種能力,介面也應該是高度內聚的。例如,琴棋書畫就應該分別設計為四個介面,而不應設計成一個介面中的四個方法,因為如果設計成一個介面中的四個方法,那麼這個介面很難用,畢竟琴棋書畫四樣都精通的人還是少數,而如果設計成四個介面,會幾項就實現幾個介面,這樣的話每個介面被複用的可能性是很高的。Java中的介面代表能力、代表約定、代表角色,能否正確的使用介面一定是程式設計水平高低的重要標識。)
- 合成聚合複用原則:優先使用聚合或合成關係複用程式碼。(通過繼承來複用程式碼是面向物件程式設計中被濫用得最多的東西,因為所有的教科書都無一例外的對繼承進行了鼓吹從而誤導了初學者,類與類之間簡單的說有三種關係,IS-A關係、HAS-A關係、USE-A關係,分別代表繼承、關聯和依賴。其中,關聯關係根據其關聯的強度又可以進一步劃分為關聯、聚合和合成,但說白了都是HAS-A關係,合成聚合複用原則想表達的是優先考慮HAS-A關係而不是IS-A關係複用程式碼,原因嘛可以自己從百度上找到一萬個理由,需要說明的是,即使在Java的API中也有不少濫用繼承的例子,例如Properties類繼承了Hashtable類,Stack類繼承了Vector類,這些繼承明顯就是錯誤的,更好的做法是在Properties類中放置一個Hashtable型別的成員並且將其鍵和值都設定為字串來儲存資料,而Stack類的設計也應該是在Stack類中放一個Vector物件來儲存資料。記住:任何時候都不要繼承工具類,工具是可以擁有並可以使用的(HAS/USE),而不是拿來繼承的。)
- 迪米特法則:迪米特法則又叫最少知識原則,一個物件應當對其他物件有儘可能少的瞭解。(迪米特法則簡單的說就是如何做到“低耦合”,門面模式和調停者模式就是對迪米特法則的踐行。對於門面模式可以舉一個簡單的例子,你去一家公司洽談業務,你不需要了解這個公司內部是如何運作的,你甚至可以對這個公司一無所知,去的時候只需要找到公司入口處的前臺美女,告訴她們你要做什麼,她們會找到合適的人跟你接洽,前臺的美女就是公司這個系統的門面。再複雜的系統都可以為使用者提供一個簡單的門面,Java Web開發中作為前端控制器的Servlet或Filter不就是一個門面嗎,瀏覽器對伺服器的運作方式一無所知,但是通過前端控制器就能夠根據你的請求得到相應的服務。調停者模式也可以舉一個簡單的例子來說明,例如一臺計算機,CPU、記憶體、硬碟、顯示卡、音效卡各種裝置需要相互配合才能很好的工作,但是如果這些東西都直接連線到一起,計算機的佈線將異常複雜,在這種情況下,主機板作為一個調停者的身份出現,它將各個裝置連線在一起而不需要每個裝置之間直接交換資料,這樣就減小了系統的耦合度和複雜度。迪米特法則用通俗的話來將就是不要和陌生人打交道,如果真的需要,找一個自己的朋友,讓他替你和陌生人打交道。)
74、Java企業級開發中常用的設計模式有哪些?
答: 按照分層開發的觀點,可以將應用劃分為:表示層、業務邏輯層和持久層,每一層都有屬於自己類別的設計模式。
表示層設計模式:
1)Interceptor Filter:攔截過濾器,提供請求預處理和後處理的方案,可以對請求和響應進行過濾。
2)Front Controller:通過中央控制器提供請求管理和處理,管理內容讀取、安全性、檢視管理和導航等功能。Struts 2中的StrutsPrepareAndExecuteFilter、Spring MVC中的DispatcherServlet都是前端控制器,後者如下圖所示:
3)View Helper:檢視幫助器,負責將顯示邏輯和業務邏輯分開。顯示的部分放在檢視元件中,業務邏輯程式碼放在幫助器中,典型的功能是內容讀取、驗證與適配。
4)Composite View:複合檢視。
業務邏輯層設計模式:
1)Business Delegate:業務委託,減少表示層和業務邏輯層之間的耦合。
2)Value Object:值物件,解決層之間交換資料的開銷問題。
3)Session Façade:會話門面,隱藏業務邏輯元件的細節,集中工作流程。
4)Value Object Assembler:靈活的組裝不同的值物件
5)Value List Handler:提供執行查詢和處理結果的解決方案,還可以快取查詢結果,從而達到提升效能的目的。
6)Service Locator:服務定位器,可以查詢、建立和定位服務工廠,封裝其實現細節,減少複雜性,提供單個控制點,通過快取提高效能。
持久層設計模式:
1)Data Access Object:資料訪問物件,以面向物件的方式完成對資料的增刪改查。
【補充】如果想深入的瞭解Java企業級應用的設計模式和架構模式,可以參考這些書籍: 《Pro Java EE Spring Patterns》、《POJO in Action》、《Patterns of Enterprise Application Architecture》。
75、你在開發中都用到了那些設計模式?用在什麼場合?
答:面試被問到關於設計模式的知識時,可以揀最常用的作答,例如:
1)工廠模式:工廠類可以根據條件生成不同的子類例項,這些子類有一個公共的抽象父類並且實現了相同的方法,但是這些方法針對不同的資料進行了不同的操作(多型方法)。當得到子類的例項後,開發人員可以呼叫基類中的方法而不必考慮到底返回的是哪一個子類的例項。
2)代理模式:給一個物件提供一個代理物件,並由代理物件控制原物件的引用。實際開發中,按照使用目的的不同,代理可以分為:遠端代理、虛擬代理、保護代理、Cache代理、防火牆代理、同步化代理、智慧引用代理。
3)介面卡模式:把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起使用的類能夠一起工作。
4)模板方法模式:提供一個抽象類,將部分邏輯以具體方法或構造器的形式實現,然後宣告一些抽象方法來迫使子類實現剩餘的邏輯。不同的子類可以以不同的方式實現這些抽象方法(多型實現),從而實現不同的業務邏輯。
除此之外,還可以講講上面提到的門面模式、橋樑模式、單例模式、裝潢模式(Collections工具類裡面的synchronizedXXX方法把一個執行緒不安全的容器變成執行緒安全容器就是對裝潢模式的應用,而Java IO裡面的過濾流(有的翻譯成處理流)也是應用裝潢模式的經典例子)等,反正原則就是揀自己最熟悉的用得最多的作答,以免言多必失。
76、XML 文件定義有幾種形式?它們之間有何本質區別?解析XML 文件有哪幾種方式?
答:XML文件定義分為DTD和Schema兩種形式;其本質區別在於Schema本身也是一個XML檔案,可以被XML解析器解析。對XML的解析主要有DOM(文件物件模型)、SAX、StAX(JDK 1.6中引入的新的解析XML的方式,Streaming API for XML) 等,其中DOM處理大型檔案時其效能下降的非常厲害,這個問題是由DOM 的樹結構所造成的,這種結構佔用的記憶體較多,而且DOM 必須在解析檔案之前把整個文件裝入記憶體,適合對XML 的隨機訪問(典型的用空間換取時間的策略);SAX是事件驅動型的XML解析方式,它順序讀取XML檔案,不需要一次全部裝載整個檔案。當遇到像檔案開頭,文件結束,或者標籤開頭與標籤結束時,它會觸發一個事件,使用者通過在其回撥事件中寫入處理程式碼來處理XML檔案,適合對XML 的順序訪問;如其名稱所暗示的那樣,StAX把重點放在流上。實際上,StAX與其他方法的區別就在於應用程式能夠把XML作為一個事件流來處理。將XML作為一組事件來處理的想法並不新穎(事實上 SAX 已經提出來了),但不同之處在於StAX允許應用程式程式碼把這些事件逐個拉出來,而不用提供在解析器方便時從解析器中接收事件的處理程式。
77、你在專案中哪些地方用到了XML?
答:XML的主要作用有兩個方面:資料交換(曾經被稱為業界資料交換的事實標準,現在此項功能在很多時候都被JSON取代)和資訊配置。在做資料交換時,XML將資料用標籤組裝成起來,然後壓縮打包加密後通過網路傳送給接收者,接收解密與解壓縮後再從XML檔案中還原相關資訊進行處理。目前很多軟體都使用XML來儲存配置資訊,很多專案中我們通常也會將作為配置的硬程式碼(hard code)寫在XML檔案中,Java的很多框架也是這麼做的。
78、在進行資料庫程式設計時,連線池有什麼作用?
答:由於建立連線和釋放連線都有很大的開銷(尤其是資料庫伺服器不在本地時,每次建立連線都需要進行TCP的三次握手,再加上網路延遲,造成的開銷是不可忽視的),為了提升系統訪問資料庫的效能,可以事先建立若干連線置於連線池中,需要時直接從連線池獲取,使用結束時歸還連線池而不必關閉連線,從而避免頻繁建立和釋放連線所造成的開銷,這是典型的用空間換取時間的策略(浪費了空間儲存連線,但節省了建立和釋放連線的時間)。池化技術在Java開發中是很常見的,在使用執行緒時建立執行緒池的道理與此相同。基於Java的開源資料庫連線池主要有: C3P0、Proxool、DBCP、BoneCP、Druid等。
【補充】在計算機系統中時間和空間是不可調和的矛盾,理解這一點對設計滿足效能要求的演算法是至關重要的。大型網站效能優化的一個關鍵就是使用快取,而快取跟上面講的連線池道理非常類似,也是使用空間換時間的策略。可以將熱點資料置於快取中,當用戶查詢這些資料時可以直接從快取中得到,這無論如何也快過去資料庫中查詢。當然,快取的置換策略等也會對系統性能產生重要影響,對於這個問題的討論已經超出了這裡要闡述的範圍。
79、什麼是DAO模式?
答:DAO(DataAccess Object)顧名思義是一個為資料庫或其他持久化機制提供了抽象介面的物件,在不暴露資料庫實現細節的前提下提供了各種資料操作。為了建立一個健壯的Java EE應用,應該將所有對資料來源的訪問操作進行抽象化後封裝在一個公共API中。用程式設計語言來說,就是建立一個介面,介面中定義了此應用程式中將會用到的所有事務方法。在這個應用程式中,當需要和資料來源進行互動的時候則使用這個介面,並且編寫一個單獨的類來實現這個介面,在邏輯上該類對應一個特定的資料儲存。DAO模式實際上包含了兩個模式,一是Data Accessor(資料訪問器),二是Data Object(資料物件),前者要解決如何訪問資料的問題,而後者要解決的是如何用物件封裝資料。
80、什麼是ORM?
答:物件關係對映(Object-Relational Mapping,簡稱ORM)是一種為了解決程式的面向物件模型與資料庫的關係模型互不匹配問題的技術;簡單的說,ORM 是通過使用描述物件和資料庫之間對映的元資料(可以用XML或者是註解),將Java程式中的物件自動持久化到關係資料庫中或者將關係資料庫表中的行轉換成Java物件,其本質上就是將資料從一種形式轉換到另外一種形式。
81、JDBC中如何進行事務處理?
答:Connection提供了事務處理的方法,通過呼叫setAutoCommit(false)可以設定手動提交事務;當事務完成後用commit()顯式提交事務;如果在事務處理過程中發生異常則通過rollback()進行事務回滾。除此之外,較新的JDBC標準還引入了Savepoint(儲存點)的概念,允許事務回滾到指定的儲存點。
82、 事務的ACID是指什麼?
答:
1)原子性(Atomic):事務中各項操作,要麼全做要麼全不做,任何一項操作的失敗都會導致整個事務的失敗;
2)一致性(Consistent):事務結束後系統狀態是一致的;
3)隔離性(Isolated):併發執行的事務彼此無法看到對方的中間狀態;
4)永續性(Durable):事務完成後所做的改動都會被持久化,即使發生災難性的失敗。通過日誌和同步備份可以在故障發生後重建資料。
【補充】關於事務,在面試中被問到的概率是很高的,可以問的問題也是很多的。首先需要知道的是,只有存在併發資料訪問時才需要事務。當多個事務訪問同一資料時,可能會存在5類問題,包括3類資料讀取問題(髒讀、不可重複讀和幻讀)和2類資料更新問題(第1類丟失更新和第2類丟失更新)。
- 髒讀(Dirty Read):A事務讀取B事務尚未提交的資料並在此基礎上操作,而B事務執行回滾,那麼A讀取到的資料就是髒資料。
時間 |
轉賬事務A |
取款事務B |
T1 |
|
開始事務 |
T2 |
開始事務 |
|
T3 |
|
查詢賬戶餘額為1000元 |
T4 |
|
取出500元餘額修改為500元 |
T5 |
查詢賬戶餘額為500元(髒讀) |
|
T6 |
|
撤銷事務餘額恢復為1000元 |
T7 |
匯入100元把餘額修改為600元 |
|
T8 |
提交事務 |
|
- 不可重複讀(Unrepeatable Read):事務A重新讀取前面讀取過的資料,發現該資料已經被另一個已提交的事務B修改過了。
時間 |
轉賬事務A |
取款事務B |
T1 |
|
開始事務 |
T2 |
開始事務 |
|
T3 |
|
查詢賬戶餘額為1000元 |
T4 |
查詢賬戶餘額為1000元 |
|
T5 |
|
取出100元修改餘額為900元 |
T6 |
|
提交事務 |
T7 |
查詢賬戶餘額為900元(不可重複讀) |
|
- 幻讀(Phantom Read):事務A重新執行一個查詢,返回一系列符合查詢條件的行,發現其中插入了被事務B提交的行。
時間 |
統計金額事務A |
轉賬事務B |
T1 |
|
開始事務 |
T2 |
開始事務 |
|
T3 |
統計總存款為10000元 |
|
T4 |
|
新增一個存款賬戶存入100元 |
T5 |
|
提交事務 |
T6 |
再次統計總存款為10100元(幻讀) |
|
- 第1類丟失更新:事務A撤銷時,把已經提交的事務B的更新資料覆蓋了。
時間 |
取款事務A |
轉賬事務B |
T1 |
開始事務 |
|
T2 |
|
開始事務 |
T3 |
查詢賬戶餘額為1000元 |
|
T4 |
|
查詢賬戶餘額為1000元 |
T5 |
|
匯入100元修改餘額為1100元 |
T6 |
|
提交事務 |
T7 |
取出100元將餘額修改為900元 |
|
T8 |
撤銷事務 |
|
T9 |
餘額恢復為1000元(丟失更新) |
|
- 第2類丟失更新:事務A覆蓋事務B已經提交的資料,造成事務B所做的操作丟失。
時間 |
轉賬事務A |
取款事務B |
T1 |
|
開始事務 |
T2 |
開始事務 |
|
T3 |
|
查詢賬戶餘額為1000元 |
T4 |
查詢賬戶餘額為1000元 |
|
T5 |
|
取出100元將餘額修改為900元 |
T6 |
|
提交事務 |
T7 |
匯入100元將餘額修改為1100元 |
|
T8 |
提交事務 |
|
T9 |
查詢賬戶餘額為1100元(丟失更新) |
|
資料併發訪問所產生的問題,在有些場景下可能是允許的,但是有些場景下可能就是致命的,資料庫通常會通過鎖機制來解決資料併發訪問問題,按鎖定物件不同可以分為表級鎖和行級鎖;按併發事務鎖定關係可以分為共享鎖和獨佔鎖,具體的內容大家可以自行查閱資料進行了解。
直接使用鎖是非常麻煩的,為此資料庫為使用者提供了自動鎖機制,只要使用者指定會話的事務隔離級別,資料庫就會通過分析SQL語句然後為事務訪問的資源加上合適的鎖,此外,資料庫還會維護這些鎖通過各種手段提高系統的效能,這些對使用者來說都是透明的(就是說你不用理解,事實上我確實也不知道)。ANSI/ISO SQL 92標準定義了4個等級的事務隔離級別,如下表所示:
隔離級別 |
髒讀 |
不可重複讀 |
幻讀 |
第一類丟失更新 |
第二類丟失更新 |
READ UNCOMMITED |
允許 |
允許 |
允許 |
不允許 |
允許 |
READ COMMITTED |
不允許 |
允許 |
允許 |
不允許 |
允許 |
REPEATABLE READ |
不允許 |
不允許 |
允許 |
不允許 |
不允許 |
SERIALIZABLE |
不允許 |
不允許 |
不允許 |
不允許 |
不允許 |
需要說明的是,事務隔離級別和資料訪問的併發性是對立的,事務隔離級別越高併發性就越差。所以要根據具體的應用來確定合適的事務隔離級別,這個地方沒有萬能的原則。
83、Statement和PreparedStatement有什麼區別?哪個效能更好?
答: 與Statement相比,①PreparedStatement介面代表預編譯的語句,它主要的優勢在於可以減少SQL的編譯錯誤並增加SQL的安全性(減少SQL注射攻擊的可能性);②PreparedStatement中的SQL語句是可以帶引數的;③當批量處理SQL時或頻繁執行相同的查詢時,PreparedStatement有明顯的效能上的優勢,由於資料庫可以將編譯優化後的SQL語句快取起來,下次執行相同語句時就會很快。
【補充】為了提供對儲存過程的呼叫,JDBC API中還提供了CallableStatement介面。儲存過程(Stored Procedure)是資料庫系統中,一組為了完成特定功能的SQL語句的集合,經編譯後儲存在資料庫中,使用者通過指定儲存過程的名字並給出引數(如果該儲存過程帶有引數)來執行它。雖然呼叫儲存過程會帶來網路開銷、安全性、效能上的好處,但是存在如果底層資料庫發生遷移時就會有很多麻煩,因為每種資料庫的儲存過程在書寫上存在不少的差別。
84、使用JDBC操作資料庫時,如何提升讀取資料的效能?如何提升更新資料的效能?
答:要提升讀取資料的效能,可以指定通過結果集(ResultSet)物件指定每次抓取資料的大小(fetch size);要提升更新資料的效能可以使用PreparedStatement語句構建批處理(batch)。
85、JDBC能否處理Blob和Clob?
答: Blob是指二進位制大物件(Binary Large Object),而Clob是指大字元物件(Character Large Objec),因此其中Blob是為儲存大的二進位制資料而設計的,而Clob是為儲存大的文字資料而設計的。JDBC的PreparedStatement和ResultSet都提供了相應的方法來支援Blob和Clob操作。下面的程式碼展示瞭如何使用JDBC操作LOB:
我使用的資料庫是MySQL,建立一個張有三個欄位的使用者表,包括編號(id)、姓名(name)和照片(photo),建表語句如下:
-
create
table tb_user
-
(
-
id
int primary
key auto_increment,
-
name
varchar(
20)
unique
not
null,
-
photo longblob
-
);
下面的Java程式碼向資料庫中插入一條記錄:
-
package com.lovo.demo;
-
-
import java.io.FileInputStream;
-
import java.io.IOException;
-
import java.io.InputStream;
-
import java.sql.Connection;
-
import java.sql.DriverManager;
-
import java.sql.PreparedStatement;
-
import java.sql.SQLException;
-
-
class JdbcLobTest {
-
-
public static void main(String[] args) {
-
Connection con =
null;
-
try {
-
// 1. 載入驅動(Java6以上版本可以省略)
-
Class.forName(
"com.mysql.jdbc.Driver");
-
// 2. 建立連線
-
con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test",
"root",
"123456");
-
// 3. 建立語句物件
-
PreparedStatement ps = con.prepareStatement(
"insert into tb_user values (default, ?, ?)");
-
ps.setString(
1,
"駱昊");
// 將SQL語句中第一個佔位符換成字串
-
try (InputStream in =
new FileInputStream(
"test.jpg")) {
// Java 7的TWR
-
ps.setBinaryStream(
2, in);
// 將SQL語句中第二個佔位符換成二進位制流
-
// 4. 發出SQL語句獲得受影響行數
-
System.out.println(ps.executeUpdate() ==
1 ?
"插入成功" :
"插入失敗");
-
}
catch(IOException e) {
-
System.out.println(
"讀取照片失敗!");
-
}
-
}
catch (ClassNotFoundException | SQLException e) {
// Java 7的多異常捕獲
-
e.printStackTrace();
-
}
finally {
// 釋放外部資源的程式碼都應當放在finally中保證其能夠得到執行
-
try {
-
if(con !=
null && !con.isClosed()) {
-
con.close();
// 5. 釋放資料庫連線
-
con =
null;
// 指示垃圾回收器可以回收該物件
-
}
-
}
catch (SQLException e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
}
分享一下我的偶像大神的人工智慧教程!http://blog.csdn.net/jiangjunshow