重新封装JDBC的连接、关闭资源、查询数据、更新数据 - 利用内省、反射、元数据 -- 强烈建议看一下自我感觉挺有用的

news/2024/5/18 21:43:01 标签: Java, JDBC, 内省, 反射

文章目录

      • 1. 数据库连接、关闭工具类 - JDBCUtil
      • 2. 内省JavaBean工具类 - BeanUtil
      • 3. 数据CRUD工具类 - 增删改查 - CURDUtil
      • 4. 总结

JDBCUtil_1">1. 数据库连接、关闭工具类 - JDBCUtil

这里没用到连接池,如果用连接池,可查看我以前写的文章,其实代码都差不多。改一下类,导一下包就行了。

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import org.junit.Test;

// 数据库连接、关闭工具类
public class JDBCUtil {
	
	// 类加载时自动运行静态代码块读取配置文件
	private static String url;
	private static String userName;
	private static String password;
	static {
		try {
			// 1. 加载配置文件
			Properties properties = new Properties();
			properties.load(JDBCUtil.class.getClassLoader().getResourceAsStream("DB.properties"));
			
			// 2. 加载驱动
			Class.forName(properties.getProperty("className"));
			
			// 3. 初始化成员属性
			url = properties.getProperty("url");
			userName = properties.getProperty("userName");
			password = properties.getProperty("password");
			
			
		} catch (IOException |  ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	// 返回一个数据库连接
	public static Connection getConnection() {
		try {
			return DriverManager.getConnection(url, userName, password);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	// 关闭数据库连接、SQL对象、结果集的资源
	public static void close(ResultSet rs, Statement statement, Connection conn) {
		
			try {
				if(rs != null) {
					rs.close();
				}
				
				if(statement != null) {
					statement.close();
				}
				if(conn != null) {
					conn.close();
				}
				
			} catch (SQLException e) {
				e.printStackTrace();
			}
		
	}
	
}

JavaBean__BeanUtil_80">2. 内省JavaBean工具类 - BeanUtil

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Date;
import java.util.HashMap;
import java.util.Map;

public class BeanUtil {
	
	// 获取JavaBean的  所有  属性名:set属性名() 的键值对
	public static Map<String, Method> getFields(Class<?> beanType) {
		
		Map<String, Method> map = new HashMap<String, Method>();
		
		try {
			
			//利用内省获取  BeanInfo 即  Bean的所有信息对象
			BeanInfo beanInfo = Introspector.getBeanInfo(beanType, Object.class);
			
			// 根据  BeanInfo对象  获取 关于  属性的描述器  - 可从中获取  get、set方法、属性的类型 这三个重要方法
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			
			// JavaBean有很多个属性,每个属性对应一个描述器
			for(PropertyDescriptor propertyDescriptor : propertyDescriptors) {
				
				// 获取属性名
				String beanPropertyName = propertyDescriptor.getName().toLowerCase();
				
				// 获取 set属性() 的方法Method对象
				Method writeMethod = propertyDescriptor.getWriteMethod();
				
				// 将上述两者放入 HashMap中
				map.put(beanPropertyName, writeMethod);
				
			}
			
		} catch (IntrospectionException e) {
			e.printStackTrace();
		}
		
		return map;
	}
	
	// 将 Util.Date 装为  数据库的sql.Date
	public static Date invertToSQLData(java.util.Date date) {
		if(date == null) {
			throw new RuntimeException("能别搞笑吗?我不需要空值");
		}
		return new Date(date.getTime());
	}
	
	
	// 针对Oracle进行类型转换 -- 转为JavaBean的属性类型
	public static Object invertToBeanAttributeType(Object value) {
		
		if(value instanceof BigDecimal) {
			value = ((BigDecimal) value).intValue();
		}else if ( value instanceof java.sql.Date) {
			value = new java.util.Date(((Date) value).getTime());
		}
		return value;
		
	}
	
}

3. 数据CRUD工具类 - 增删改查 - CURDUtil

考虑事务,其实这就数据库的Connection由程序代码的使用者自己关闭,数据的提交也由程序代码的使用者自己commit

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.junit.Test;

import top.linruchang.TestBean.Dept;

// 增删改查类
public class CRUDUtil {

	/**
	 * 
	 * @Description 不用处理事务,用于对表的更改 - DML
	 * @param sql  传入SQL语句 - DML语句
	 * @param args where的条件值
	 * @return -1表示并没有操纵表,1表示成功操纵表
	 */
	public static int update(String sql, Object... args) {

		Connection conn = JDBCUtil.getConnection();
		PreparedStatement prepareStatement = null;

		try {
			prepareStatement = conn.prepareStatement(sql);
			ParameterMetaData parameterMetaData = prepareStatement.getParameterMetaData();

			// 1. 判断sql参数与实参个数是否相同
			int fillValueCount = parameterMetaData.getParameterCount();
			if (fillValueCount != args.length) {
				throw new RuntimeException("SQL语句的填充数跟传入参数个数不符");
			}

			// 2.填充SQL语句
			for (int i = 0; i < args.length; i++) {
				prepareStatement.setObject(i + 1, args[i]);
			}

			// 3.执行SQL语句
			return prepareStatement.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(null, prepareStatement, conn);
		}

		return -1;
	}

	/**
	 * 
	 * @Description 考虑事务,用于对表的更改 - DML
	 * @param sql  传入SQL语句 - DML语句
	 * @param args where的条件值
	 * @return -1表示并没有操纵表,1表示成功操纵表
	 */
	public static int update(Connection conn, String sql, Object... args) {

		PreparedStatement prepareStatement = null;

		try {
			prepareStatement = conn.prepareStatement(sql);
			ParameterMetaData parameterMetaData = prepareStatement.getParameterMetaData();

			// 1. 判断sql参数与实参个数是否相同
			int fillValueCount = parameterMetaData.getParameterCount();
			if (fillValueCount != args.length) {
				throw new RuntimeException("SQL语句的填充数跟传入参数个数不符");
			}

			// 2.填充SQL语句
			for (int i = 0; i < args.length; i++) {
				prepareStatement.setObject(i + 1, args[i]);
			}

			// 3.执行SQL语句
			return prepareStatement.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(null, prepareStatement, null);
		}

		return -1;
	}

	/**
	 * 
	 * @Description 不考虑事务,查询数据,返回一个容器 - 不同的隔离级别有对数据行进行锁定,返回数据不一致
	 * @param beanType 传入JavaBean的反射对象
	 * @param SQL      查询SQL语句 - DQL
	 * @param args     where的条件值
	 * @return 返回List<T>容器对象
	 */
	public static <T> List<T> query(Class<T> beanType, String SQL, Object... args) {

		// 1. 获取数据库连接
		Connection conn = JDBCUtil.getConnection();
		PreparedStatement statement = null;
		ResultSet rs = null;

		// 2. 用来存储查找到的 行记录 Bean对象
		List<T> lists = new ArrayList<T>();

		try {
			// 3. 编译SQL语句 - 还没编译,代码运行时在编译
			statement = conn.prepareStatement(SQL);

			// 4. 获取 PrepareStatement的元数据,用于查看SQL语句中有多少个填充符。
			ParameterMetaData parameterMetaData = statement.getParameterMetaData();
			int fillValueCount = parameterMetaData.getParameterCount();
			if (fillValueCount != args.length) {
				throw new RuntimeException("SQL语句的填充数跟传入参数个数不符");
			}

			// 5. 填充SQL语句
			for (int i = 0; i < args.length; i++) {
				statement.setObject(i + 1, args[i]);
			}

			// 6. 执行SQL语句,并且得到结果集的元数据,用于获取 列名、以及 列数
			rs = statement.executeQuery();
			ResultSetMetaData metaData = rs.getMetaData();

			// 7. 进行行记录的Bean封装
			while (rs.next()) {

				// 8.利用反射生成一个 JavaBean对象
				T beanObj = beanType.newInstance();

				// 9. 获取该JavaBean所有的set方法
				Map<String, Method> map = BeanUtil.getFields(beanType);
				String columnName = null;
				for (int i = 0; i < metaData.getColumnCount(); i++) {
					// 10. 获取表在数据库的列名, getColumnLabel可能获取到查询语句的列别名,故不使用这个
					columnName = metaData.getColumnName(i + 1).toLowerCase();

					// 11. 查看Map里面是否有该列的set方法,用于设置字段
					if (!map.containsKey(columnName)) {
						throw new RuntimeException("可能你Bean字段、set方法写错了,请检查一下");
					}

					// 12. 获取列值,下面的if判断是用于oracle数据的number类型,我没有调试过其他数据库。读者可以自行在这基础上进行优化
					Object value = rs.getObject(columnName);
					value = BeanUtil.invertToBeanAttributeType(value);
					
					// 13. 调用对应字段的set属性方法,设置 JavaBean对象
					map.get(columnName).invoke(beanObj, value);

				}

				lists.add(beanObj);
			}

		} catch (SQLException | InstantiationException | IllegalAccessException | IllegalArgumentException
				| InvocationTargetException e) {
			e.printStackTrace();
		} finally {

			// 14. 关闭连接
			JDBCUtil.close(rs, statement, conn);
		}

		// 15. 返回javaBean结果集
		return lists;
	}

	/**
	 * 
	 * @Description 考虑事务,查询数据,返回一个容器
	 * @param beanType 传入JavaBean的反射对象
	 * @param SQL      查询SQL语句 - DQL
	 * @param args     where的条件值
	 * @return 返回List<T>容器对象
	 */
	public static <T> List<T> query(Connection conn, Class<T> beanType, String SQL, Object... args) {
		
		PreparedStatement statement = null;
		ResultSet rs = null;

		// 2. 用来存储查找到的 行记录 Bean对象
		List<T> lists = new ArrayList<T>();

		try {
			// 3. 编译SQL语句 - 还没编译,代码运行时在编译
			statement = conn.prepareStatement(SQL);

			// 4. 获取 PrepareStatement的元数据,用于查看SQL语句中有多少个填充符。
			ParameterMetaData parameterMetaData = statement.getParameterMetaData();
			int fillValueCount = parameterMetaData.getParameterCount();
			if (fillValueCount != args.length) {
				throw new RuntimeException("SQL语句的填充数跟传入参数个数不符");
			}

			// 5. 填充SQL语句
			for (int i = 0; i < args.length; i++) {
				statement.setObject(i + 1, args[i]);
			}

			// 6. 执行SQL语句,并且得到结果集的元数据,用于获取 列名、以及 列数
			rs = statement.executeQuery();
			ResultSetMetaData metaData = rs.getMetaData();

			// 7. 进行行记录的Bean封装
			while (rs.next()) {

				// 8.利用反射生成一个 JavaBean对象
				T beanObj = beanType.newInstance();

				// 9. 获取该JavaBean所有的set方法
				Map<String, Method> map = BeanUtil.getFields(beanType);
				String columnName = null;
				for (int i = 0; i < metaData.getColumnCount(); i++) {
					// 10. 获取表在数据库的列名, getColumnLabel可能获取到查询语句的列别名,故不使用这个
					columnName = metaData.getColumnName(i + 1).toLowerCase();

					// 11. 查看Map里面是否有该列的set方法,用于设置字段
					if (!map.containsKey(columnName)) {
						throw new RuntimeException("可能你Bean字段、set方法写错了,请检查一下");
					}

					// 12. 获取列值,下面的if判断是用于oracle数据的number类型,我没有调试过其他数据库。读者可以自行在这基础上进行优化
					Object value = rs.getObject(columnName);
					value = BeanUtil.invertToBeanAttributeType(value);

					// 13. 调用对应字段的set属性方法,设置 JavaBean对象
					map.get(columnName).invoke(beanObj, value);

				}

				lists.add(beanObj);
			}

		} catch (SQLException | InstantiationException | IllegalAccessException | IllegalArgumentException
				| InvocationTargetException e) {
			e.printStackTrace();
		} finally {

			// 14. 关闭连接
			JDBCUtil.close(rs, statement, null);
		}

		// 15. 返回javaBean结果集
		return lists;
	}
	
}

4. 总结

封装之后我们到时查询、修改表数据的时候,只需要提供 SQL语句、以及填充的参数即可以了


http://www.niftyadmin.cn/n/1658100.html

相关文章

文件夹标记为model_「正点原子NANO STM32开发板资料连载」第五章 SYSTEM 文件夹介绍...

1&#xff09;实验平台&#xff1a;ALIENTEK NANO STM32F411 V1开发板2&#xff09;摘自《正点原子STM32F4 开发指南&#xff08;HAL 库版》关注官方微信号公众号&#xff0c;获取更多资料&#xff1a;正点原子第五章 SYSTEM 文件夹介绍第三章&#xff0c;我们介绍了如何在 MDK…

linux 创建系统服务,Linux系统服务 创建Linux系统服务的方法

想了解创建Linux系统服务的方法的相关内容吗&#xff0c;在本文为您仔细讲解Linux系统服务的相关知识和一些Code实例&#xff0c;欢迎阅读和指正&#xff0c;我们先划重点&#xff1a;Linux系统服务&#xff0c;下面大家一起来学习吧。linux环境&#xff1a;ubuntu#! /bin/sh# …

linux修改weblogic环境变量,Linux中安装weblogic10和JDK5及配置环境变量(精)

Linux 中安装 weblogic10和 JDK5及配置环境变量Linux 中安装 weblogic10和 JDK5及配置环境变量好久没发技术贴了,因为最近也没学到啥,荒废了快,现在学了点东西,赶紧记上,不然真白学了,我特别不相信我的脑袋,过两天肯定忘的一干二净, 这是非常肯定的,对此我也在调查原因!这两天装…

越疆dobot机械臂_越疆联合牛津大学教育专家推出 AI 工程师教材及课程,接轨 AI 国际教育市场...

深圳湾现场报道&#xff0c;10 月 15 日&#xff0c;在深圳举行的「智在臂得」新品发布会上&#xff0c;AI 教育机器人和解决方案公司越疆科技宣布&#xff0c;将联合牛津大学推出教材《赋能下一代 AI 工程师》及物联网数据科学课程&#xff0c;旨在结合机器学习、云计算和机器…

linux 容器 ip,CentOS 7下为Docker容器分配固定IP

我们在使用docker run创建Docker容器时&#xff0c;可以用--net选项指定容器的网络模式&#xff0c;Docker有以下4种网络模式&#xff1a;host模式&#xff0c;使用--nethost指定。container模式&#xff0c;使用--netcontainer:NAME_or_ID指定。none模式&#xff0c;使用--net…

get request uni 参数_TP5请求(request)变量

可以通过Request对象完成全局输入变量的检测、获取和安全过滤&#xff0c;支持包括$_GET、$_POST、$_REQUEST、$_SERVER、$_SESSION、$_COOKIE、$_ENV等系统变量&#xff0c;以及文件上传信息。检测变量是否设置可以使用has方法来检测一个变量参数是否设置&#xff0c;如下&…

vue 页面引入多个内部js_.html多页页面引入vue.js怎么开发?

vue.config里可以配置多页面应用module.exports {// publicPath: process.env.NODE_ENV production// ? https://dev-cdp.cn-siit.com/// : , // http://bri-e.cn-siit.com/cdp/#/tags-manage 用 /cdp/dist/publicPath: ./,outputDir: dist,assetsDir: ,pages: {index: {// …

linux编程内容,Linux下C编程基础之:实验内容

3.7实验内容3.7.1vi使用练习1&#xff0e;实验目的通过指定指令的vi操作练习&#xff0c;使读者能够熟练使用vi中的常见操作&#xff0c;并且熟悉vi的3种模式&#xff0c;如果读者能够熟练掌握实验内容中所要求的内容&#xff0c;则表明对vi的操作已经很熟练了。2&#xff0e;实…