一個JDBC DAO封裝類
最近應項目要求,須要本身寫一個JDBC DAO的封裝類,可以高效穩定的提供數據庫操做服務,對數據庫的訪問及操做必須儘量的輕量級。我的認爲一個高效穩定的時實系統的架構和編碼規範應具有如下特色:html
* 源碼中儘可能少的new和儘可能多的staticjava
* 儘可能少的過濾器程序員
* 儘可能少的數據傳遞過程sql
* 儘可能少的數據轉換和儘可能多的泛型數據庫
* 直接使用Java數據庫API架構
* 使用數據庫鏈接池jsp
* 特別易用測試
基於以上考慮,實現了下面這個DAO類。此類將查詢出來的數據以List<Map<String Object>>的形式封裝並返回,HashMap表明數據行DataRow,HashMap的key(String)表明數據庫表中的字段名,value(Object)表明其值,在jsp頁面中使用list.get(int index)得到行,使用map.get(「字段名」)得到在數據庫表中該字段的值,好比得到第5行的userName得值:String userName = list.get(4).get(「userName」);。執行增刪改操做將返回int類型的值表示操做影響到的行數。網站
此類適合我的或小團隊用來開發實時系統或網站。使用此類,程序員必須熟知數據庫的設計,由於是要在jsp或servlet中直接寫sql語句的。也所以,此類不適合用來作大型企業級應用。ui
應用案例:
表設計(MySQL):
create
table
test(
test_id
int
auto_increment
primary
key
, #ID編號
test_title
varchar
(50)
not
null
, #標題
test_content
varchar
(500)
not
null
#內容
);
jsp顯示頁面
<%@ page language="java" import="java.util.*,access.DB" pageEncoding="UTF-8"%>
<
html
>
<
head
>
<
title
>測試</
title
>
<
meta
http-equiv
=
"content-type"
content
=
"text/html;charset=utf-8"
>
</
head
>
<
body
>
<%
String sql = "select * from test;";
List<
Map
<String, Object>> list = DB.query(sql);
if(list!=null && list.size()>0){
out.println("<
table
border
=
'1'
>");
out.println(" <
tr
>");
out.println(" <
th
>ID號</
th
>");
out.println(" <
th
>標題</
th
>");
out.println(" <
th
>內容</
th
>");
out.println(" </
tr
>");
for(Map<
String
, Object> row : list){
out.println(" <
tr
>");
out.println(" <
td
>"+row.get("test_id")+"</
td
>");
out.println(" <
td
>"+row.get("test_title")+"</
td
>");
out.println(" <
td
>"+row.get("test_content")+"</
td
>");
out.println(" </
tr
>");
}
out.println("</
table
>");
}
%>
</
body
>
</
html
>
數據庫控制訪問類DB.java:
package
access;
import
java.sql.*;
import
java.util.ArrayList;
import
java.util.HashMap;
import
java.util.List;
import
java.util.Map;
import
javax.naming.InitialContext;
import
javax.sql.DataSource;
/**
* 數據庫訪問操做類
*
* 說明:
* 本類共有7個方法,三個自服務方法(得到數據庫鏈接、關閉執行查詢操做鏈接、關閉執行更新操做鏈接)
* 四個數據庫操做執行的方法(不帶參數的更新、但參數的更新、不帶參數的查詢、帶參數的查詢)
*
* 查詢方法返回List<Map<String Object>>,表示查詢出的數據圖。控制端使用list.get(rowIndex).get("字段名")
* 獲取rowIndex行的表字段名的值。
*
* 更新方法返回int,表示執行後所影響的行數,使用該方法不該根據判斷返回的值來判定業務是否成功與否,只要此方
* 法不拋出異常均表示SQL語句已成功執行。爲何返回int而不採用返回boolean?簡單的說,由於執行更新,數據庫端
* 有可能返回0行數據被影響的狀況,好比刪除一個空表,將會返回0,在這裏0並不表示執行失敗,因此不能用來斷定業
* 務是否操做成功。爲了解釋這點,舉個比較詳細的例子:
* 假設有兩張表:商品表和商品類型表,假設在刪除商品類型時候要求同時刪除該商品類型下的商品數據,那麼通常的
* 咱們會在刪除商品類型以前先刪除該商品類型下的全部商品數據(這裏執行了兩個刪除動做)。若是有一天建立了一個
* 新的商品類別,但還沒來得及爲該商品類別添加商品數據,商品數據表是一張空表,但決策決定刪除該商品類別,那麼
* 在這種狀況下,執行刪除商品信息數據SQL語句定然順利,但定然獲得的是0行受影響,若是將0視爲業務執行失敗的話
* 就錯誤的了。因此此類的更新方法返回的值製做參考之用,不該用來斷定業務操做知否成功。很顯然例子中的業務操做
* 是成功的,因此此類的更新方法返回的都是int類型。
*
* 代碼示例:
* try{
* String sql="update table set field1 = ?,field2=? where id=?";
* List<Object> par = new ArrayList<Object>();
* par.add("field1 value");
* par.add("field2 value");
* par.add(1);
* DB.update(sql,par);//這裏無需根據判斷返回值來斷定是否執行成功
* }catch(Exception e){
* e.printStackTrace();
* }
* @author jsper.org
*
*/
public
class
DB {
/**
* 得到數據庫鏈接
*/
protected
static
Connection getConnection() {
Connection conn =
null
;
try
{
//JNDI鏈接池方式
InitialContext ctx =
new
InitialContext();
DataSource ds = (DataSource)ctx.lookup(
"java:comp/env/cjilziwomgkx"
);
conn = ds.getConnection();
}
catch
(Exception e) {
e.printStackTrace();
}
return
conn;
}
/**
* 關閉執行查詢操做的鏈接
*/
protected
static
void
closeConnection(ResultSet resultSet,
Statement statement, Connection connection) {
try
{
resultSet.close();
}
catch
(SQLException e) {
e.printStackTrace();
}
try
{
statement.close();
}
catch
(SQLException e) {
e.printStackTrace();
}
try
{
connection.close();
}
catch
(SQLException e) {
e.printStackTrace();
}
}
/**
* 關閉執行更新操做的鏈接
*/
protected
static
void
closeConnection(Statement statement,
Connection connection) {
try
{
statement.close();
}
catch
(SQLException e) {
e.printStackTrace();
}
try
{
connection.close();
}
catch
(SQLException e) {
e.printStackTrace();
}
}
/**
* 不帶參數的更新
* @param sql
* @return flag
*/
public
static
int
update(String sql) {
int
rowCount = -
1
;
Connection connection =
null
;
PreparedStatement statement =
null
;
try
{
connection = DB.getConnection();
statement = connection.prepareStatement(sql);
rowCount = statement.executeUpdate();
}
catch
(SQLException e) {
e.printStackTrace();
}
finally
{
DB.closeConnection(statement, connection);
}
return
rowCount;
}
/**
* 帶參數的更新
* 例:
* try{
* String sql="update table set field1 = ?,field2=? where id=?";
* List<Object> par = new ArrayList<Object>();
* par.add("field1 value");
* par.add("field2 value");
* par.add(1);
* DB.update(sql,par);//這裏無需根據判斷返回值來斷定是否執行成功
* }catch(Exception e){
* e.printStackTrace();
* }
* @param sql
* @param par
* @return rowCount
*/
public
static
int
update(String sql, List<Object> par) {
//執行更新後被影響的行的數量
int
rowCount = -
1
;
Connection connection =
null
;
PreparedStatement statement =
null
;
try
{
connection = DB.getConnection();
statement = connection.prepareStatement(sql);
if
(par !=
null
) {
for
(
int
i =
0
; i < par.size(); i++) {
statement.setObject(i +
1
, par.get(i));
}
}
//將執行更新所影響的行數賦值給rouCount變量
rowCount = statement.executeUpdate();
}
catch
(SQLException e) {
e.printStackTrace();
}
finally
{
DB.closeConnection(statement, connection);
}
//返回所影響的行數給控制端
return
rowCount;
}
/**********************************************************/
/**
* 無條件查詢
* @param sql
* @return list<Map<String, Object>>
*/
public
static
List<Map<String, Object>> query(String sql) {
List<Map<String, Object>> list =
null
;
Connection connection =
null
;
PreparedStatement statement =
null
;
ResultSet resultSet =
null
;
try
{
connection = DB.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
if
(resultSet !=
null
) {
list =
new
ArrayList<Map<String, Object>>();
// 得到結果集相關屬性描述對象
ResultSetMetaData metaData = resultSet.getMetaData();
// 得到數據列的數量
int
cc = metaData.getColumnCount();
// 循環遍歷每一行數據,將行數據存進HashMap
while
(resultSet.next()) {
// 建立一個HashMap,以「鍵值對」的方式存儲字段名和值
Map<String, Object> dataRow =
new
HashMap<String, Object>();
// 循環得到每列數據的列名和值並放進HashMap
for
(
int
i =
1
; i <= cc; i++) {
dataRow.put(metaData.getColumnName(i),resultSet.getObject(i));
}
// 向數據集合裏添加一行數據
list.add(dataRow);
}
}
}
catch
(SQLException e) {
e.printStackTrace();
}
finally
{
// 關閉數據庫
DB.closeConnection(resultSet, statement, connection);
}
return
list;
}
/**
* 條件查詢
* @param sql
* @param par
* @return list<Map<String, Object>>
*/
public
static
List<Map<String, Object>> query(String sql,List<Object> par) {
List<Map<String, Object>> list =
null
;
Connection connection =
null
;
PreparedStatement statement =
null
;
ResultSet resultSet =
null
;
try
{
connection = DB.getConnection();
statement = connection.prepareStatement(sql);
if
(par !=
null
) {
for
(
int
i =
0
; i < par.size(); i++) {
statement.setObject(i +
1
, par.get(i));
}
}
resultSet = statement.executeQuery();
if
(resultSet !=
null
) {
list =
new
ArrayList<Map<String, Object>>();
// 得到結果集相關屬性描述對象
ResultSetMetaData metaData = resultSet.getMetaData();
// 得到數據列的數量
int
cc = metaData.getColumnCount();
// 循環遍歷每一行數據,將行數據存進HashMap
while
(resultSet.next()) {
// 建立一個HashMap,以「鍵值對」的方式存儲字段名和值
Map<String, Object> dataRow =
new
HashMap<String, Object>();
// 循環得到每列數據的列名和值並放進HashMap
for
(
int
i =
1
; i <= cc; i++) {
dataRow.put(metaData.getColumnName(i),resultSet.getObject(i));
}
// 向數據集合裏添加一行數據
list.add(dataRow);
}
}
}
catch
(SQLException e) {
e.printStackTrace();
}
finally
{
// 關閉數據庫
DB.closeConnection(resultSet, statement, connection);
}
return
list;
}
}