JDBC使用Java反射万能查询Oracle表数据、插入数据——【JDBC编程】

JDBC编程中使用反射技术,动态获取Oracle表数据

1、反射的概念

静态加载:在编译期,当一个类Test中需要其他类来完成操作时,Test类在编译前,jvm先加载Test类中的其他类,不管这些类未来用到或者用不到都需要加载到jvm中编译。这种加载模式成为静态加载。

动态加载:在运行时,根据程序具体的需要去动态加载一个类到jvm中,这个加载模式成为动态加载。

Class关键字:Class位于java.lang中,称为 类 类型,也就是说,Object类、Person类、ArrayList类等都是Class类型的对象。如果要表示具体的类类型,可以使用Class< Person >;如果要表示未知的类类型,使用Class<?>

Class 对象就表示jvm加载到共享区的字节码文件,jvm只加载一次。

2、构建Oracle数据库连接方法,关闭方法——便于调用

同时为了方便也构建了静态常量类,方便调用,存储了 驱动 URL 数据库用户名以及密码

静态常量类:

package com.jdbc.reflect;

public class DBInfo {
	public static final String ORCL_DRIVER = "oracle.jdbc.driver.OracleDriver";
	public static final String ORCL_URL = "jdbc:oracle:thin:@localhost:1521:orcl";
	public static final String ORCL_USER = "SCOTT";
	public static final String ORCL_PWD = "tiger";
}

Oracle连接方法与关闭方法类:

package com.jdbc.reflect;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @since 2019-8-3
 * @author Cool.R
 * @version 1.0
 */
public class DBhelper {
	// 数据库连接获取方法
	public static Connection getConnection() {
		Connection connection = null;
		try {
			Class.forName(DBInfo.ORCL_DRIVER);
			connection = DriverManager.getConnection(DBInfo.ORCL_URL, DBInfo.ORCL_USER, DBInfo.ORCL_PWD);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return connection;
	}

	// 数据库资源关闭方法
	public static void close(Connection connection, Statement statement, ResultSet resultSet) {
		try {
			if (resultSet != null) {
				resultSet.close();
			}
			if (statement != null) {
				statement.close();
			}
			if (connection != null) {
				connection.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			resultSet = null;
			statement = null;
			connection = null;
		}
	}
}

Oracle数据库中的表 EMP表为例

emp员工表
emp员工表

提供与员工表对应的类,用于构造实例对象存储表数据

把表的每行看成一个对象,字段值就是属性值:

对应的类:含有对应字段的属性

package com.jdbc.reflect;

import java.util.Date;
/**
 * @since 2019-8-3
 * @author Cool.R
 * @version 1.0
 */
public class EMP {
	private int empno;
	private String ename;
	private String job;
	private int mgr;
	private Date hiredate;
	private double sal;
	private double comm;
	private int deptno;

	// 设置器与访问器
	public int getEmpno() {
		return empno;
	}

	public void setEmpno(int empno) {
		this.empno = empno;
	}

	public String getEname() {
		return ename;
	}

	public void setEname(String ename) {
		this.ename = ename;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	public int getMgr() {
		return mgr;
	}

	public void setMgr(int mgr) {
		this.mgr = mgr;
	}

	public Date getHiredate() {
		return hiredate;
	}

	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}

	public double getSal() {
		return sal;
	}

	public void setSal(double sal) {
		this.sal = sal;
	}

	public double getComm() {
		return comm;
	}

	public void setComm(double comm) {
		this.comm = comm;
	}

	public int getDeptno() {
		return deptno;
	}

	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}

	// 有参构造
	public EMP(int empno, String ename, String job, int mgr, Date hiredate, double sal, double comm, int deptno) {
		super();
		this.empno = empno;
		this.ename = ename;
		this.job = job;
		this.mgr = mgr;
		this.hiredate = hiredate;
		this.sal = sal;
		this.comm = comm;
		this.deptno = deptno;
	}

	// 无参构造
	public EMP() {
		super();
	}

	// 重写toString
	@Override
	public String toString() {
		return "EMP [empno=" + empno + ", ename=" + ename + ", job=" + job + ", mgr=" + mgr + ", hireDate=" + hiredate
				+ ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + "]";
	}

}

表查询——记录查询数据:

查询emp表,然后将数据写入用反射构造出的对象内,将对象存储到list中:

package com.jdbc.reflect;

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.util.ArrayList;
import java.util.List;

public class OracleDAOImpl {
	// 该方法用于构造设置器名
	public static String creatSetor(String coluName) {
		String setor = null;
		setor = "set" + coluName.substring(0, 1).toUpperCase() + coluName.substring(1).toLowerCase();
		return setor;
	}

