Java 之 JDBC(二)

前面咱們已經知道了一些經常使用的JDBC操做,接下來咱們繼續深刻,繼續改進咱們的DAO。java

Java 之 JDBC (一)mysql

1、JDBC池連接

一、沒有池的狀況下:

總之就是不使用池的狀況下:每次操做都須要進行鏈接數據庫,鏈接中須要將Connection加載進內存中,驗證用戶名和密碼等都須要話費時間。

二、認識池

一、 池就是一種容納對象的容器
二、 鏈接池就是保存數據庫鏈接對象的容器
三、 在鏈接池中咱們會預先建立必定數量的鏈接對象,當須要數據庫鏈接的時候,只要從數據庫鏈接池中取出一個,使用完畢以後就再放回去,這些鏈接對象是以一種循環隊列來存放的,取的時候從頭開始,放回的時候放在尾部。
四、 經過設置最大鏈接數量來防止系統無止盡的與數據庫鏈接
五、 鏈接池中能夠設置監聽機制,用來測試鏈接的數量
複製代碼

鏈接池中的屬性:git

三、鏈接池的使用

一、 鏈接池是使用 java.sql.DataSource接口來表示鏈接池的
二、 DataSource和jdbc同樣,也是隻提供一個接口,由第三方組織來提供,因此鏈接池不一樣的廠家,有不一樣的鏈接池
複製代碼

四、詳細步驟

DBCP的使用github

如下代碼就是獲取數據庫鏈接池,並獲取鏈接對象。sql

2、配置信息

第一步 文件建立數據庫

一、項目目錄下新建一個resource文件夾 
二、編寫db.properties文件
複製代碼

文件內容爲:數組

// 記錄配置信息
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mytest?rewriteBatchedStatements=true
username=root
password=zjj19970517
maxActive=8
複製代碼

爲何要使用配置文件?bash

第二步 文件讀取app

例子: dom

咱們能夠改寫咱們的utils類:(經過靜態代碼塊執行獲取鏈接池)

3、Druid使用

Druid地址

Druid是一個JDBC組件庫,包括數據庫鏈接池、SQL Parser等組件。DruidDataSource是最好的數據庫鏈接池。

DBCP遷移到Druid

DruidDataSource的配置是兼容DBCP的。從DBCP遷移到DruidDataSource,只須要修改數據源的實現類就能夠了。
複製代碼

4、DAO重構改進

一、抽取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
	}
}

複製代碼

二、抽取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;
}
複製代碼

三、內省

(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());
		
	}
}

複製代碼

四、使用內省封裝通用的結果集處理器

  • 處理單個結果集
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));
	}

}

複製代碼

最終demo代碼

相關文章
相關標籤/搜索