DBUtils工具類的使用方法詳解

2020-10-09 11:00:20

DBUtils使用方法詳解

一、前言

本文是關於DBUtils使用方法的介紹,但在介紹DBUtils之前,首先介紹一些JDBC的基礎知識,有不足之處歡迎大家指正!

二、JDBC介紹

1.基本概念

JDBC,英文名為:Java DataBase Connectivity它是Java和資料庫之間的橋樑,是一個獨立於特定資料庫管理系統、通用的SQL資料庫存取和操作的公共介面(一組API),定義了用來存取資料庫的標準Java類庫(java.sql,javax.sql)使用這些類庫可以以一種標準的方法,方便的存取資料庫資源。
它最大的優點是為存取不同的資料庫提供了一種統一的途徑。接下來用兩張圖形象的說明這一特點。

  • 沒有JDBC時,Java程式存取資料庫時:

沒有JDBC時,java應用程式訪問各類資料庫過程

  • 有了JDBC,Java程式存取資料庫時:

java應用程式通過JDBC訪問各種資料庫
本文中的程式碼都是針對於MySql資料庫實現的,並且所有程式碼都經過測試,各位放心食用。

2.JDBC存取資料庫的流程
  1. 載入驅動(DriverManager)
  2. 獲取連線(DriverManager,Connection)
  3. 獲取執行SQL物件(Statement,PrepareStatement)
  4. 解析結果集(ReslutSet)
  5. 釋放資源(close())

以上五個步驟每寫一個運算元據庫的類都是需要的,例如載入驅動、獲取資料庫連線、釋放資源這三個步驟都要寫到。為了簡化程式碼,讓程式的可移植性和觀賞性更高,更加靈活的應對各種變化,需要編寫一個工具類來處理這些重複的步驟,這樣就引出了DBUtils工具類。

三、DBUtils介紹

1.基本概念

DBUtils:它是Apache組織提供的一個對JDBC進行簡單封裝的開源工具類,使用它能簡化JDBC應用程式的開發,提高程式碼的可移植性和觀賞性,同時也不會影響程式的效能。

2.組態檔

首先需要在專案(Project)的src目錄下建立一個"jdbc.properties"的組態檔,在建立檔案時要注意是在src目錄下,否則會有錯誤。創建配置檔案
組態檔內容為:

//使用者名稱和密碼
user=root
password=root
//資料庫路徑
url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8
//資料庫驅動
driverClass=com.mysql.cj.jdbc.Driver

組態檔的好處是:

  • 實現資料和程式碼分離,實現瞭解耦;
  • 如果需要修改組態檔資訊,可以避免程式重新打包;
  • 資料庫路徑、使用者名稱、密碼或者驅動發生變更時,無需改動程式碼,直接修改組態檔,大大提高了生產效率;

出現的問題:
設定資料庫路徑開始設定url為:

String url = "jdbc:mysql://localhost:3306/test";

執行後出現java.sql.SQLException異常, 並顯示 The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specifc time zone value if you want to utilize time zone support.
通過檢視資料,將url修改為:

String url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8

解決了問題,在連線字串後面加上?useUnicode=true& characterEncoding =UTF-8目的是為了解決中文亂碼輸入問題;加上userSSL=false是為了符合不使用SSL的現有應用程式,通過設定userSSL=false顯示禁用SSL;serverTimezone=GMT%2B8作用是統一標準世界時間。

3.建立JDBCUtils類

裡面包含了獲取資料庫的連線、載入驅動方法和釋放資源方法
獲取資料庫的連線、載入驅動方法:

public static Connection getConnection() throws Exception {
		/**
		 * 獲取資料庫的連線
		 */
		//1.讀取組態檔的4個基本資訊
		InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
		
		Properties pros = new Properties();
		pros.load(is);
		
		String user = pros.getProperty("user");
		String password = pros.getProperty("password");
		String url = pros.getProperty("url");
		String driverClass = pros.getProperty("driverClass");
		
		//2.載入驅動
		Class.forName(driverClass);
		
		//3.獲取連線
		Connection con = DriverManager.getConnection(url,user,password);
		System.out.println(con);
		return con;
	}