	public static List<?> getRows(String whereSQL, Object[] params, Class<?> clazz) {
		// 由于集合存储的对象类型不确定,故泛型设置为Object
		List<Object> list = new ArrayList<Object>();
		// 获取反射对象的类名---也是查询表的表名
		String className = clazz.getSimpleName();
		String sql = "select * from " + className + whereSQL;

		// 建立数据库连接
		Connection conn = DBhelper.getConnection();
		// 使用预处理sql语句方法
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = conn.prepareStatement(sql);
			// 循环把params中的所有参数绑定的ps中--拼接sql语句参数,使其成为完整的sql语句
			for (int i = 0; i < params.length; i++) {
				ps.setObject(i + 1, params[i]);
			}
			// 运行预编译sql语句,获得行结果集
			rs = ps.executeQuery();
			// 遍历结果集rs,并获取rs每行内的数据
			while (rs.next()) {
				// 利用反射获取类对象,由于不确定类,用object代替
				Object instance = clazz.newInstance();
				// 获取此 ResultSet 对象的列的编号、类型和属性
				// 并返回ResultSetMetaData
				ResultSetMetaData rsmd = rs.getMetaData();
				System.out.println("获取列数:" + rsmd.getColumnCount());
				// 遍历每行内的列元素
				for (int i = 0; i < rsmd.getColumnCount(); i++) {
					// 获取每行中每个字段的名称,oracle从1开始
					String coluName = rsmd.getColumnName(i + 1);
					// 获取对应列值
					Object coluVal = rs.getObject(i + 1);
					// 获取类的属性--属性名全小写
					// 为根据给定的属性名获取指定的属性
					// Field内包含修饰符,类型,属性名等内容
					Field field = clazz.getDeclaredField(coluName.toLowerCase());
					// 创建Method用于设置属性值
					// 获取类的设置方法,用于调用来设置实例对象的对应属性值
					// 设置器方法名需要另行拼接
					Method method = clazz.getDeclaredMethod(creatSetor(coluName), field.getType());
					// 开始调用获取的set设置器方法,为对应的属性字段填入从数据库内获取的值
					// 先对获取的列属性值的类型,再根据判断的类型进行相应的类的属性要求进行强转后写入方法

					// 如果sql查到的值数据类型是Number型,
					// Oracle中的number值读入java中会被设置为BigDecimal值,
					// 它的直接父类是Java中的number,所以只要判断coluVal
					// 是不是Number的实现类即可
					if (coluVal instanceof Number) {
						// 判断类的实例化对象的属性数据类型
						// 即类内创建的属性的数据类型

						// 如果类属性是int或integer类型
						if (field.getType().getName().equals("int")
								|| field.getType().getName().equals("java.lang.Integer")) {
							method.invoke(instance, ((Number) coluVal).intValue());
						} else if (field.getType().getName().equals("float")
								|| field.getType().getName().equals("java.lang.Float")) {
							method.invoke(instance, ((Number) coluVal).doubleValue());
						} else if (field.getType().getName().equals("double")
								|| field.getType().getName().equals("java.lang.Double")) {
							method.invoke(instance, ((Number) coluVal).doubleValue());
						}

						// 如果获取的列值为空,则不调用该属性的设置器方法,使用系统给的默认值

					} else if (coluVal == null) {
						// 方法放空,不进行任何处理。默认使用类给的默认值

					} else {
						// 如果没有上诉情况则直接设置器方法,把获取的字段值赋给对应属性
						method.invoke(instance, coluVal);
					}
				}
				// 把设置好属性数据的实例对象放入集合list中
				list.add(instance);
			}
			// 循环体结束处
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 关闭数据库资源,自定义方法
			DBhelper.close(conn, ps, rs);
		}
		return list;
	}

