JDBC连接操作数据库的封装

本文探讨了在JDBC操作数据库时存在的重复代码问题,并提出了解决方案——将JDBC的六个基本步骤封装到工具类中。通过配置文件管理数据库连接信息,实现数据库变化时仅修改配置文件。同时,对增删改操作和查询操作进行了不同的封装,利用泛型和反射简化了代码,使得调用更加便捷。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题分析

使用JDBC技术操作数据库通常要经过6个步骤:加载驱动,获得连接,获得处理命令的对象,执行sql操作,结果处理,资源关闭;每次进行不同的操作就需要重写这几个步骤,因此存在大量重复代码,为了便于使用,可以将这几个步骤单独分为不同方法组合在同一个工具类中封装起来,在别处进行数据库操作直接调用这个工具类中方法即可。

代码实现

package com.jdbc_03.utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;

import com.alibaba.druid.pool.DruidDataSource;

/**
 * 自己封装的数据库工具类,包含一些操作数据库的简便方法
 * 1. 获取连接
 * 2. 关闭资源
 * 3..
 * @author mrchai
 */
public class DBUtils {

	private static String driverClass;
	private static String url;
	private static String user;
	private static String password;
	
	/**最大活动连接数*/
	private static int maxActive;
	/**最小闲置连接*/
	private static int minIdle;
	/**等待连接获取的最长时间*/
	private static long maxWait;
	
	/**druid数据源对象*/
	private static DruidDataSource dataSource;
	
	
	static{
		init();
	}
	
	public static void init(){
		try {
			Properties prop = new Properties();
			//加载属性文件
			prop.load(new FileInputStream("src/jdbc.properties"));
			//获取属性信息(连接数据库的相关字符串)
			driverClass = prop.getProperty("driverClass");
			url = prop.getProperty("url");
			user = prop.getProperty("user");
			password = prop.getProperty("password");
			
			maxActive = Integer.parseInt(prop.getProperty("maxActive"));
			minIdle = Integer.parseInt(prop.getProperty("minIdle"));
			maxWait = Long.parseLong(prop.getProperty("maxWait"));
			
			//创建数据源并配置
			dataSource = new DruidDataSource();
			dataSource.setDriverClassName(driverClass);
			dataSource.setUrl(url);
			dataSource.setUsername(user);
			dataSource.setPassword(password);
			dataSource.setMaxActive(maxActive);
			dataSource.setMinIdle(minIdle);
			dataSource.setMaxWait(maxWait);
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 2.获取连接
	 * @return
	 */
	public static synchronized Connection getConn(){
		if(dataSource == null || dataSource.isClosed()){
			init();
		}
		try {
			return dataSource.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 关闭连接池
	 */
	public static synchronized void closePool(){
		if(dataSource != null){
			dataSource.close();
		}
	}
	
	/**
	 * 6.关闭资源
	 * @param rs
	 * @param stat
	 * @param conn
	 */
	public static void close(ResultSet rs,Statement stat,Connection conn){
		try {
			if(rs != null){
				rs.close();
			}
			if(stat != null){
				stat.close();
			}
			if(conn != null){
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 封装通用的增、删、改操作(针对任何数据库表的更新操作(DML语句)都能通过该方法实现)
	 * @param sql
	 * @return
	 */
	public static int exeUpdate(Connection conn,String sql,Object... params){
		PreparedStatement ps = null;
		try {
			//编译sql语句获取预处理对象
			ps = conn.prepareStatement(sql);
			if(Objects.nonNull(params)){				
				for(int i = 0;i<params.length;i++){
					ps.setObject(i + 1, params[i]); 
				}
			}
			//执行更新
			int i = ps.executeUpdate();
			return i;
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(null, ps, null); 
		}
		return 0;
	}
	
	/**
	 * 封装通用的查询集合操作
	 * @param t 返回数据的类型 
	 * @param sql
	 * @param params
	 * @return
	 */
	public static <T> List<T> queryList(Class<T> t,String sql,Object...params){
		//声明空集合
		List<T> data = new ArrayList<>();
		//获取查询结果信息
		List<Map<String,Object>> list = getDataPair(sql,params);
		if(list.isEmpty()){
			return data;
		}
		for(Map<String,Object> map:list){
			T obj = parseMapToBean(map,t);
			data.add(obj);
		}
		return data;
	}
	
	/**
	 * 封装通用的查询对象操作
	 * @param t
	 * @param sql
	 * @param params
	 * @return
	 */
	public static <T> T queryOne(Class<T> t,String sql,Object...params){
		List<Map<String,Object>> list = getDataPair(sql, params);
		T obj = null;
		if(list.size()>0){
			Map<String,Object> map = list.get(0);
			obj = parseMapToBean(map,t);
			return obj;
		}
		return obj;
	}
	
	/**
	 * 将一个Map集合对象转换为一个JavaBean并返回
	 * @param map
	 * @param t
	 * @return
	 */
	private static <T> T parseMapToBean(Map<String, Object> map, Class<T> t) {
		T obj = null;
		try {
			//创建一个空实例
			obj = t.newInstance();
			//获取Map集合的键集
			Set<String> keys = map.keySet();
			for (String cname : keys) {
				//获取属性对象
				Field f = t.getDeclaredField(cname);
				//获取set方法的名称
				String setMethodName = "set"+cname.substring(0, 1).toUpperCase()+cname.substring(1);
				//获取set方法对象
				Method m = t.getMethod(setMethodName, f.getType());
				//执行方法
				m.invoke(obj, map.get(cname));
			}
		} catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return obj;
	}
	
	/**
	 * 解析指定查询语句,并将获取的数据(列名,列值)以集合的形式返回
	 * @param sql
	 * @param params
	 * @return
	 */
	private static List<Map<String,Object>> getDataPair(String sql,Object...params){
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<Map<String,Object>> list = new ArrayList<>();
		try {
			conn=getConn();
			ps = conn.prepareStatement(sql);
			if(Objects.nonNull(params)){
				for (int i = 0; i < params.length; i++) {
					ps.setObject(i+1, params[i]);
				}
			}
			rs = ps.executeQuery();
			//获取结果集元数据
			ResultSetMetaData rsmd = rs.getMetaData();
			//获取列总数,获取列名称,获取标签名,获取列值,将相关数据存储到map集合
			int count = rsmd.getColumnCount();
			while(rs.next()){
				//对结果集每遍历一次,获取一条数据(即每一个map对象)
				Map<String,Object> map = new HashMap<>();
				//遍历每一列
				for (int i = 1; i <= count; i++) {
					//获取列名称
					String columnName = rsmd.getColumnName(i);
					//获取列值
					Object value = rs.getObject(i);
					if(Objects.nonNull(value)){
						//将数据存入map
						map.put(columnName, value);
					}
				}
				//将Map集合存入List
				list.add(map);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs, ps, conn);
		}
		return list;
	}
}

说明

数据库和Druid连接池的配置信息统一写在一个配置文件中,当数据库改变时就不需要修改源代码而直接修改配置文件里的配置信息即可。sql增删改操作返回的是更新的数据行数,因此可以封装在一起,而查询操作需要返回查询的结果,相对比较复杂,将查询一条记录与查询所有记录分开更符合需求,利用到集合框架泛型和反射这些高级技术避免了大量重复的代码,外界调用查询方法可以和调用更新方法一样简单。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值