JDBC使用反射智能查询Oracle表数据
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员工表
提供与员工表对应的类,用于构造实例对象存储表数据
把表的每行看成一个对象,字段值就是属性值:
对应的类:含有对应字段的属性
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查询是否添加成功:
如图,插入成功