前面我們已經知道了一些常用的JDBC操作,接下來我們繼續深入,繼續改進我們的DAO。
一、JDBC池連結
1、沒有池的情況下:
總之就是不使用池的情況下:每次操作都需要進行連線資料庫,連線中需要將Connection載入進記憶體中,驗證使用者名稱和密碼等都需要話費時間。2、認識池
1、 池就是一種容納物件的容器
2、 連線池就是儲存資料庫連線物件的容器
3、 在連線池中我們會預先建立一定數量的連線物件,當需要資料庫連線的時候,只要從資料庫連線池中取出一個,使用完畢之後就再放回去,這些連線物件是以一種迴圈佇列來存放的,取的時候從頭開始,放回的時候放在尾部。
4、 通過設定最大連線數量來防止系統無止盡的與資料庫連線
5、 連線池中可以設定監聽機制,用來測試連線的數量
複製程式碼
連線池中的屬性:
3、連線池的使用
1、 連線池是使用 java.sql.DataSource介面來表示連線池的
2、 DataSource和jdbc一樣,也是隻提供一個介面,由第三方組織來提供,所以連線池不同的廠家,有不同的連線池
複製程式碼
4、詳細步驟
DBCP的使用
以下程式碼就是獲取資料庫連線池,並獲取連線物件。
二、配置資訊
第一步 檔案建立
1、專案目錄下新建一個resource資料夾
2、編寫db.properties檔案
複製程式碼
檔案內容為:
// 記錄配置資訊
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mytest?rewriteBatchedStatements=true
username=root
password=zjj19970517
maxActive=8
複製程式碼
為什麼要使用配置檔案?
第二步 檔案讀取
例子:
我們可以改寫我們的utils類:(通過靜態程式碼塊執行獲取連線池)
三、Druid使用
Druid是一個JDBC元件庫,包括資料庫連線池、SQL Parser等元件。DruidDataSource是最好的資料庫連線池。
DBCP遷移到Druid
DruidDataSource的配置是相容DBCP的。從DBCP遷移到DruidDataSource,只需要修改資料來源的實現類就可以了。
複製程式碼
四、DAO重構改進
1、抽取DML方法
資料查詢語言DQL
資料操縱語言DML
資料定義語言DDL
資料控制語言DCL。
複製程式碼
/**
* 更新操作公共方法
* @param sql 預編譯sql語句
* @param params 引數陣列
* @return
*/
public int _executeUpdate(String sql, Object...params) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 連線資料庫
conn = JDBCUtils.getConnection();
// 建立預編譯
ps = conn.prepareStatement(sql);
// 設定引數
for(int i= 0 ; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
// 執行更新
return ps.executeUpdate(); // 返回更新的行數
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, ps, null);
}
return -1; // 如果更新失敗,返回-1
}
複製程式碼
使用如下:
/**
* 儲存學生
* @param stu
*/
public void save(Student stu) {
String sql = "insert into student (name, age) values (? , ?)";
this._executeUpdate(sql, stu.getName(), stu.getAge()); //直接呼叫
}
複製程式碼
為了今後使用方便我們把_executeUpdate
方法抽取出來,放入一個CRUDTemplate
的模版類中。
package com.meils.jdbc.utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* CRUD操作模版
* @author apple
*
*/
public class CRUDTemplate {
/**
* 更新操作公共方法
* @param sql 預編譯sql語句
* @param params 引數陣列
* @return
*/
public static int _executeUpdate(String sql, Object...params) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 連線資料庫
conn = JDBCUtils.getConnection();
// 建立預編譯
ps = conn.prepareStatement(sql);
// 設定引數
for(int i= 0 ; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
// 執行更新
return ps.executeUpdate(); // 返回更新的行數
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, ps, null);
}
return -1; // 如果更新失敗,返回-1
}
}
複製程式碼
2、抽取DQL方法
第一步 新建handle處理層介面
新建一個包: com.meils.jdbc.handle
// IResultSetHandle.java
package com.meils.jdbc.handle;
import java.sql.ResultSet;
import java.util.List;
/**
* 結果集處理介面
* @author apple
*
*/
// 這裡傳入了型別,T為我們通過這個方法處理後要返回的型別
public interface IResultSetHandle<T>{
/**
* 處理結果集
* @param rs 傳入結果集
* @return 返回List集合
*/
T handle(ResultSet rs);
}
複製程式碼
第二步 實現介面類
在student的dao實現介面類中定義內部類
/**
* 結果集處理 實現類
* @author apple
*
*/
// 因為具體到某一個dao層的時候我們就知道了我們想要的型別了,所以傳入<List<Student>>
class StuResultSetHandle implements IResultSetHandle <List<Student>>{
@Override
public List<Student> handle(ResultSet rs) {
List<Student> list = new ArrayList<Student>();
try {
while (rs.next()) {
Student stu = new Student();
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
stu.setId(rs.getInt("id"));
list.add(stu);
}
return list; // 返回集合
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
複製程式碼
第三步 編寫DQL模版方法
// CRUDTemplate.java
package com.meils.jdbc.utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.meils.jdbc.handle.IResultSetHandle;
/**
* CRUD操作模版
* @author apple
*
*/
public class CRUDTemplate {
/**
* 更新操作公共方法
* @param sql 預編譯sql語句
* @param params 引數陣列
* @return
*/
public static int _executeUpdate(String sql, Object...params) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 連線資料庫
conn = JDBCUtils.getConnection();
// 建立預編譯
ps = conn.prepareStatement(sql);
// 設定引數
for(int i= 0 ; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
// 執行更新
return ps.executeUpdate(); // 返回更新的行數
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, ps, null);
}
return -1; // 如果更新失敗,返回-1
}
/**
* 查詢 公共方法
* @param sql sql預編譯語句
* @param rh 結果集處理的實現物件
* @param params 要給sql語句傳入的引數
* @return 返回一個結果集
*/
// 這裡我們也使用範型,因為我們這裡要返回結果集處理方法處理完畢之後的集合,但是處理完畢的結果集我們並不知道是什麼型別,因此我們需要通過範型來設定變化的型別
public static <T>T _executeQuery(String sql, IResultSetHandle<T> rh, Object... params) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
rs = ps.executeQuery();
return rh.handle(rs); // 處理結果集
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, ps, rs);
}
return null;
}
}
複製程式碼
第四步 使用如下
@Override
public Student findOne(int id) {
String sql = "select * from student where id = ?";
IResultSetHandle <List<Student>> result = new StuResultSetHandle();
List<Student> list = CRUDTemplate._executeQuery(sql,result,id);
return list.size() == 1 ? list.get(0) : null;
}
複製程式碼
3、內省
(1)class型別
User u = User.class.newInstance(); // 使用class常見物件
User u1 = new User(); // 使用類名建立物件
複製程式碼
(2) 內省
我們使用內省來檢視一個JavaBean類內部的屬性和get set方法。
package com.it666.jdbc.test;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import com.it666.jdbc.domain.User;
class ClassTest{
public Class c;
public ClassTest(Class c) {
this.c = c;
}
}
public class Test {
public static void main(String[] args) throws Exception {
/* ClassTest ct = new ClassTest(User.class);
User u = (User) ct.c.newInstance();*/
// 建立User 物件
User u = User.class.newInstance();
// 1獲取beanInfo物件
BeanInfo beanInfo = Introspector.getBeanInfo(User.class,Object.class);
// 2獲取beanInfo類的內部資訊
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
// 獲取屬性名
//System.out.println(pd.getName());
// 獲取get方法
///System.out.println(pd.getReadMethod());
// 獲取set方法
System.out.println(pd.getWriteMethod());
// 呼叫方法
pd.getWriteMethod().invoke(u, "111");
}
// 使用User 物件的方法
System.out.println(u.getName());
System.out.println(u.getPwd());
}
}
複製程式碼
4、使用內省封裝通用的結果集處理器
- 處理單個結果集
package db.handle;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 結果集處理介面的實現類
* @author apple
*
* @param <T>
*
*/
public class BeanHandler<T> implements IResultSetHandle <T>{
public Class<T> classType;
public BeanHandler (Class<T> classType) {
this.classType = classType;
}
/**
* 處理結果集返回結果
* 返回一個物件
*/
@Override
public T handle(ResultSet rs) {
try {
if(rs.next()) {
try {
// 例項化一個物件
T obj = this.classType.newInstance();
// 獲取BeanInfo 物件
BeanInfo bf = Introspector.getBeanInfo(this.classType, Object.class);
// 獲取BeanClass 類的屬性和方法
PropertyDescriptor[] pds = bf.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Object val = rs.getObject(pd.getName());
//¸使用set方法,設定屬性值
pd.getWriteMethod().invoke(obj, val);
}
return obj;
} catch(Exception e) {
e.printStackTrace();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
複製程式碼
- 處理多個結果集
package db.handle;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class BeanListHandler<T> implements IResultSetHandle<List<T>>{
private Class<T> classType;
public BeanListHandler(Class<T> classType) {
this.classType = classType;
}
/**
* 查詢
* 返回集合
*/
@Override
public List<T> handle(ResultSet rs) {
List<T> list = new ArrayList<>();
try {
while(rs.next()) {
T obj = this.classType.newInstance();
BeanInfo bf = Introspector.getBeanInfo(this.classType,Object.class);
PropertyDescriptor[] pds = bf.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Object val = rs.getObject(pd.getName());
pd.getWriteMethod().invoke(obj, val);
}
list.add(obj);
}
return list;
}catch (Exception e) {
e.printStackTrace();;
}
return null;
}
}
複製程式碼
- 使用如下:
package db.dao.impl;
import java.util.List;
import db.dao.IStudentDao;
import db.domain.Student;
import db.handle.BeanHandler;
import db.handle.BeanListHandler;
import db.utils.CRUDTemplate;
public class StudentDaoImpl implements IStudentDao {
@Override
public int save(Student stu) {
String sql = "insert into student (name, age) values (? , ?)";
return CRUDTemplate._executeUpdate(sql, stu.getName(), stu.getAge());
}
@Override
public int delete(int id) {
String sql = "delete from student where pid = ?";
return CRUDTemplate._executeUpdate(sql, id);
}
@Override
public int update(int id, Student stu) {
String sql = "update student set name=?, age=? where pid =? ";
return CRUDTemplate._executeUpdate(sql, stu.getName(), stu.getAge(), id);
}
@Override
public Student findOne(int id) {
String sql = "select * from student where pid = ?";
return CRUDTemplate._executeQuery(sql, new BeanHandler<Student>(Student.class), id);
}
@Override
public List<Student> findAll() {
String sql = "select * from student ";
return CRUDTemplate._executeQuery(sql,new BeanListHandler<Student>(Student.class));
}
}
複製程式碼