前言:我们熟知的做数据持久层的框架有很多,比如点的Hibernate,Mybatis,Spring Data(基于Hibernate)。其中Hibernate是全自动化的ORM框架。也就是做到了对象和表的直接映射,sql查询直接可以返回java对象。而要做到这一点就离不开java 的反射机制。本文就是利用反射模拟返回对象的这一过程。可以对ORM框架有更深的理解。
4.0.0
org.gosang
jdbc01
1.0-SNAPSHOT
mysql
mysql-connector-java
5.1.46
com.mchange
c3p0
0.9.5.2
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/mydb1
xxx
xxx
50
100
2
10
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50562
Source Host : localhost:3306
Source Schema : mydb1
Target Server Type : MySQL
Target Server Version : 50562
File Encoding : 65001
Date: 22/07/2020 23:45:00
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`Sid` int(10) NULL DEFAULT NULL,
`Sname` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`Ssex` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (2, '钱电', '男');
INSERT INTO `student` VALUES (3, '孙风', '男');
INSERT INTO `student` VALUES (4, '李云', '男');
INSERT INTO `student` VALUES (5, '周梅', '女');
INSERT INTO `student` VALUES (6, '吴兰', '女');
INSERT INTO `student` VALUES (7, '郑竹', '女');
INSERT INTO `student` VALUES (9, '张三', '女');
INSERT INTO `student` VALUES (10, '李四', '女');
INSERT INTO `student` VALUES (11, '李四', '女');
INSERT INTO `student` VALUES (12, '赵六', '女');
INSERT INTO `student` VALUES (13, '孙七', '女');
INSERT INTO `student` VALUES (14, '孙七', '男');
SET FOREIGN_KEY_CHECKS = 1;
package com.gosang.test;
public class Student {
private Integer Sid;
private String Sname;
private String Ssex;
public Integer getSid() {
return Sid;
}
public void setSid(Integer sid) {
Sid = sid;
}
public String getSname() {
return Sname;
}
public void setSname(String sname) {
Sname = sname;
}
public String getSsex() {
return Ssex;
}
public void setSsex(String ssex) {
Ssex = ssex;
}
@Override
public String toString() {
return "Student{" +
"Sid=" + Sid +
", Sname='" + Sname + '\'' +
", Ssex='" + Ssex + '\'' +
'}';
}
}
package com.gosang.utils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class DBUtils<T> {
public T getPOJO(Connection connection,String sql,Class clazz) {
PreparedStatement statement = null;
ResultSet resultSet = null;
T t = null;
try {
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while (resultSet.next()){
//从数据库中拿到对应的数据,然后就要把这些数据封装成对象。使用反射完成动态创建对象。
//按照我们通常的思路,从数据库拿到值后,手动创建一个Student对象后,把值set进去就好了。但是这样写就相当于给Student写了个DBUitls,
// 那DBUtils就失去了它作为通用工具的意义。故采用反射,动态的创建要返回对象。
//1.通过构造器创建好对象
Constructor<T> constructor = clazz.getConstructor(null);
t = constructor.newInstance();
//数据解析并返回
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
//表有很多列,每一列的属性可能都不同。故做以下逻辑判断
for (int i = 1;i<=columnCount;i++){
String columnName = metaData.getColumnName(i);
String typeName = metaData.getColumnTypeName(i);
Object columnVal = null;
switch (typeName){
case "INT":
columnVal = resultSet.getInt(columnName);
break;
case "VARCHAR":
columnVal = resultSet.getString(columnName);
break;
}
//2.拼接对象的set方法,用于设值。反射中的设置刚好和正常的思路反过来,是方法.invoke(对象,参数)/正常是对象.方法(参数)
//String method = "set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1);
Field field = clazz.getDeclaredField(columnName);
//拿到方法需要方法名和返回值类型,也就是对应变量的属性
Method method = clazz.getMethod("set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1),field.getType());
//设值
method.invoke(t,columnVal);
}
}
} catch (Exception throwables) {
throwables.printStackTrace();
}finally {
try {
resultSet.close();
statement.close();
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return t;
}
public List<T> getList(Connection connection,String sql,Class clazz){
PreparedStatement statement = null;
ResultSet resultSet = null;
List<T> Tlist = new ArrayList();
try {
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while (resultSet.next()){
//从数据库中拿到对应的数据,然后就要把这些数据封装成对象。使用反射完成动态创建对象。
//按照我们平时的思路,从数据库拿到值后,手动创建一个Student对象后,把值set进去就好了。但是这样写就相当于给Student写了个DBUitls,
// 那DBUtils就失去了它作为通用工具的意义。故采用反射,动态的创建要返回对象。
//1.通过构造器创建好对象
Constructor<T> constructor = clazz.getConstructor(null);
T t = constructor.newInstance();
//数据解析并返回
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 1;i<=columnCount;i++){
String columnName = metaData.getColumnName(i);
String typeName = metaData.getColumnTypeName(i);
Object columnVal = null;
switch (typeName){
case "INT":
columnVal = resultSet.getInt(columnName);
break;
case "VARCHAR":
columnVal = resultSet.getString(columnName);
break;
}
//2.拼接对象的set方法,用于设值。反射中的设置刚好和正常的思路反过来。是方法.invoke(对象,参数)。正常是对象.方法(参数)
//String method = "set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1);
Field field = clazz.getDeclaredField(columnName);
Method method = clazz.getMethod("set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1),field.getType());
method.invoke(t,columnVal);
}
Tlist.add(t);
}
} catch (Exception throwables) {
throwables.printStackTrace();
}finally {
try {
resultSet.close();
statement.close();
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return Tlist;
}
}
package com.gosang.test;
import com.gosang.utils.DBUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class c3p0Test {
public static void main(String[] args) {
ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
DBUtils dbUtils = new DBUtils<Student>();
Connection connection = null;
try {
connection = dataSource.getConnection();
//String sql = "SELECT * FROM student where SId = '02'";
String sql = "SELECT * FROM student";
/*Object pojo = dbUtils.getPOJO(connection, sql, Student.class);
System.out.println(pojo);*/
List<Student> list = dbUtils.getList(connection, sql, Student.class);
System.out.println(list);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}