簡單通用JDBC輔助類封裝(實例)
哎,最近很好久沒寫點東西了,由于工作的原因,接觸公司自己研發(fā)的底層orm框架,偶然發(fā)現(xiàn)該框架在調(diào)用jdbc操作的時候參考的是hibernate 里面的SimpleJdbcTemplate,這里我想到了在大學(xué)的時候自己用過的一個簡單的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;
//四個方法
//method1: 創(chuàng)建數(shù)據(jù)庫的連接
public Connection getConntion(){
try {
//1: 加載連接驅(qū)動,Java反射原理
Class.forName(Config.CLASS_NAME);
//2:創(chuàng)建Connection接口對象,用于獲取MySQL數(shù)據(jù)庫的連接對象。三個參數(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;
}
}
}
平時的用上面的代碼能夠解決一些簡單的CRUD的應(yīng)用了,但是還有很多限制,比如每次程序拿連接都要new,這樣就給系統(tǒng)加大了負擔(dān),沒有事務(wù),沒有dataSource等等,今天看見一哥們在園里面寫的一篇用反射解決直接以對象參數(shù)的方式CRUD,這個我以前也寫過,沒寫完,主要是自己想寫一個通用的DButil,最后研究來研究去,發(fā)現(xiàn)越來越和hibernate里面的simpleJdbcTemplate接近了,所以就直接去看hibernate的源碼了,加上那段時間有些事,沒有時間,就將這件事閑置起來了,現(xiàn)在把這個東西補上,也給自己回顧一下下
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() + ",";
}
//去掉最后一個,符號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語句最后一個,符號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();
//此初判斷返回值的類型,因為存入數(shù)據(jù)庫時有的字段值格式需要改變,比如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");
//臨時Method對象,負責(zé)迭代時裝method對象.
Method tempMethod = null;
//由于修改時不需要修改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字段的對象存放到一個變量中,然后在集合中刪掉.
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() + "= ?,";
}
//去掉最后一個,符號
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();
//此初判斷返回值的類型,因為存入數(shù)據(jù)庫時有的字段值格式需要改變,比如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字段的對象存放到一個變量中,然后在集合中刪掉.
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;
}
}
//第一個字母轉(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)到第幾個字段
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的第一個方法是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類型時,返回的SQL語句值.對應(yīng)get
*/
public Integer getInt(Method method, T entity) throws Exception{
return (Integer)method.invoke(entity, new Object[]{});
}
/**
* 方法返回類型為String時,返回的SQL語句拼裝值.比如'abc',對應(yīng)get
*/
public String getString(Method method, T entity) throws Exception{
return (String)method.invoke(entity, new Object[]{});
}
/**
* 方法返回類型為Blob時,返回的SQL語句拼裝值.對應(yīng)get
*/
public InputStream getBlob(Method method, T entity) throws Exception{
return (InputStream)method.invoke(entity, new Object[]{});
}
/**
* 方法返回類型為Date時,返回的SQL語句拼裝值,對應(yīng)get
*/
public Date getDate(Method method, T entity) throws Exception{
return (Date)method.invoke(entity, new Object[]{});
}
/**
* 參數(shù)類型為Integer或int時,為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時,為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時,為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時,為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("計算機");
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)過測試,這三個方法都能正常運行,時間倉促,有些代碼是參考其他哥們的,有些地方可能考慮的不是很全面或者有些代碼會有冗余,BaseDAO中做通用crud操作沒有寫全,要是哪位小伙伴有興趣,可以接下去寫寫,比如查詢,批量化操作等等,如果測試通過的話,記得給我發(fā)一份啊,呵呵
以上這篇簡單通用JDBC輔助類封裝(實例)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot3整合 Elasticsearch 8.x 使用Repository構(gòu)
我們構(gòu)建了一個完整的 Spring Boot 3 和 Elasticsearch 8.x 的增刪改查示例應(yīng)用,使用 Spring Data Elasticsearch Repository,我們能夠快速實現(xiàn)對 Elasticsearch 的基本 CRUD 操作,簡化了開發(fā)流程,希望這個示例能夠幫助你理解如何在項目中有效使用 Elasticsearch!2024-11-11
Java編程IP地址和數(shù)字相互轉(zhuǎn)換代碼示例
這篇文章主要介紹了Java編程IP地址和數(shù)字相互轉(zhuǎn)換代碼示例,具有一定借鑒價值,需要的朋友可以參考下。2017-11-11
Spring中的監(jiān)聽器SpringApplicationRunListener詳解
這篇文章主要介紹了Spring中的監(jiān)聽器SpringApplicationRunListener詳解,命名我們就可以知道它是一個監(jiān)聽者,分析springboot啟動流程我們會發(fā)現(xiàn),它其實是用來在整個啟動流程中接收不同執(zhí)行點事件通知的監(jiān)聽者,需要的朋友可以參考下2023-11-11
關(guān)于同一個service調(diào)用service本身的方法
這篇文章主要介紹了關(guān)于同一個service調(diào)用service本身的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
Java實現(xiàn)將PPT轉(zhuǎn)為OFD過程詳解
本文將通過Java后端程序代碼展示如何實現(xiàn)將PPT幻燈片轉(zhuǎn)成OFD格式,文中的示例代碼講解詳細,對我們學(xué)習(xí)或工作有一定的幫助,需要的可以參考一下2022-01-01
基于Redisson實現(xiàn)注解式分布式鎖的示例代碼
這篇文章主要為大家詳細介紹了如何基于Redisson實現(xiàn)注解式分布式鎖,文中的示例代碼講解詳細,具有一定的參考價值,需要的可以了解一下2023-07-07
Java中防止數(shù)據(jù)重復(fù)提交超簡單的6種方法
在平時開發(fā)中,如果網(wǎng)速比較慢的情況下,用戶提交表單后,發(fā)現(xiàn)服務(wù)器半天都沒有響應(yīng),那么用戶可能會以為是自己沒有提交表單,就會再點擊提交按鈕重復(fù)提交表單,這篇文章主要給大家介紹了關(guān)于Java中防止數(shù)據(jù)重復(fù)提交超簡單的6種方法,需要的朋友可以參考下2021-11-11

