1. 程式人生 > >資料庫:JDBC開發

資料庫:JDBC開發

目錄

1.什麼是JDBC?

2.JDBC執行原理

3.JDBC開發步驟

4.常見API詳解

5.實現增刪改查

6.登入驗證(SQL注入問題)

7.PreparedStatement介面(解決SQL注入問題)

8.DAO開發


1.什麼是JDBC?

java database connectivity(java連線資料庫技術),是sun公司為了簡化開發,設計的一套資料庫連線管理規範,主要由一些介面組成。

2.JDBC執行原理

JDBC執行原理如下圖所示:

 

 

3.JDBC開發步驟

步驟

  1. 註冊驅動(通過DriverManager管理驅動)
  2. 建立連線(Connection)
  3. 傳送sql命令
  4. 獲取響應處理結果
  5. 釋放資源

程式碼

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mysql.jdbc.Driver;
public class Test {
	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			//1.註冊驅動
			DriverManager.registerDriver(new Driver());
			//2.建立連線
			conn = DriverManager.getConnection(
					//?useSSL=true 加密傳輸,保證資料安全
					"jdbc:mysql://localhost:3306/mysql?useSSL=true", 
					"root", 
					"root");
			System.out.println(conn);
			//3.傳送sql命令
			String sql = "select * from student";
			stmt = conn.createStatement();
			rs = stmt.executeQuery(sql);
			//4.獲取響應並處理
			while(rs.next()){//獲取記錄
				//逐列獲取資料
				int sid = rs.getInt("sid");
				String sname = rs.getString("sname");
				int cid = rs.getInt("cid");
				System.out.printf("sid:%s,sname:%s,cid:%s\n",sid,sname,cid);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			//5.釋放資源
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (rs != null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (rs != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

 

4.常見API詳解

常見類及介面

  • DriverManager:類,驅動管理器
  • Connection:介面,代表與資料庫服務的連線
  • Statement:介面,傳送sql指令
  • PreparedStatement:Statement介面的介面,傳送sql指令(主要用這個)
  • ResultSet:介面,結果集,底層封裝指向結果的遊標
  • ResultSetMetaData:介面,封裝了結果集的元資料資訊

DriverManager

作用:註冊和管理驅動程式;獲取連線物件。

示例:

//註冊驅動的兩種方式:
//1.通過DriverManager進行註冊
DriverManager.registerDriver(new Driver());
//2.載入類的時候靜態改程式碼塊裡面呼叫下面的程式碼進行驅動註冊
Class.forName("com.mysql.jdbc.Driver");//(建議使用)
//通過DriverManager獲取資料庫連線
conn = DriverManager.getConnection(url,user,password);

Connection

作用:作為資料傳輸通道;用於建立傳送sql命令的物件Statement或PreparedStatement。

常用方法:

//設定自動提交
conn.setAutoCommit();
conn.commit();
conn.rollback();
//建立傳送sql命令的物件
conn.createStatement();
conn.prepareStatement(sql);//PreparedStatement介面是Statement 介面的子介面
conn.prepareCall(sql);//CallableStatement介面是Statement 介面的子介面 用於呼叫儲存過程
//元資料:解釋資料的資料
DatabaseMetaData md = conn.getMetaData();
String dpn = md.getDatabaseProductName();
String driverName = md.getDriverName();
String url = md.getURL();
String username = md.getUserName();

Statement

作用:傳送sql指令

子介面:PreparedStatement(用於替換父介面) 和 CallableStatement(呼叫儲存過程)

常用方法:

  • execute:傳送任意sql命令,返回值boolean
  • executeQuery:傳送查詢sql命令,返回值是ResultSet物件
  • executeUpdate:傳送增刪改和ddl語句,返回值是影響的行數
  • executeBatch:傳送批處理命令,返回值int[ ]

ResultSet

作用:底層封裝指向結果集的遊標,可以獲取結果集中的資料

常用方法:

  • next():用於移動遊標
  • getX():獲取自段值
  • getMetaData():獲取結果集的元資料資訊
  • ResultSetMetaData rsmd = rs.getMetaData();//獲取結果集的元資料資訊
  • int columnCount = rsmd.getColumnCount();//獲取列數
  • String columnName = rsmd.getColumnName(1);//獲取列名

5.實現增刪改查(見下面的DAO開發)

6.登入驗證

登入驗證中的問題?使用Statement物件傳送sql指令時,利用檢驗不合格、不充分繞過驗證,從而完成SQL注入。

何為SQL注入

//定義sql字串
String sql = "select * from user where uname='"+uname+"' and password='"+password+"'";
//若uname和password的值如下:
String username="' or 1=1 or '";
String password="";
//將uname和password傳入上面的sql字串,將得到如下SQL語句
sql = "select * from user where uname='' or 1=1 or '' and password=''";
//這條sql語句的過濾條件是恆成立的,所以,一定會有查詢結果,從而無法達到驗證登入的效果

SQL注入產生的原因?利用sql的拼接。

如何解決SQL注入問題?使用PreparedStatement介面傳送sql指令,即可解決,具體見下文。

7.PreparedStatement介面

什麼是PreparedStatement

  • Statement的子介面
  • 採用佔位符以及賦值方式解決sql注入問題
  • 採用預編譯方式,效率高於Statement,常用PreparedStatement

示例程式碼

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = "select * from userinfo where username=? and password=?";
//預編譯(語法、語義等檢查)
ps = conn.prepareStatement(sql);
//賦值
ps.setString(1, username);
ps.setString(2, password);
rs = ps.executeQuery();
if (rs.next()) {
    System.out.println("登入成功");
} else {
    System.out.println("登入失敗");
}

8.DAO開發

什麼是DAO?data access object,即資料訪問物件,被定義成介面,專門用於對資料庫表的進行增刪改查操作。

什麼是DAO開發?sun公司提出三層開發架構,其中資料持久層是實現與資料庫的互動,因此資料持久層開發稱為DAO開發。

如何進行DAO開發

dao開發:由介面+實現類組成,每個介面只做一件事,對某一張表進行增刪改查操作(鬆耦合,儘可能避免依賴某一個具體類)

步驟

  1. 建立entity包,並在該包下為資料庫中的每一張表建立一個類,資料庫表中的每一條記錄就對應該類的一個物件稱為物件-關係對映;
  2. 建立dao包,並在包下針對資料庫的每一張表定義Dao介面以及實現BaseDao類(通用查和通用改的類);
  3. 建立dao.impl包,並在包下建立Dao介面的實現類並繼承BaseDao類,然後實現該類;
  4. 測試Dao的增刪改查是否正確。
  5. 在開發過程中,會建立獲取連線資源和關閉資源的工具類JdbcUtils,並放在util包下。

包、介面與類

完整程式碼

package entity;

public class User {
	private int uid;
	private String uname;
	private String password;
	public User(){}
	public int getUid() {
		return uid;
	}
	public User setUid(int uid) {
		this.uid = uid;
		return this;
	}
	public String getUname() {
		return uname;
	}
	public User setUname(String uname) {
		this.uname = uname;
		return this;
	}
	public String getPassword() {
		return password;
	}
	public User setPassword(String password) {
		this.password = password;
		return this;
	}
	@Override
	public String toString() {
		return "User [uid=" + uid + ", uname=" + uname + ", password=" + password + "]";
	}
	
}
package dao;

import java.util.List;

import entity.User;

public interface UserDao {
	//增刪改查
	int insert(User user);
	int delete(User user);
	int update(User user);
	List<User> select(User user);
	List<User> queryAll();
}
package dao;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;

import util.JdbcUtils;

public class BaseDao {
	
	private Connection conn;
	private PreparedStatement ps;
	private ResultSet rs;
	
	//通用增刪改方法
	public int excuteUpdate(String sql, Object[] objects){
		int res = 0;
		try {
			//獲取資料庫連線
			conn = JdbcUtils.getConnection();
			//獲取執行sql的物件
			ps = conn.prepareStatement(sql);
			for(int i=0; i<objects.length; i++){
				ps.setObject(i+1, objects[i]);
			}
			res = ps.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.closeRes(rs, ps, conn);
		}
		return res;
	}
	//通用查詢方法
	public <T> List<T> excuteQuery(String sql, Object[] objects, Class<T> clz){
		List<T> res = new ArrayList<>();
		try {
			//獲取資料庫連線
			conn = JdbcUtils.getConnection();
			//獲取執行sql的物件
			ps = conn.prepareStatement(sql);
			for(int i=0; i<objects.length; i++){
				ps.setObject(i+1, objects[i]);
			}
			//執行sql,獲取結果集
			rs = ps.executeQuery();
			ResultSetMetaData rmd = rs.getMetaData();
			int columnCount = rmd.getColumnCount();
			while(rs.next()){
				T t = clz.newInstance();
				for(int i=0; i<columnCount; i++){
					Object value = rs.getObject(i+1);
					String columnName = rmd.getColumnName(i+1);
					Field field = clz.getDeclaredField(columnName);
					field.setAccessible(true);
					field.set(t, value);
				}
				res.add(t);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.closeRes(rs, ps, conn);
		}
		return res;
	}
}

package dao.impl;

import java.util.List;
import dao.*;
import entity.User;

public class UserDaoImpl extends BaseDao implements UserDao {
	@Override
	public int insert(User user) {
		String sql = "insert into user(uname,password) values(?,?)";
		Object[] objects = {user.getUname(),user.getPassword()};
		return excuteUpdate(sql, objects);
	}
	@Override
	public int delete(User user) {
		String sql = "delete from user where uid=?";
		Object[] objects = {user.getUid()};
		return excuteUpdate(sql, objects);
	}
	@Override
	public int update(User user) {
		String sql = "update user set uname=?,password=? where uid=?";
		Object[] objects = {user.getUname(),user.getPassword(),user.getUid()};
		return excuteUpdate(sql, objects);
	}
	@Override
	public List<User> select(User user) {
		String sql = "select * from user where uname=? and password=?";
		Object[] objects = {user.getUname(),user.getPassword()};
		return excuteQuery(sql, objects, User.class);
	}
	@Override
	public List<User> queryAll() {
		String sql = "select * from user";
		Object[] objects = {};
		return excuteQuery(sql, objects, User.class);
	}

}
package util;

import java.io.*;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {
	
	private static String driver;
	private static String url;
	private static String user;
	private static String password;
	
	static{
		try {
			InputStream is = 
					JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
			System.out.println(is);
			Properties properties = new Properties();
			properties.load(is);
			is.close();
			//1.註冊驅動
			driver = properties.getProperty("driver");
			System.out.println(driver);
			Class.forName(driver);
			url = properties.getProperty("url");
			System.out.println(url);
			user = properties.getProperty("user");
			System.out.println(user);
			password = properties.getProperty("password");
			System.out.println(password);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//獲取Connection連線
	public static Connection getConnection() throws SQLException{
		//2.獲取資料庫連線
		return DriverManager.getConnection(url, user, password);
	}
	//關閉資源
	public static void closeRes(ResultSet rs, PreparedStatement ps, Connection conn){
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (ps != null) {
			try {
				ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
	}
}

jdbc.properties檔案的內容,該檔案要放置在src下面才能被正常訪問。 

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/bd1808?useSSL=true
user=root
password=root