簡單通用JDBC輔助類封裝(實(shí)例)
哎,最近很好久沒寫點(diǎn)東西了,由于工作的原因,接觸公司自己研發(fā)的底層orm框架,偶然發(fā)現(xiàn)該框架在調(diào)用jdbc操作的時(shí)候參考的是hibernate 里面的SimpleJdbcTemplate,這里我想到了在大學(xué)的時(shí)候自己用過的一個(gè)簡單的jdbc封裝,現(xiàn)在我將代碼貼出來,和大家一起分享:
Config類:讀取同一包下的數(shù)據(jù)庫連接配置文件,這樣是為了更好的通用性考慮
package com.tly.dbutil;
import java.io.IOException;
import java.util.Properties;
public class Config {
private static Properties prop = new Properties();
static{
try {
//加載dbconfig.properties配置文件
prop.load(Config.class.getResourceAsStream("dbconfig.properties"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//設(shè)置常量
public static final String CLASS_NAME = prop.getProperty("CLASS_NAME");
public static final String DATABASE_URL = prop.getProperty("DATABASE_URL");
public static final String SERVER_IP = prop.getProperty("SERVER_IP");
public static final String SERVER_PORT = prop.getProperty("SERVER_PORT");
public static final String DATABASE_SID = prop.getProperty("DATABASE_SID");
public static final String USERNAME = prop.getProperty("USERNAME");
public static final String PASSWORD = prop.getProperty("PASSWORD");
}
dbconfig.properties:數(shù)據(jù)庫配置文件,你也可以用xml格式等,注意Config類里面該文件的調(diào)用位置
CLASS_NAME=com.mysql.jdbc.Driver DATABASE_URL=jdbc:mysql SERVER_IP=localhost SERVER_PORT=3306 DATABASE_SID=employees USERNAME=root PASSWORD=1
接下來就是數(shù)據(jù)庫連接輔助類DBConn了
package com.employees.dbutil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DBConn {
//三屬性、四方法
//三大核心接口
private Connection conn = null;
private PreparedStatement pstmt = null;
private ResultSet rs = null;
//四個(gè)方法
//method1: 創(chuàng)建數(shù)據(jù)庫的連接
public Connection getConntion(){
try {
//1: 加載連接驅(qū)動(dòng),Java反射原理
Class.forName(Config.CLASS_NAME);
//2:創(chuàng)建Connection接口對象,用于獲取MySQL數(shù)據(jù)庫的連接對象。三個(gè)參數(shù):url連接字符串 賬號 密碼
String url = Config.DATABASE_URL+"://"+Config.SERVER_IP+":"+Config.SERVER_PORT+"/"+Config.DATABASE_SID;
conn = DriverManager.getConnection(url,Config.USERNAME,Config.PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
//method2:關(guān)閉數(shù)據(jù)庫的方法
public void closeConn(){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(pstmt!=null){
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//method3: 專門用于發(fā)送增刪改語句的方法
public int execOther(PreparedStatement pstmt){
try {
//1、使用Statement對象發(fā)送SQL語句
int affectedRows = pstmt.executeUpdate();
//2、返回結(jié)果
return affectedRows;
} catch (SQLException e) {
e.printStackTrace();
return -1;
}
}
//method4: 專門用于發(fā)送查詢語句
public ResultSet execQuery(PreparedStatement pstmt){
try {
//1、使用Statement對象發(fā)送SQL語句
rs = pstmt.executeQuery();
//2、返回結(jié)果
return rs;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
}
平時(shí)的用上面的代碼能夠解決一些簡單的CRUD的應(yīng)用了,但是還有很多限制,比如每次程序拿連接都要new,這樣就給系統(tǒng)加大了負(fù)擔(dān),沒有事務(wù),沒有dataSource等等,今天看見一哥們在園里面寫的一篇用反射解決直接以對象參數(shù)的方式CRUD,這個(gè)我以前也寫過,沒寫完,主要是自己想寫一個(gè)通用的DButil,最后研究來研究去,發(fā)現(xiàn)越來越和hibernate里面的simpleJdbcTemplate接近了,所以就直接去看hibernate的源碼了,加上那段時(shí)間有些事,沒有時(shí)間,就將這件事閑置起來了,現(xiàn)在把這個(gè)東西補(bǔ)上,也給自己回顧一下下
BaseDao類
package com.employees.dao;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.employees.dbutil.DBConn;
public class BaseDAO<T> {
DBConn conn = new DBConn();
private Connection connection = null;
@SuppressWarnings("unused")
private Class<T> persistentClass;
@SuppressWarnings("unchecked")
public BaseDAO() {
initConnection();
//獲得參數(shù)化類型
ParameterizedType type = (ParameterizedType)getClass().getGenericSuperclass();
persistentClass = (Class<T>)type.getActualTypeArguments()[0];
}
/**
* 獲得數(shù)據(jù)庫連接
*/
public void initConnection() {
connection = conn.getConntion();
}
/**
* 保存
*/
public void save(T entity) throws Exception{
//SQL語句,insert into table name (
String sql = "insert into " + entity.getClass().getSimpleName().toLowerCase() + "(";
//獲得帶有字符串get的所有方法的對象
List<Method> list = this.matchPojoMethods(entity,"get");
Iterator<Method> iter = list.iterator();
//拼接字段順序 insert into table name(id,name,email,
while(iter.hasNext()) {
Method method = iter.next();
sql += method.getName().substring(3).toLowerCase() + ",";
}
//去掉最后一個(gè),符號insert insert into table name(id,name,email) values(
sql = sql.substring(0, sql.lastIndexOf(",")) + ") values(";
//拼裝預(yù)編譯SQL語句insert insert into table name(id,name,email) values(?,?,?,
for(int j = 0; j < list.size(); j++) {
sql += "?,";
}
//去掉SQL語句最后一個(gè),符號insert insert into table name(id,name,email) values(?,?,?);
sql = sql.substring(0, sql.lastIndexOf(",")) + ")";
//到此SQL語句拼接完成,打印SQL語句
System.out.println(sql);
//獲得預(yù)編譯對象的引用
PreparedStatement statement = connection.prepareStatement(sql);
int i = 0;
//把指向迭代器最后一行的指針移到第一行.
iter = list.iterator();
while(iter.hasNext()) {
Method method = iter.next();
//此初判斷返回值的類型,因?yàn)榇嫒霐?shù)據(jù)庫時(shí)有的字段值格式需要改變,比如String,SQL語句是'"+abc+"'
if(method.getReturnType().getSimpleName().indexOf("String") != -1) {
statement.setString(++i, this.getString(method, entity));
} else if(method.getReturnType().getSimpleName().indexOf("Date") != -1){
statement.setDate(++i, this.getDate(method, entity));
} else if(method.getReturnType().getSimpleName().indexOf("InputStream") != -1) {
statement.setAsciiStream(++i, this.getBlob(method, entity),1440);
} else {
statement.setInt(++i, this.getInt(method, entity));
}
}
//執(zhí)行
conn.execOther(statement);
//關(guān)閉連接
conn.closeConn();
}
/**
* 修改
*/
public void update(T entity) throws Exception{
String sql = "update " + entity.getClass().getSimpleName().toLowerCase() + " set ";
//獲得該類所有g(shù)et方法對象集合
List<Method> list = this.matchPojoMethods(entity,"get");
//臨時(shí)Method對象,負(fù)責(zé)迭代時(shí)裝method對象.
Method tempMethod = null;
//由于修改時(shí)不需要修改ID,所以按順序加參數(shù)則應(yīng)該把Id移到最后.
Method idMethod = null;
Iterator<Method> iter = list.iterator();
while(iter.hasNext()) {
tempMethod = iter.next();
//如果方法名中帶有ID字符串并且長度為2,則視為ID.
if(tempMethod.getName().lastIndexOf("Id") != -1 && tempMethod.getName().substring(3).length() == 2) {
//把ID字段的對象存放到一個(gè)變量中,然后在集合中刪掉.
idMethod = tempMethod;
iter.remove();
//如果方法名去掉set/get字符串以后與pojo + "id"想符合(大小寫不敏感),則視為ID
} else if((entity.getClass().getSimpleName() + "Id").equalsIgnoreCase(tempMethod.getName().substring(3))) {
idMethod = tempMethod;
iter.remove();
}
}
//把迭代指針移到第一位
iter = list.iterator();
while(iter.hasNext()) {
tempMethod = iter.next();
sql += tempMethod.getName().substring(3).toLowerCase() + "= ?,";
}
//去掉最后一個(gè),符號
sql = sql.substring(0,sql.lastIndexOf(","));
//添加條件
sql += " where " + idMethod.getName().substring(3).toLowerCase() + " = ?";
//SQL拼接完成,打印SQL語句
System.out.println(sql);
PreparedStatement statement = this.connection.prepareStatement(sql);
int i = 0;
iter = list.iterator();
while(iter.hasNext()) {
Method method = iter.next();
//此初判斷返回值的類型,因?yàn)榇嫒霐?shù)據(jù)庫時(shí)有的字段值格式需要改變,比如String,SQL語句是'"+abc+"'
if(method.getReturnType().getSimpleName().indexOf("String") != -1) {
statement.setString(++i, this.getString(method, entity));
} else if(method.getReturnType().getSimpleName().indexOf("Date") != -1){
statement.setDate(++i, this.getDate(method, entity));
} else if(method.getReturnType().getSimpleName().indexOf("InputStream") != -1) {
statement.setAsciiStream(++i, this.getBlob(method, entity),1440);
} else {
statement.setInt(++i, this.getInt(method, entity));
}
}
//為Id字段添加值
if(idMethod.getReturnType().getSimpleName().indexOf("String") != -1) {
statement.setString(++i, this.getString(idMethod, entity));
} else {
statement.setInt(++i, this.getInt(idMethod, entity));
}
//執(zhí)行SQL語句
statement.executeUpdate();
//關(guān)閉預(yù)編譯對象
statement.close();
//關(guān)閉連接
connection.close();
}
/**
* 刪除
*/
public void delete(T entity) throws Exception{
String sql = "delete from " + entity.getClass().getSimpleName().toLowerCase() + " where ";
//存放字符串為"id"的字段對象
Method idMethod = null;
//取得字符串為"id"的字段對象
List<Method> list = this.matchPojoMethods(entity, "get");
Iterator<Method> iter = list.iterator();
while(iter.hasNext()) {
Method tempMethod = iter.next();
//如果方法名中帶有ID字符串并且長度為2,則視為ID.
if(tempMethod.getName().lastIndexOf("Id") != -1 && tempMethod.getName().substring(3).length() == 2) {
//把ID字段的對象存放到一個(gè)變量中,然后在集合中刪掉.
idMethod = tempMethod;
iter.remove();
//如果方法名去掉set/get字符串以后與pojo + "id"想符合(大小寫不敏感),則視為ID
} else if((entity.getClass().getSimpleName() + "Id").equalsIgnoreCase(tempMethod.getName().substring(3))) {
idMethod = tempMethod;
iter.remove();
}
}
sql += idMethod.getName().substring(3).toLowerCase() + " = ?";
PreparedStatement statement = this.connection.prepareStatement(sql);
//為Id字段添加值
int i = 0;
if(idMethod.getReturnType().getSimpleName().indexOf("String") != -1) {
statement.setString(++i, this.getString(idMethod, entity));
} else {
statement.setInt(++i, this.getInt(idMethod, entity));
}
//執(zhí)行
conn.execOther(statement);
//關(guān)閉連接
conn.closeConn();
}
/**
* 通過ID查詢
*/
public T findById(Object object) throws Exception{
String sql = "select * from " + persistentClass.getSimpleName().toLowerCase() + " where ";
//通過子類的構(gòu)造函數(shù),獲得參數(shù)化類型的具體類型.比如BaseDAO<T>也就是獲得T的具體類型
T entity = persistentClass.newInstance();
//存放Pojo(或被操作表)主鍵的方法對象
Method idMethod = null;
List<Method> list = this.matchPojoMethods(entity, "set");
Iterator<Method> iter = list.iterator();
//過濾取得Method對象
while(iter.hasNext()) {
Method tempMethod = iter.next();
if(tempMethod.getName().indexOf("Id") != -1 && tempMethod.getName().substring(3).length() == 2) {
idMethod = tempMethod;
} else if((entity.getClass().getSimpleName() + "Id").equalsIgnoreCase(tempMethod.getName().substring(3))){
idMethod = tempMethod;
}
}
//第一個(gè)字母轉(zhuǎn)為小寫
sql += idMethod.getName().substring(3,4).toLowerCase()+idMethod.getName().substring(4) + " = ?";
//封裝語句完畢,打印sql語句
System.out.println(sql);
//獲得連接
PreparedStatement statement = this.connection.prepareStatement(sql);
//判斷id的類型
if(object instanceof Integer) {
statement.setInt(1, (Integer)object);
} else if(object instanceof String){
statement.setString(1, (String)object);
}
//執(zhí)行sql,取得查詢結(jié)果集.
ResultSet rs = conn.execQuery(statement);
//記數(shù)器,記錄循環(huán)到第幾個(gè)字段
int i = 0;
//把指針指向迭代器第一行
iter = list.iterator();
//封裝
while(rs.next()) {
while(iter.hasNext()) {
Method method = iter.next();
if(method.getParameterTypes()[0].getSimpleName().indexOf("String") != -1) {
//由于list集合中,method對象取出的方法順序與數(shù)據(jù)庫字段順序不一致(比如:list的第一個(gè)方法是setDate,而數(shù)據(jù)庫按順序取的是"123"值)
//所以數(shù)據(jù)庫字段采用名字對應(yīng)的方式取.
this.setString(method, entity, rs.getString(method.getName().substring(3).toLowerCase()));
} else if(method.getParameterTypes()[0].getSimpleName().indexOf("Date") != -1){
this.setDate(method, entity, rs.getDate(method.getName().substring(3).toLowerCase()));
} else if(method.getParameterTypes()[0].getSimpleName().indexOf("InputStream") != -1) {
this.setBlob(method, entity, rs.getBlob(method.getName().substring(3).toLowerCase()).getBinaryStream());
} else {
this.setInt(method, entity, rs.getInt(method.getName().substring(3).toLowerCase()));
}
}
}
//關(guān)閉結(jié)果集
rs.close();
//關(guān)閉預(yù)編譯對象
statement.close();
return entity;
}
/**
* 過濾當(dāng)前Pojo類所有帶傳入字符串的Method對象,返回List集合.
*/
private List<Method> matchPojoMethods(T entity,String methodName) {
//獲得當(dāng)前Pojo所有方法對象
Method[] methods = entity.getClass().getDeclaredMethods();
//List容器存放所有帶get字符串的Method對象
List<Method> list = new ArrayList<Method>();
//過濾當(dāng)前Pojo類所有帶get字符串的Method對象,存入List容器
for(int index = 0; index < methods.length; index++) {
if(methods[index].getName().indexOf(methodName) != -1) {
list.add(methods[index]);
}
}
return list;
}
/**
* 方法返回類型為int或Integer類型時(shí),返回的SQL語句值.對應(yīng)get
*/
public Integer getInt(Method method, T entity) throws Exception{
return (Integer)method.invoke(entity, new Object[]{});
}
/**
* 方法返回類型為String時(shí),返回的SQL語句拼裝值.比如'abc',對應(yīng)get
*/
public String getString(Method method, T entity) throws Exception{
return (String)method.invoke(entity, new Object[]{});
}
/**
* 方法返回類型為Blob時(shí),返回的SQL語句拼裝值.對應(yīng)get
*/
public InputStream getBlob(Method method, T entity) throws Exception{
return (InputStream)method.invoke(entity, new Object[]{});
}
/**
* 方法返回類型為Date時(shí),返回的SQL語句拼裝值,對應(yīng)get
*/
public Date getDate(Method method, T entity) throws Exception{
return (Date)method.invoke(entity, new Object[]{});
}
/**
* 參數(shù)類型為Integer或int時(shí),為entity字段設(shè)置參數(shù),對應(yīng)set
*/
public Integer setInt(Method method, T entity, Integer arg) throws Exception{
return (Integer)method.invoke(entity, new Object[]{arg});
}
/**
* 參數(shù)類型為String時(shí),為entity字段設(shè)置參數(shù),對應(yīng)set
*/
public String setString(Method method, T entity, String arg) throws Exception{
return (String)method.invoke(entity, new Object[]{arg});
}
/**
* 參數(shù)類型為InputStream時(shí),為entity字段設(shè)置參數(shù),對應(yīng)set
*/
public InputStream setBlob(Method method, T entity, InputStream arg) throws Exception{
return (InputStream)method.invoke(entity, new Object[]{arg});
}
/**
* 參數(shù)類型為Date時(shí),為entity字段設(shè)置參數(shù),對應(yīng)set
*/
public Date setDate(Method method, T entity, Date arg) throws Exception{
return (Date)method.invoke(entity, new Object[]{arg});
}
}
EmployeesDao繼承BaseDAO,可以直接使用父類的方法,增加了代碼的復(fù)用
package com.employees.dao;
import java.util.ArrayList;
import java.util.List;
import com.employees.po.Employees;
public class EmployeesDao extends BaseDAO<Employees> {
// 添加員工信息的操作
public boolean addEmployees(final Employees employees) throws Exception {
save(employees);
return true;
}
// 將員工信息添加到表格中
public List<Employees> addEmployees(int id) throws Exception {
List<Employees> lstEmployees = new ArrayList<Employees>();
Employees employees = findById(id);
// 將當(dāng)前封轉(zhuǎn)好的數(shù)據(jù)裝入對象中
lstEmployees.add(employees);
return lstEmployees;
}
public void deleteEmp(final Employees entity) throws Exception {
this.delete(entity);
}
public void updateEmp(final Employees entity) throws Exception {
this.update(entity);
}
}
po層的代碼就不貼了,現(xiàn)在用junit4做一下測試
package com.employees.dao;
import org.junit.Test;
import com.employees.po.Employees;
public class EmployeesDaoTest {
@Test
public void testAdd() throws Exception {
Employees emp = new Employees();
emp.setPname("tly");
emp.setPsex("男");
emp.setPbeliefs("xxxxx");
emp.setPaddr("天河");
emp.setPhobby("打籃球");
emp.setPsubject("計(jì)算機(jī)");
emp.setPtel("123456");
EmployeesDao dao = new EmployeesDao();
dao.addEmployees(emp);
}
@Test
public void testUpdate() throws Exception {
EmployeesDao dao = new EmployeesDao();
Employees emp = dao.findById(14);
emp.setPtel("999999");
dao.updateEmp(emp);
}
@Test
public void testdelete() throws Exception {
EmployeesDao dao = new EmployeesDao();
Employees emp = dao.findById(15);
dao.deleteEmp(emp);
}
}
經(jīng)過測試,這三個(gè)方法都能正常運(yùn)行,時(shí)間倉促,有些代碼是參考其他哥們的,有些地方可能考慮的不是很全面或者有些代碼會有冗余,BaseDAO中做通用crud操作沒有寫全,要是哪位小伙伴有興趣,可以接下去寫寫,比如查詢,批量化操作等等,如果測試通過的話,記得給我發(fā)一份啊,呵呵
以上這篇簡單通用JDBC輔助類封裝(實(shí)例)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用@Validated和@Valid 解決list校驗(yàn)的問題
這篇文章主要介紹了使用@Validated和@Valid 解決list校驗(yàn)的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
兩個(gè)List集合取相同重復(fù)數(shù)據(jù)的方法
今天小編就為大家分享一篇關(guān)于兩個(gè)List集合取相同重復(fù)數(shù)據(jù)的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
java微信公眾號開發(fā)(搭建本地測試環(huán)境)
這篇文章主要介紹了java微信公眾號開發(fā),主要內(nèi)容有測試公眾號與本地測試環(huán)境搭建,需要的朋友可以參考下2015-12-12
SpringBoot 如何實(shí)現(xiàn)異步編程
在SpringBoot的日常開發(fā)中,一般都是同步調(diào)用的,但實(shí)際中有很多場景非常適合使用異步來處理,本文就詳細(xì)的介紹一下SpringBoot 如何實(shí)現(xiàn)異步編程 ,具有一定的參考價(jià)值,感興趣的可以了解一下2021-12-12
教你開發(fā)腳手架集成Spring?Boot?Actuator監(jiān)控的詳細(xì)過程
這篇文章主要介紹了開發(fā)腳手架集成Spring?Boot?Actuator監(jiān)控的詳細(xì)過程,集成包括引入依賴配置文件及訪問驗(yàn)證的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05