	// main方法
	public static void main(String[] args) {
		// where前有空格,用于拼接正确的sql语句
		// String whereSQL = " where deptno = ? ";
		// List<?> rows = getRows(whereSQL, new Object[] {10}, EMP.class);
		// //where条件是部门10,故传入10
		String whereSQL = " ";
		// object[] 数组内用于存储 查询条件,由于不知道查询条件的数据类型所以使用object数组
		// 提供的whereSQL语句中出现几个问号?就在Object[]数组内设置几个条件值
		// EMP是你写的用于接收查询结果的类名,EMP.class为传入的EMP的class对象
		List<?> rows = getRows(whereSQL, new Object[] {}, EMP.class);// whereSQL条件放空故不传任何值
		// 遍历集合
		for (Object object : rows) {
			System.out.println(object.toString());
		}
	}
}

运行效果:

查询效果

表插入——插入实现:

插入Insert方法实现:

package com.jdbc.reflect;

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.SQLException;
import java.util.Date;

public class DAOInsert {
	// 根据传入的属性名构造对应的访问器方法名
	public static String creatGetter(String fieldName) {
		String getter = null;

		getter = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1).toLowerCase();

		return getter;
	}

	// 插入操作方法 insert
	public static int insert(Object obj) {
		int r = 0;
		// 利用反射生成类的class对象
		Class<?> clazz = obj.getClass();
		// 建立数据库连接,调用了自定义方法
		Connection conn = DBhelper.getConnection();
		// 构建查询sql语句
		String sql = "insert into " + clazz.getSimpleName() + " values(?,?,?,?,?,?,?,?)";
		// 声明为预处理sql
		PreparedStatement ps = null;
		// 声明属性名,方便后边调用;
		String fieldName = null;
		try {
			// 向sql预处理中传入构建好的sql语句
			ps = conn.prepareStatement(sql);
			// 开始绑定参数

			// 获取类对象的属性数组
			Field[] field = clazz.getDeclaredFields();
			// 遍历属性数组,获取属性名,传入用于构建访问器方法名的creatGetter(String fieldName)中
			for (int i = 0; i < field.length; i++) {
				// System.out.println(field[i].getName());
				fieldName = field[i].getName();
				// 獲取類的第一個屬性名
				System.out.println(fieldName);
				System.out.println("输出访问器方法名:->" + creatGetter(fieldName));
				// 利用反射获取对应方法名的方法--无参方法
				Method md = clazz.getDeclaredMethod(creatGetter(fieldName));
				// 接收md(访问器方法传回来的值)
				Object objVal = md.invoke(obj);
				// 对objVal的值类型进行判断
				if (field[i].getType().getSimpleName().equals("Date")) {
					// 将对象属性时间转换成util下的时间方便提取时间戳
					java.util.Date tsp = (Date) objVal;
					// 使用util.date提从的getTime()获取时间戳的方法,获取对象属性时间戳
					// 然后由得到的时间戳将其准换成sql下的时间方便插入
					ps.setObject(i + 1, new java.sql.Date(tsp.getTime()));
				} else {
					// 其他情况 java中的数据类型数据可以直接插入oracle中
					ps.setObject(i + 1, objVal);
				}

			}
			// 执行预处理sql语句 没处理一条则返回0;处理成功几条返回几,这里只提交了一个对象,故只返回1
			r = ps.executeUpdate();
			// 提交事务
			conn.commit();
			// 关闭数据库资源//使用了自定义的方法
			DBhelper.close(conn, ps, null);

		} catch (SQLException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		// 返回处理成功的insert语句条数,这里只处理了一条,如果成功返回值应该是1
		return r;
	}

	public static void main(String[] args) {
		// 利用有参构造方法生成实例化对象
		EMP emp = new EMP(1080, "CaiZi", "Idiot", 7788, new Date(), 333.0, 3.3, 10);
		// 将实例化对象传入自定义的静态插入方法中
		int result = insert(emp);
		System.out.println("添加结果1、成功 0、失败:" + result);
	}
}

执行效果:

控制台
插入成功效果

查看Oracle 中 emp表

emp查询是否添加成功:
插入成功
如图,插入成功

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值