1. 程式人生 > >Java14---JDBC封裝優化,ORM思想

Java14---JDBC封裝優化,ORM思想

導讀

1.PreparedStatement
2.封裝優化
3.ORM思想

PreparedStatement

–是Statement的子介面
特點:可以設定引數,把帶引數的SQL語句先傳過去,再設定對應引數的值傳過去執行

較Statement來看,PreparedStatement的變化主要在第三,第四步驟

第三步,建立PreparedStatement,傳入帶引數的SQL語句
	對於變化的數值,可以引數化,用?做佔位符佔位
	String sql = "INSERT INTO t_user (id,username,password,sex,"
				+ "id_number,tel,addr) "
				+ "VALUES(t_user_id_seq.NEXTVAL,?,?,?,?,?,?)";

	PreoareStatement pstmt=conn.prepareStatement(sql);

第四步,執行SQL語句
	1)先設定佔位符的值,發過去值執行SQL語句
	每一個問號對應一個索引,從1開始,語句按照從左到右的順序
	pstmt.setXXX(索引,對應的值);
	
	2)執行,注意不要再次傳入SQL語句了
	int rows = pstmt.executeUpdate();
	

PreparedStatement vs Statement

直觀看:
利用PreparedStatement不需要拼接,不需要關心單引號的問題
先傳帶引數的SQL語句
在傳引數執行

利用Statement利用拼接,注意文字型要加單引號拼接
把完整的拼接後的語句傳過去執行
效率看:
如果新增1個學生,Statement相對快一點(後者只傳一次)
如果新增100個學生,
	對於Statement,迴圈第四步,傳送100次語句過去,都不相同
		對於一個語法,傳送過去需要先編譯處理,再執行,編譯100次		
	對於Preparedstatement,迴圈第四步,傳送100次引數值過去,語句是一樣的
		對於帶引數的語句,先預編譯,只要預編譯1次,執行100次,相對效率高一點
從安全形度來看:
	需求:登入時,通過使用者名稱和密碼查詢一個使用者
	Statement:
	"SELECT id,username,password,sex FROM t_user WHERE username="+username+" and password='"+password+"'";
	
	PreparedStatement:
	"SELECT id,username,password,sex FROM t_user WHERE username=? and password=?";

假如:使用者名稱:aa
     密碼:111
	 結果一致
	 
假如:使用者名稱:aa
     密碼:"111' OR '1'='1"
	 Statement中槍,可以查到所有的使用者資訊
	 PreparedSatement直接報錯,不允許設定

PreparedStatement更安全

PreparedStatement可以替代Statement,我們推薦使用PreparedSatement

封裝優化

1.封裝第一,二步

自創類ConnectionFactory實現

package com.hala.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * Connection工廠類
 * 利用這個類獲取連線的資料庫物件
 * @author air
 *
 */
public class ConnectionFactory {

	private static final String DRIVER="oracle.jdbc.driver.OracleDriver";

	public static Connection getConnection(){
		//這裡把宣告放在try{}裡邊的話成為區域性變數,會報錯
		Connection conn=null;
		try {
			Class.forName(DRIVER);
			conn=DriverManager.getConnection(
					"jdbc:oracle:thin:@localhost:1521:XE",
					"easybuy",
					"easybuy");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return conn;
	}
}

替換
Connection conn=ConnectionFactory.getConnection();

注意:這裡有兩種優化思想
(1)將常量抽出為private static final 屬性,便於使用改動
(2)將這些常量存在一個配置檔案中,在ConnectionFactory所在的包下建立一個properties檔案

properties:屬性檔案(不能帶引號,否則引號也作為有效的一部分)
			鍵值對
			key=value
			key=value
			key=value
		Java中:Properties類,集合類,儲存鍵值對
			這個類物件可以從properties檔案中載入資料,把所有的鍵值對
			載入到記憶體物件中

jdbcinfo.properties

driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
username=easybuy
userpassword=easybuy

怎樣獲取檔案中的鍵值對來使用呢?
->更改後的 ConnectionFactory.java

package com.hala.jdbc;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * Connection工廠類
 * 利用這個類獲取連線的資料庫物件
 * @author air
 *
 */
public class ConnectionFactory {
	//用來儲存從檔案中獲得的值
	private static String DRIVER;
	private static String URL;
	private static String USERNAME;
	private static String USERPASSWORD;
	
	
	//利用靜態程式碼塊實現,在類載入時執行,只會執行一次
	static{
		//1.建立一個Properties物件
		Properties prop=new Properties();
	
		try {
			//2.載入properties檔案的資料,這種寫法只能對同包下的檔案獲取一個位元組流
			//載入後prop裡邊就有了檔案裡邊的鍵值對
			prop.load(ConnectionFactory.class.
					getResourceAsStream("jdbcinfo.properties"));
			//3.通過鍵獲取對應的值,注意大小寫
			DRIVER=prop.getProperty("driver");
			URL=prop.getProperty("url");
			USERNAME=prop.getProperty("username");
			USERPASSWORD=prop.getProperty("userpassword");
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	public static Connection getConnection(){
		//這裡把宣告放在try{}裡邊的話成為區域性變數,會報錯
		Connection conn=null;
		try {
			Class.forName(DRIVER);
			conn=DriverManager.getConnection(URL,USERNAME,USERPASSWORD);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return conn;
	}
}

2.釋放資源:自創一個類實現

package com.hala.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 釋放資源
 * @author air
 *
 */
public class DBUtils {
	//這裡PreparedStatement是Statement的子介面,所以這裡用Statement即可
	public static void close(ResultSet rs,Statement stmt,Connection conn){
		if(rs!=null){
			try {
			rs.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		}
		
		if(stmt!=null){
			try {
				stmt.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			}
		
		if(conn!=null){
			try {
			conn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		}
	}

}

替換
DBUtils.close(rs,stmt,conn);

ORM思想

Object/Relational Mapping
java物件<---->資料庫對映

物件模型        			關係模型
實體類(pojo)	  			表
屬性              		列(欄位)	
OID				  		主鍵
物件              		記錄
實體類之間的關聯關係        外來鍵
一對一
對映到Java中:
Person		Passport
id           id
name         ...
Passport     Person

Person中含有Passport屬性,Passport屬性也含有Person屬性
一對多
Order (訂單)             OrderDetail(訂單明細)
List<OrderDetail>  			Order
Order中含有List<OrderDetail> 屬性,OrderDetail含有Order	屬性
多對多
Teacher           Student
List<Student>     List<Teacher>

ORM思想其實本質就是將兩個類相互關聯起來

例項:
定義一個方法,
	查詢一個訂單,及其對應的明細並返回
	要求,返回訂單物件,裡面包含對應的明細集合物件

分步操作:
1.定義一個OrderJDBC類,
		定義 Order getOrder(long id){}
		
2.定義一個OrderDetailJDBC類,
		定義 List<OrderDetail> getDetails(long orderId){}
		
3.定義一個方法,
	查詢一個訂單,及其對應的明細並返回
	要求,返回訂單物件,裡面包含對應的明細集合物件