說明:

  • 首先通過InputStream讀取組態檔的4個基本資訊,利用ClassLoader呼叫getSystemClassLoader()方法實際上相當ConnectionTest.class.getClassLoader()的作用,但使用前者的好處是避免了出現第三方API;
  • 定義4個String型別的字串接收穫取到的基本資訊;
  • 此處省略了註冊驅動操作,是因為在mysql的Driver實現類中,宣告如下操作,故在實際的程式碼編寫中不需要在重新進行註冊驅動。
static {
		try {
			java.sql.DriverManager.registerDriver(new Driver());
		} catch (SQLException E) {
			throw new RuntimeException("Can't register driver!");
		}
}

非查詢類釋放資源方法:

/**
	 * 關閉連線和Statement
	 * @param con
	 * @param ps
	 */
	public static void closeResource(Connection con,Statement ps) {
		//資源關閉
		try {
			if(ps != null)
				ps.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			if(con != null)
				con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

說明: 非查詢類釋放資源過程中只需要關閉連線Connection和Statement,通過判斷Statement的物件ps和Connection的物件con是否非空即可執行資源關閉。
查詢類釋放資源方法:

/**
	 * 關閉連線、Statement和ResultSet
	 * @param con
	 * @param ps
	 */
	public static void closeResource(Connection con,Statement ps,ResultSet rs) {
		//資源關閉
		try {
			if(ps != null)
				ps.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			if(con != null)
				con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			if(rs != null)
				rs.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

說明: 查詢類釋放資源過程中不僅僅要關閉連線Connection和Statement,還需要關閉查詢過程中得到的結果集ResultSet。

4.實現對資料表的增刪改查

(1)向student表中插入一條資料
說明: 預期目的是為了將(「鄭**」,「304728796@qq.com」,「2000-01-01」)資料插入到資料庫中,執行後結果如圖所示。

@Test
	//向student表中插入一條資料
	public void testInsert(){
		Connection con = null;
		PreparedStatement ps = null;
		try {
			//1.讀取組態檔的4個基本資訊
			InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
			Properties pros = new Properties();
			pros.load(is);
			String user = pros.getProperty("user");
			String password = pros.getProperty("password");
			String url = pros.getProperty("url");
			String driverClass = pros.getProperty("driverClass");
			//2.載入驅動
			Class.forName(driverClass);
			//3.獲取連線
			con = DriverManager.getConnection(url,user,password);
			System.out.println(con);
			//4.預編譯SQL語句,返回PreparedStatement的範例
			String sql = "insert into student(name,email,birth)values(?,?,?)";//?:預留位置
			ps = con.prepareStatement(sql);
			//5.填充預留位置
			ps.setString(1, "鄭**");
			ps.setString(2, "304728796@qq.com");
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			java.util.Date date = sdf.parse("2000-01-01");
			ps.setDate(3,new Date(date.getTime()));
			//6.執行SQL
			ps.execute();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			//7.資源關閉
			try {
				if(ps != null)
					ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				if(con != null)
					con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

插入之前資料庫中原始資料為:
在這裡插入圖片描述
在插入之後資料庫中資料為:
在這裡插入圖片描述
(2)修改student表中的資料
**說明:利用ps.setObject(1, 「小華」);ps.setObject(2, 3); 預期目的是為了修改行號為3,列號為2的資料,由"鄭"修改為"小華",執行後結果如圖所示。

//修改student表的一條記錄
	@Test
	public void testUpdate() {
		//1.獲取資料庫連線
		Connection con = null;
		PreparedStatement ps = null;
		try {
			con = JDBCUtils.getConnection();
			//2.預編譯SQL語句,返回PraparedStatement的範例
			String sql = "update student set name =? where id = ?";
			ps = con.prepareStatement(sql);
			//3.填充預留位置
			ps.setObject(1, "小華");
			ps.setObject(2, 3);
			//4.執行SQL
			ps.execute();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			//5.資源的關閉
			JDBCUtils.closeResource(con,ps);
		}
	}

修改之前資料庫中原始資料為:
在這裡插入圖片描述
在修改之後資料庫中資料為:
在這裡插入圖片描述
(3)通用的增刪改運算元據庫

說明:

  • 該方法不僅僅適用於該表,其他表也適用;
  • 該方法根據testCommonUpdate方法中sql語句的改變而進行不同的操作;可實現增(insert)、刪(delete)、改(update)操作;
  • update方法中的args為可變引數,sql中的預留位置的個數與可變形參長度相同;
  • 利用update(sql,2)方法,預期目的是刪除行號為2的資料,執行後結果如圖所示。
@Test
	public void testCommonUpdate() {
		String sql = "delete from student where id = ?";
		update(sql,2);
	}
	//通用的增刪改操作
	public void update(String sql,Object ...args){//sql中預留位置的個數與可變形參長度相同
		Connection con = null;
		PreparedStatement ps = null;
		try {
			//1.獲取資料庫連線
			con = JDBCUtils.getConnection();
			//2.預編譯SQL語句,返回PraparedStatement的範例
			ps = con.prepareStatement(sql);
			//3.填充預留位置
			for(int i=0;i<args.length;i++) {
				ps.setObject(i+1, args[i]);//引數宣告:列號從1開始
			}
			//4.執行SQL
			ps.execute();
		} 
		catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			//5.資源的關閉
			JDBCUtils.closeResource(con,ps);
		}
	}

刪除之前資料庫中原始資料為:
在這裡插入圖片描述
刪除之後資料庫中資料為:
在這裡插入圖片描述
(4)查詢資料庫中的資料

package com.javaweb3.preparedstatement;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import com.javaweb4.util.JDBCUtils;
/**
 * 針對於student表的查詢
 * @author 敷衍zgf
 *
 */
public class StudentForQuery {
	@Test
	public void testQuery1(){
		Connection con = null;
		PreparedStatement ps = null;
		//執行並返回結果集
		ResultSet resultSet = null;
		try {
			con = JDBCUtils.getConnection();
			String sql = "select id,name,email,birth from student where id = ?";
			ps = con.prepareStatement(sql);
			ps.setObject(1, 1);
			resultSet = ps.executeQuery();
			//處理結果集
			if(resultSet.next()) {//判斷結果集的下一條是否有資料,如果有資料返回true,並且指標下移;如果返回false,指標不會下移
			
				//獲取當前字條資料的各個欄位值
				int id = resultSet.getInt(1);
				String name = resultSet.getString(2);
				String email = resultSet.getString(3);
				Date birth = resultSet.getDate(4);
				
				/*處理結果集
				 * 方式一:
				 */
				System.out.println("id = "+id+",name = "+name+",email = "+email+",birth = "+birth);
				//方式二:
				Object[] data = new Object[] {id,name,email,birth};
				for(int i=0;i<data.length;i++) {
					System.out.print(data[i]+" ");
				}
			}
		}catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			//關閉資源
			JDBCUtils.closeResource(con, ps, resultSet);
		}	
	}
}

資料庫中的資料:
在這裡插入圖片描述
查詢後得到的結果:
在這裡插入圖片描述

四、對以上程式碼的說明

以上對資料庫資料的增刪查操作全都是使用PreparedStatement實現的,PreparedStatement是從Statement擴充套件而來的。不使用Statement是因為它不僅需要拼寫sql語句,更嚴重的是存在SQL隱碼攻擊的問題。PreparedStatement是預編譯的,對於批次處理可以大大提高效率。

五、總結

以上就是本人對JDBC和DBUtils工具類的全部認識和簡單的運用方法,如有不足之處歡迎大家批評指正!