Sql的優化原則2:
1、只要能滿足你的需求,應盡可能使用更小的數據類型:例如使用MEDIUMINT代替INT
2、盡量把所有的列設置為NOT NULL,如果你要保存NULL,手動去設置它,而不是把它設為默認值。
3、盡量少用VARCHAR、TEXT、BLOB類型
4、如果你的數據只有你所知的少量的幾個。最好使用ENUM類型
5、正如graymice所講的那樣,建立索引。
以下是我做的一個實驗,可以發現索引能極大地提高查詢的效率:
我有一個會員信息表users,里邊有37365條用戶記錄:
在不加索引的時候進行查詢:
sql語句A:
select * from users where username like ’%許%’;
在Mysql-Front中的8次查詢時長為:1.40,0.54,0.54,0.54,0.53,0.55,0.54 共找到960條記錄
sql語句B:
select * from users where username like ’許%’;
在Mysql-Front中的8次查詢時長為:0.53,0.53,0.53,0.54,0.53,0.53,0.54,0.54 共找到836條記錄
sql語句C:
select * from users where username like ’%許’;
在Mysql-Front中的8次查詢時長為:0.51,0.51,0.52,0.52,0.51,0.51,0.52,0.51 共找到7條記錄
為username列添加索引:
create index usernameindex on users(username(6));
再次查詢:
sql語句A:
select * from users where username like ’%許%’;
在Mysql-Front中的8次查詢時長為:0.35,0.34,0.34,0.35,0.34,0.34,0.35,0.34 共找到960條記錄
sql語句B:
select * from users where username like ’許%’;
在Mysql-Front中的8次查詢時長為:0.06,0.07,0.07,0.07,0.07,0.07,0.06,0.06 共找到836條記錄
sql語句C:
select * from users where username like ’%許’;
在Mysql-Front中的8次查詢時長為:0.32,0.31,0.31,0.32,0.31,0.32,0.31,0.31 共找到7條記錄
在實驗過程中,我沒有另開任何程序,以上的數據說明在單表查詢中,建立索引的可以極大地提高查詢速度。
另外要說的是如果建立了索引,對于like ’許%’類型的查詢,速度提升是最明顯的。因此,我們在寫sql語句的時候也盡量采用這種方式查詢。
對于多表查詢我們的優化原則是:
盡量將索引建立在:left join on/right join on ... +條件,的條件語句中所涉及的字段上。
多表查詢比單表查詢更能體現索引的優勢。
6、索引的建立原則:
如果一列的中數據的前綴重復值很少,我們最好就只索引這個前綴。Mysql支持這種索引。我在上面用到的索引方法就是對username最左邊的6個字符進行索引。索引越短,占用的
磁盤空間越少,在檢索過程中花的時間也越少。這方法可以對最多左255個字符進行索引。
在很多場合,我們可以給建立多列數據建立索引。
索引應該建立在查詢條件中進行比較的字段上,而不是建立在我們要找出來并且顯示的字段上
7、限制索引的使用的避歸。
7.1 IN、OR子句常會使用工作表,使索引失效。
如果不產生大量重復值,可以考慮把子句拆開。拆開的子句中應該包含索引。這句話怎么理解決,請舉個例子
例子如下:
如果在fields1和fields2上同時建立了索引,fields1為主索引
以下sql會用到索引
select * from tablename1 where fields1=’value1’ and fields2=’value2’
以下sql不會用到索引
select * from tablename1 where fields1=’value1’ or fields2=’value2’
7.2 使用IS NULL 或IS NOT NULL
使用IS NULL 或IS NOT NULL同樣會限制索引的使用。因為NULL值并沒有被定義。在SQL語句中使用NULL會有很多的麻煩。因此建議開 發人員在建表時,把需要索引的列設成NOT NULL。如果被索引的列在某些行中存在NULL值,就不會使用這個索引(除非索引是一個位圖索引,關于位圖索引在稍后在詳細討論)。
7.3 使用函數
如果不使用基于函數的索引,那么在SQL語句的WHERE子句中對存在索引的列使用函數時,會使優化器忽略掉這些索引。下面的查詢不會使用索引(只要它不是基于函數的索引)
select empno,ename,deptno
from emp
where trunc(hiredate)='01-MAY-81';
把上面的語句改成下面的語句,這樣就可以通過索引進行查找。
select empno,ename,deptno
from emp
where hiredate<(to_date('01-MAY-81')+0.9999);
7.4 比較不匹配的數據類型
比較不匹配的數據類型也是比較難于發現的性能問題之一。注意下面查詢的例子,account_number是一個VARCHAR2類型,在account_number字段上有索引。下面的語句將執行全表掃描。
select bank_name,address,city,state,zip
from banks
where account_number = 990354;
Oracle可以自動把where子句變成to_number(account_number)=990354,這樣就限制了索引的使用,改成下面的查詢就可以使用索引:
select bank_name,address,city,state,zip
from banks
where account_number ='990354';
特別注意:不匹配的數據類型之間比較會讓Oracle自動限制索引的使用,即便對這個查詢執行Explain Plan也不能讓您明白為什么做了一 次“全表掃描”。
補充:
1.索引帶來查詢上的速度的大大提升,但索引也占用了額外的硬盤空間(當然現在一般硬盤空間不成問題),而且往表中插入新記錄時索引也要隨著更新這也需要一定時間.
有些表如果經常insert,而較少select,就不用加索引了.不然每次寫入數據都要重新改寫索引,花費時間;
這個視實際情況而定,通常情況下索引是必需的.
2.我在對查詢效率有懷疑的時候,一般是直接用Mysql的Explain來跟蹤查詢情況.
你用Mysql-Front是通過時長來比較,我覺得如果從查詢時掃描字段的次數來比較更精確一些.
------------------------------------
另:
----------------------------------
1.把某個字段重新生氣序列(從1到n):
DECLARE @i int
Set @i = 0
Update Table1 Set @i = @i + 1,Field1 = @i
2.按成績排名次
Update 成績表
Set a.名次 = (
Select Count(*) + 1
From 成績表 b
Where a.總成績 < b.總成績
)
From 成績表 a
3.查詢外部數據庫
Select a.*
From OpenRowSet('Microsoft.Jet.OLEDB.4.0','c:\test.mdb';'admin';'',Table1) a
4.查詢Excel文件
Select *
From OpenDataSource('Microsoft.Jet.OLEDB.4.0','Data Source="c:\test.xls";User ID=Admin;Password=;Extended properties=Excel 8.0')...Sheet1$
5.在查詢中指定排序規則
Select * From Table1 Order By Field1 COLLATE Chinese_PRC_BIN
為什么要指定排序規則呢?參見:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1633985
例,檢查數據庫中的Pub_Users表中是否存在指定的用戶:
Select Count(*) From Pub_Users Where [UserName]='admin' And [PassWord]='aaa' COLLATE Chinese_PRC_BIN
默認比較是不區分大小寫的,如果不加COLLATE Chinese_PRC_BIN,那么密碼aaa與AAA是等效的,這當然與實際不符.注意的是,每個條件都要指定排序規則,上例中用戶名就不區分大小寫.
6.Order By的一個小技巧
Order By可以指定列序而不用指定列名,在下面的例子里說明它的用處(注意,第三列未指定別名)
Select a.ID,a.Name,(Select Count(*) From TableB b Where a.ID=b.PID) From TableA a Order By 3
student.setUsername(addStudentForm.getUsername());
student.setPassword(addStudentForm.getPassword());
student.setSex(addStudentForm.getSex());
try {
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");//固定的格式
Date date = sd.parse(birth);//將字符轉化為DATE類型
student.setBirthday(date);
} catch (ParseException e) {
System.out.println("插入失敗插入失敗插入失敗插入失敗插入失敗");
}
student.setGrade(addStudentForm.getGragde());
personDAO.insertStudentOrTeacher(student);
return mapping.findForward("ok");
}
/*************************************************************************/
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date=new Date();
String toLocaleString = date.toLocaleString();
article.setSavetime(sd.parse(toLocaleString));
/*************************************************
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date=new Date();
String dd=sd.format(date);
在講外連接之前,先舉例介紹內連接,也就是一般的相等連接。
select * from a, b where a.id = b.id;
對于外連接,Oracle中可以使用“(+)”來表示,9i可以使用LEFT/RIGHT/FULL OUTER JOIN,下面將配合實例一一介紹。
1. LEFT OUTER JOIN:左外關聯
SELECT e.last_name, e.department_id, d.department_name
FROM employees e
LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id);
等價于
SELECT e.last_name, e.department_id, d.department_name
FROM employees e, departments d
WHERE e.department_id=d.department_id(+);
結果為:所有員工及對應部門的記錄,包括沒有對應部門編號department_id的員工記錄。
2. RIGHT OUTER JOIN:右外關聯
SELECT e.last_name, e.department_id, d.department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON (e.department_id = d.department_id);
等價于
SELECT e.last_name, e.department_id, d.department_name
FROM employees e, departments d
WHERE e.department_id(+)=d.department_id;
結果為:所有員工及對應部門的記錄,包括沒有任何員工的部門記錄。
3. FULL OUTER JOIN:全外關聯
SELECT e.last_name, e.department_id, d.department_name
FROM employees e
FULL OUTER JOIN departments d
ON (e.department_id = d.department_id);
結果為:所有員工及對應部門的記錄,包括沒有對應部門編號department_id的員工記錄和沒有任何員工的部門記錄。
1.磁盤柜上有14塊73G的磁盤, 數據庫為200G 大小包括日志文件,如何設置磁盤(要說明這14磁盤是怎么用的)?
這個問題應該是考察硬件知識和數據庫物理部署。
首先需要知道這些磁盤是否要用于存放數據庫備份文件和數據庫性能(讀/寫)要求。來決定raid的級別。
1)、如果偏重于性能考慮,而且不用存放數據庫備份文件的話,考慮使用raid0+1,這樣可使用的磁盤容量為:14*73*50%=511G。
2)、如果讀/寫性能要求不高,而且還比較摳門的話,可以考慮raid5,這樣可使用的磁盤容量為:13*73=949G。
至于如何使用應該是說數據庫物理文件的部署。注意說出將tempdb,data file,log file分開存放以減少I/O競爭即可。其實現在的條帶化磁盤一般都會自動將文件分存,人為的分布已經越來越不重要了。
2.有兩服務器群集,分別為node1和node2 現在要打win200系統補丁,打完后,要重新啟動,如何打補丁,不能影響用戶使用(要用群集的術語詳細說明)。
這個具體操作有點忘了。大致是:首先看哪個節點正在使用,通過節點IP(私有)訪問另一個空閑節點,為其打上補丁,然后在群集管理器中停止該節點(也可以用命令行方式),重新啟動。等到啟動完畢,將切換使用節點,為另一個節點打補丁。然后重新啟動。
3.有一個A 數據庫,分別復制到B和C B 要求 每次數據更新 也同時更新,C 每天更新一次就行,如何制定復制策略!
這個應該考察的是復制知識。
a->b
1)、如果使用SQL Server復制功能,那么讓a->b使用事務性復制方式(同步復制)。
2)、如果表不多,也可以自己寫觸發器,利用linkserver+distribute transaction。
a->c
1)、如果使用SQL Server復制功能,那么讓a->b使用快照復制方式,在某一時間點進行一次性復制。
2)、也可以自己寫bat,將a備份后,通過ftp傳輸備份介質,恢復c。(比較麻煩,不推薦)
4.有一個order 表,有90個字段,20個索引,15個復合索引,其中有3個索引字段超過10個,如何進行優化
這個問題問的比較沒水平。你不詳細說明這個表的使用方式(讀寫類的,還是幾乎是靜態表),就問人家怎么優化?!!還不如問問索引的分布訪問原理更好。
看得出他就想讓你說:那三個索引超過10個,B樹遍例效率很低,適當減少字段數目。如果是SQL2005,可以將選擇性不好的字段放在“索引附加字段”中,以保證索引覆蓋。而且SQL Server由于有鎖升級的毛病,可以考慮拆開表。
5.有一個數據庫200G大小,每天增加50M 允許用戶隨時訪問,制定備份策略(詳細說明)。
這種情況可以采用增量備份方式。每周日做一次全備份,周一到周六作增量備份(由于數據量較少,可以考慮每30分鐘增量備份一次)。這樣可以盡量減少性能消耗,而且如果transaction log丟失的情況下,可以保證最多丟失30分鐘數據。
6.管理50臺數據庫,日常工作是檢查數據庫作業是否完成,你該如何完成這項檢查工作?
這個比較簡單。在每臺機器上建立linkserver,然后在DBA管理服務器上做個分布式視圖,每次查詢該視圖,各個機器上的作業情況一目了然。分布式視圖寫法:
create view vw_job
as
select '機器一' as MName,* from linkserver1..sysjobactivity
union all
select '機器二' as MName,* from linkserver2..sysjobactivity
union all
select '機器三' as MName,* from linkserver3..sysjobactivity
7.自定義函數和存儲過程的區別是什么,什么情況下只能用自定義函數,什么情況下只能用存儲過程
這個應該是考察存儲過程編寫經驗。一般自定義函數主要用于其他sql中的調用,如:
select yourfunc(...) from table
這種情況下,一般只能通過函數實現。
存儲過程的功能要遠遠強于函數,例如動態執行sql(sp_executesql)的使用和一些特殊的功能,自定義函數中是不支持的,只能用存儲過程實現。
8.SQL 2005 的新特性是什么 ? 與oracle 有什么區別?
SQL 2005 的新特性一般都是和Oracle學的。
下面是當時被leimin逼著寫的,你可以做個參考:
一、數據庫設計方面
1、字段類型。
varchar(max)\nvarchar(max)類型的引入大大的提高了編程的效率,可以使用字符串函數對CLOB類型進行操作,這是一個亮點。但是這就引發了對varchar和char效率討論的老問題。到底如何分配varchar的數據,是否會出現大規模的碎片?是否碎片會引發效率問題?這都是需要進一步探討的東西。
varbinary(max)代替image也讓SQL Server的字段類型更加簡潔統一。
XML字段類型更好的解決了XML數據的操作。XQuery確實不錯,但是個人對其沒好感。(CSDN的開發者應該是相當的熟了!)
2、外鍵的級聯更能擴展
可能大部分的同行在設計OLTP系統的時候都不愿意建立外鍵,都是通過程序來控制父子數據的完整性。但是再開發調試階段和OLAP環境中,外鍵是可以建立的。新版本中加入了SET NULL 和 SET DEFAULT 屬性,能夠提供能好的級聯設置。
3、索引附加字段
這是一個不錯的新特性。雖然索引的附加字段沒有索引鍵值效率高,但是相對映射到數據表中效率還是提高了很多。我做過試驗,在我的實驗環境中會比映射到表中提高30%左右的效率。
4、計算字段的持久化
原來的計算字段其實和虛擬字段很像。只是管理方面好了而已,性能方面提高不多。但是SQL2005提供了計算字段的持久化,這就提高了查詢的性能,但是會加重insert和update的負擔。OLTP慎用。OLAP可以大規模使用。
5、分區表
分區表是個亮點!從分區表也能看出微軟要做大作強SQL Server的信心。資料很多,這里不詳細說。但是重點了解的是:現在的SQL Server2005的表,都是默認為分區表的。因為它要支持滑動窗口的這個特性。這種特性對歷史數據和實時數據的處理是很有幫助的。
但是需要注意的一點,也是我使用過程中發現的一個問題。在建立function->schema->table后,如果在現有的分區表上建立沒有顯式聲明的聚集索引時,分區表會自動變為非分區表。這一點很讓我納悶。如果你覺得我的非分區索引無法對起子分區,
你可以提醒我一下呀!沒有任何的提醒,直接就變成了非分區表。不知道這算不算一個bug。大家也可以試試。
分區表效率問題肯定是大家關心的問題。在我的試驗中,如果按照分區字段進行的查詢(過濾)效率會高于未分區表的相同語句。但是如果按照非分區字段進行查詢,效率會低于未分區表的相同語句。但是隨著數據量的增大,這種成本差距會逐漸減小,趨于相等。(500萬數量級只相差10%左右)
6、CLR類型
微軟對CLR作了大篇幅的宣傳,這是因為數據庫產品終于融入.net體系中。最開始我們也是狂喜,感覺對象數據庫的一些概念可以實現了。但是作了些試驗,發現使用CLR的存儲過程或函數在達到一定的閥值的時候,系統性能會呈指數級下滑!這是非常危險的!只使用幾個可能沒有問題,當一旦大規模使用會造成嚴重的系統性能問題!
其實可以做一下類比,Oracle等數據庫產品老早就支持了java編程,而且提供了java池參數作為用戶配置接口。但是現在有哪些系統大批使用了java存儲過程?!連Oracle自己的應用都不用為什么?!還不是性能有問題!否則面向對象的數據庫早就實現了!
建議使用CLR的地方一般是和應用的復雜程度或操作系統環境有很高的耦合度的場景。如你想構建復雜的算法,并且用到了大量的指針和高級數據模型。或者是要和操作系統進行Socket通訊的場景。否則建議慎重!
7、索引視圖
索引視圖2k就有。但是2005對其效率作了一些改進但是schema.viewname的作用域真是太限制了它的應用面。還有一大堆的環境參數和種種限制都讓人對它有點卻步。
8、語句和事務快照
語句級快照和事務級快照終于為SQL Server的并發性能帶來了突破。個人感覺語句級快照大家應該應用。事務級快照,如果是高并發系統還要慎用。如果一個用戶總是被提示修改不成功要求重試時,會殺人的!
9、數據庫快照
原理很簡單,對要求長時間計算某一時間點的報表生成和防用戶操作錯誤很有幫助。但是比起Oracle10g的閃回技術還是細粒度不夠。可惜!
10、Mirror
Mirror可以算是SQL Server的Data guard了。但是能不能被大伙用起來就不知道了。
二、開發方面
1、Ranking函數集
其中最有名的應該是row_number了。這個終于解決了用臨時表生成序列號的歷史,而且SQL Server2005的row_number比Oracle的更先進。因為它把Order by集成到了一起,不用像Oracle那樣還要用子查詢進行封裝。但是大家注意一點。如下面的例子:
select ROW_NUMBER() OVER (order by aa)
from tbl
order by bb
會先執行aa的排序,然后再進行bb的排序。
可能有的朋友會抱怨集成的order by,其實如果使用ranking函數,Order by是少不了的。如果擔心Order by會影響效率,可以為order by的字段建立聚集索引,查詢計劃會忽略order by 操作(因為本來就是排序的嘛)。
2、top
可以動態傳入參數,省卻了動態SQL的拼寫。
3、Apply
對遞歸類的樹遍歷很有幫助。
4、CTE
個人感覺這個真是太棒了!閱讀清晰,非常有時代感。
5、try/catch
代替了原來VB式的錯誤判斷。比Oracle高級不少。
6、pivot/unpivot
個人感覺沒有case直觀。而且默認的第三字段(還可能更多)作為group by字段很容易造成新手的錯誤。
三、DBA管理方面
1、數據庫級觸發器
記得在最開始使用2k的時候就要用到這個功能,可惜2k沒有,現在有了作解決方案的朋友會很高興吧。
2、多加的系統視圖和實時系統信息
這些東西對DBA挑優非常有幫助,但是感覺粒度還是不太細。
3、優化器的改進
一直以來個人感覺SQL Server的優化器要比Oracle的聰明。SQL2005的更是比2k聰明了不少。(有次作試驗發現有的語句在200萬級時還比50萬級的相同語句要快show_text的一些提示沒有找到解釋。一直在奇怪。)
論壇例子:
http://community.csdn.net/Expert/topic/4543/4543718.xml?temp=.405987
4、profiler的新事件觀察
這一點很好的加強了profiler的功能。但是提到profiler提醒大家注意一點。windows2003要安裝sp1補丁才能啟動profiler。否則點擊沒有反應。
5、sqlcmd
習慣敲命令行的朋友可能會爽一些。但是功能有限。適合機器跑不動SQL Server Management Studio的朋友使用。
四、遺憾
1、登陸的控制
始終遺憾SQL Server的登陸無法分配CPU/內存占用等指標數。如果你的SQL Server給別人分配了一個只可以讀幾個表的權限,而這個家伙瘋狂的死循環進行連接查詢,會給你的系統帶來很大的負擔。而SQL Server如果能像Oracle一樣可以為登陸分配如:5%的cpu,10%的內存。就可以解決這個漏洞。
2、數據庫物理框架沒有變動
undo和redo都放在數據庫得transaction中,個人感覺是個敗筆。如果說我們在設計數據庫的時候考慮分多個數據庫,可能能在一定程度上避免I/O效率問題。但是同樣會為索引視圖等應用帶來麻煩。看看行級和事務級的快照數據放在tempdb中,就能感覺到目前架構的尷尬。
3、還是沒有邏輯備份
備份方面可能還是一個老大難的問題。不能單獨備份幾個表總是感覺不爽。靈活備份的問題不知道什么時候才能解決。
4、SSIS(DTS)太復雜了
SQL Server的異構移植功能個人感覺最好了。(如果對比過SQL Server的鏈接服務器和Oracle的透明網關的朋友會發現SQL Server的sp_addlinkedserver(openquery)異構數據庫系列比Oracle真是強太多了。)
以前的DTS輕盈簡單。但是現在的SSIS雖然功能強大了很多,但是總是讓人感覺太麻煩。看看論壇中詢問SSIS的貼子就知道。做的功能太強大了,往往會有很多用戶不會用了。
與oracle 有什么區別?
這個問題相當變態!不同點我能給他講一天!首先名字就不一樣嘛!! :)
9.DBA 的品質應該有哪些,你有哪些, 有什么欠缺的?
略
10。如果想配置SQL Mail 應該在服務器安裝哪些軟件!
需要哪些軟件?安個outlook express就可以了。sql server提供接口存儲過程,非常簡單。
寫個過濾器類:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class Filter1 implements Filter {
private FilterConfig filterConfig=null;
private String encoding=null;
public void init(FilterConfig filterConfig) throws ServletException {
// TODO 自動生成方法存根
this.filterConfig=filterConfig;
this.encoding=this.filterConfig.getInitParameter("encoding");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// TODO 自動生成方法存根
if(encoding!=null)
{
request.setCharacterEncoding(encoding);
}
chain.doFilter(request, response);
}
public void destroy() {
// TODO 自動生成方法存根
this.encoding=null;
this.filterConfig=null;
}
}
再在項目的web.xml中配置如下:
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.tools.Filter1</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:所有的JSP頁面的類型均為<%@ page contentType="text/html; charset=UTF-8"%>
//////////////////////////////////////////////////////////////////////////////
方法二:
/////////////////////////////////////////////////////////////////////////
在struts中的可以重寫ActionServlet類的process方法
package tools;//包
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import org.apache.struts.action.ActionServlet;
public class MyActionServlet extends ActionServlet{
private static final long serialVersionUID = 6864646927139403188L;
public MyActionServlet()
{
}
protected void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
super.process(request, response);
}
}
再在項目的web.xml中
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>tools.MyActionServlet</servlet-class>/////////////根據自己的的MyActionSerclet所在的位置
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
注意:所有的JSP頁面的類型均為<%@ page contentType="text/html; charset=UTF-8"%>
1中方法=====================================================
要是數據庫是MYSQL還要在applicationContext.xml配置中加
<property name="url" value="jdbc:mysql://localhost:3306/j2ee?useUnicode=true&characterEncoding=UTF-8"></property>
2中方法.****************************************************
MYSQL 中的hibernate.cfg.xml在<session-factory>和</session-factory>之間加入這么一段:
<property name="connection.useUnicode">true</property>
<property name="connection.characterEncoding">UTF-8</property>
這樣一來,是可以解決亂碼問題。
///幾個重要的語句
String insertSql="insert into Product(name,price) values('"+name+"',"+price+")";//price 為整型
String updateSql="update Product set PName='"+name+"', PPrice="+price+" where PID='"+id+"'";
String sql="select * from Product where PName like '%"+key+"%'";
String sql = "delete t_user where userid="+userid;
JNDI方法一
/////////////////////////////////////////
記得導入6個.JAR包并在tomcat中的lib文件下也要導入這6個.JAR包
工具類
package util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import com.Admin;
/**
* @author wsq
* @version 1.0 07/10/20
*/
public class DBConnection {
private static Connection con = null;
private static Statement stmt = null;
private static ResultSet rs = null;
private static ArrayList<String[]> ArrayRs = null;
/**
*
* 創建數據源
*
* @return Connection
* @throws Exception
*/
public static synchronized Connection getConnection() throws Exception {
Context initCtx = new InitialContext(); // 從Context中lookup數據源。
DataSource ds = (DataSource) initCtx.lookup("java:comp/env/jdbc/data"); // jdbc/data為下面Resource的name屬性
return ds.getConnection();
}
/**
*
* 執行數據查詢操作
*
* @param sql
* @return ResultSet
*/
public static ArrayList executeQuery(String sql) {
try {
stmt = con.createStatement();
rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData(); // 獲取此 ResultSet 對象的列的編號、類型和屬性。
int numberOfColumns = rsmd.getColumnCount();// 返回此 ResultSetMetaData對象中的列數。
// 判斷是否為空
if (!ArrayRs.isEmpty()) {
ArrayRs.clear();
}
/*
* 將每條記錄寫入數組 將數組放在ArrayList里
*/
while (rs.next()) {
String[] strArrayTemp = new String[numberOfColumns];
for (int i = 0; i < numberOfColumns; i++) {
if (rs.getObject(i + 1) == null) {
strArrayTemp[i] = "";
} else {
strArrayTemp[i] = rs.getObject(i + 1).toString();// 以
// Java
// 編程語言中
// Object
// 的形式獲取此
// ResultSet
// 對象的當前行中指定列的值;
// 第一個列是1,第二個列是2,....
System.out.println(" test value " + strArrayTemp[i]);
}
}
ArrayRs.add(strArrayTemp);
}
System.out.println("executeQuery successfully!");
return (ArrayList) ArrayRs.clone();
} catch (SQLException ex) {
System.out.println("query error:" + ex.getMessage());
} finally {
DBConnection.close();
}
return ArrayRs;
}
/**
* @param executeInsert插入數據方法
* @return 插入條數是否成功(boolean)
*/
public static boolean executeInsert(String strSql) throws SQLException {
rs = null;
try {
con = DBConnection.getConnection();
stmt = con.createStatement();
con.setAutoCommit(true);
int i = stmt.executeUpdate(strSql);
if (i == 1) {
return (true);
}
} catch (Exception e) {
System.out.println("Insert error:" + e.getMessage());
} finally {
DBConnection.close();
}
return (false);
}
/**
* 執行數據更新操作
*
* @param sql
* @return 更新是否成功 (int)
* @throws Exception
*/
public static int executeUpdate(String sql) throws Exception {
int result = 0;
con = DBConnection.getConnection();
try {
Statement stmt = con.createStatement();
result = stmt.executeUpdate(sql);// 返回影響的行數
con.commit(); // 提交
} catch (SQLException ex) {
try {
con.rollback();// 回滾
} catch (SQLException e) {
System.out.println("update error:" + e.getMessage());
}
System.err.println(ex.getMessage());
} finally {
DBConnection.close();
}
return result;
}
/**
* @param executeDelete刪除數據方法
* @return 刪除數據數(int)
*/
public static int executeDelete(String strSql) throws SQLException {
rs = null;
int j = 0;
try {
con = DBConnection.getConnection();
stmt = con.createStatement();
con.setAutoCommit(false);
j = stmt.executeUpdate(strSql);
if (j > 0) {
con.commit();
} else {
con.rollback();
}
} catch (Exception e) {
System.out.println("Delete error:" + e.getMessage());
} finally {
DBConnection.close();
}
return j;
}
/**
*
* 關閉連接,將連接送回連接池
*
*/
public static void close() {
if (con != null) {
try {
con.close();
con = null;
} catch (SQLException ex) {
System.err.println(ex.getMessage());
}
}
}
}
在項目的...\WebRoot\META-INF下創建個context.xml或者在tomcat中的server.xml寫
<Context path="/jndi" docBase="jndi" debug="0" reloadable="true" crossContext="true">
<Resource name="jdbc/data" auth="Container" type="javax.sql.DataSource"
driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=dbs"
username="wsq" password="123" maxIdle="20" maxWait="5000"
maxActive="100" removeAbandoned="true"
removeAbandonedTimeout="60" logAbandoned="true"/>
</Context>
方法二
Struts(1.2)
/////////////////////////
連接池在struts-cionfig.xml中的配置(sql2000)
<data-sources>
<data-source type="org.apache.commons.dbcp.BasicDataSource" key="data'>
<set-property property="driverClassName"value="com.microsoft.jdbc.sqlserver.SQLServerDriver" />//記得要Name
<set-property property="url"value="jdbc:microsoft:sqlserver://localhost:1433;databasename=dbs" />
<set-property property="username" value="wsq" />//記得要name
<set-property property="password" value="123" />
<set-property property="maxActive" value="10" />
<set-property property="maxWait" value="5000" />
<set-property property="defaultAutoCommit" value="false" />//記得在false的情況(插入和更新時要con.commit)
<set-property property="defaultReadOnly" value="false" />
</data-source>
</data-sources>
/////////////////////////////////////////////////////////
輔助類
package tools;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
public class DBUtil {
Connection con=null;
ResultSet rs = null;
public DBUtil(DataSource dataSource)
{
try {
con=dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
}
////在數據庫中執行查詢操作
public ResultSet executeQuery(String sql) {
try {
Statement stmt = con.createStatement();
rs = stmt.executeQuery(sql);
}
catch(SQLException ex) {
ex.printStackTrace();
}
return rs;
}
// 在數據庫中執行數據更新的方法
public int executeUpdate(String sql) {
int result = 0;
try {
Statement stmt = con.createStatement();
//返回影響的行數
result = stmt.executeUpdate(sql);
}
catch(SQLException ex) {
try {
con.rollback(); //回滾
} catch (SQLException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
System.err.println(ex.getMessage());
}
return result;
}
// 關閉數據源
public void close(){
if(con!=null){
try{
con.close();
con = null;
}catch(SQLException ex) {
System.err.println(ex.getMessage());
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////
(不利用輔助類時)
在xxxAction.java中的execute()方法中
try{
DataSource dataSource=getDataSource(request,"data");//得到數據源
//得到數據源ServletContext context=servlet.getServletContext();
// DataSource dataSource=(DataSource) context.getAttribute("data");
Connetion con=dataSource.getConnection();
PreparedStatement pstm=con.prepareStatement("insert into userone (name,password) values(?,?)");
pstm.setString(1,name);
pstm.setString(2,password);
pstm.executUpadate();
con.commit();/////記得寫上(在插入或更新時一定要記得加上)正確是提交事務
} catch (SQLException e) {
con.rollback();//失敗時回滾
e.printStackTrace();
}
finally{
pstm.close();
con.close();
}
方法三(最原始的)直接連
**********************
1. MySQL(http://www.mysql.com)mm.mysql-2.0.2-bin.jar/
Class.forName( "org.gjt.mm.mysql.Driver" );
cn = DriverManager.getConnection(
"jdbc:mysql://MyDbComputerNameOrIP:3306/myDatabaseName", sUsr, sPwd );
2. PostgreSQL(http://www.de.postgresql.org)pgjdbc2.jar/
Class.forName( "org.postgresql.Driver" );
cn = DriverManager.getConnection(
"jdbc:postgresql://MyDbComputerNameOrIP/myDatabaseName", sUsr, sPwd );
3. Oracle(http://www.oracle.com/ip/deploy/database/oracle9i/)classes12.zip
Class.forName( "oracle.jdbc.driver.OracleDriver" );
cn = DriverManager.getConnection(
"jdbc:oracle:thin:@MyDbComputerNameOrIP:1521:ORCL", sUsr, sPwd );
4. Sybase(http://jtds.sourceforge.net)jconn2.jar/
Class.forName( "com.sybase.jdbc2.jdbc.SybDriver" );
cn = DriverManager.getConnection(
"jdbc:sybase:Tds:MyDbComputerNameOrIP:2638", sUsr, sPwd );
//(Default-Username/Password: "dba"/"sql")
5. Microsoft SQLServer(http://jtds.sourceforge.net/)
Class.forName( "net.sourceforge.jtds.jdbc.Driver" );
cn = DriverManager.getConnection(
"jdbc:jtds:sqlserver://MyDbComputerNameOrIP:1433/master", sUsr, sPwd );
6. Microsoft SQLServer(http://www.microsoft.com/)
Class.forName( "com.microsoft.jdbc.sqlserver.SQLServerDriver" );
cn = DriverManager.getConnection(
"jdbc:microsoft:sqlserver://localhost:1433;databaseName=dbs", sUsr, sPwd );
7. ODBC
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
Connection cn = DriverManager.getConnection( "jdbc:odbc:" + sDsn, sUsr, sPwd
);
select @@version 是查看你的MSSQL版本 看補丁打沒打
///////////////////////////////////////////////////////////////////////////////////
String insertSql="insert into Product values('"+id+"','"+name+"',"+price+")";
String updateSql="update Product set PName='"+name+"', PPrice="+price+" where PID='"+id+"'";
String sql="select * from Product where PName like '%"+key+"%'";
String sql = "delete t_user where userid="+userid;
////////////////////////////////////////////////////////