表的字段名与类的属性名不相同的表数据的查询操作的封装
我们在实际编程中:
对于在数据库中的字段名我们通常喜欢起名为order_id等等类似的样子,在数据库中我们对于字段名的起名一般都是全部字母小写,然后多个单词之间使用_(下划线)隔开
而对于java类中的属性名我们通常设置为orderId等等类似的样子,在java中我们对于属性名起名一般都是首字母小写,从第二个单词开始首字母大写
所以在实际编程中就很可能我们的数据库中的字段名和与对应的Java类中的属性名根本就不相同
- 一旦我们的数据库中的字段名和对应的java类中的属性名不相同的时候,如果这个时候我们去使用反射给对应的java类的对象的该属性赋值的时候我们通常都是先获得该java类中的该属性对应的Field对象,但是我们要获得java类中的该属性对应的Field对象,那么我们就要使用对应的java类的运行时类的实例去调用getDeclaredField(String fieldname)方法去获得对应的java类中名为fieldname的属性的Field对象,但是这个时候我们不知道这Java类中的属性名是什么? 我们只能知道我们通过查询操作得到的结果集中的字段名(查询的结果集中的字段名我们可以通过结果集的元数据通过调用getcolumnName(int columnIndex)方法获得),但是这个时候我们的结果集中的字段名显然就是数据表中的字段名,这个时候又由于我们的数据表中的字段名和我们的java类中的属性名不相同,那么我们就不能获得Java类中名为getcloumnName()方法的返回值的Field对象
- 所以如果我们还是使用以前的方式对这个问题进行查询的时候,这个时候就会报一个异常(运行时异常)NoSuchFieldException --> 这个异常的意思就是表示找不到对应的Field对象
- 这个异常会在我们使用运行时类的对象调用getDeclaredField(String fieldname)方法的时候发生
- 那么我们如何解决上面的问题?
- 我们可不可以在执行的sql语句中加上列的别名(也就是给列起一个别名),让这个列的别名和我们java中的属性名相同,然后我们通过调用结果集元数据对象的getColumnName(int columnIndex)方法来获得对应的结果集中的列的别名?
- 这个时候想法是对的,但是这个时候我们去执行这个程序发现还是会报错,同样还是会出现一个NoSuchFieldException
- 那么我们要如何解决这个问题?(或者说到底是哪里出现了问题?)
- 这里其实是因为我们使用结果集的元数据对象调用的方法有问题, 我们使用ResultSetMetadata接口实现类的对象调用getColumnName(String columnIndex)方法的功能时获得结果集中的对应索引位置的列名,而不是获得对应索引位置的列的别名,那么我们如何获得结果集中的列的别名?
- 这里我们就要使用结果集的元数据对象调用getColumnLabel(String columnIndex)方法来获得结果集中对应索引位置的字段名 – > 其实这里我们就是使用getColumnLabel()方法代替了getColumnName()方法
这里我们给出具体代码:
- 注意: 这里是针对于结果集中只有一条记录的情况实现的通用编程,并且这个时候在数据库中的数据表中的字段名和java类中的属性名是不相同的
package jdbc.针对返回一条记录的通用查询操作;
import com.ffyc.bean.Player;
import com.ffyc.util.JDBCUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
public class OneForQueryPlus {
public static Player oneForQueryPlus(String sql,Object ...args) throws SQLException, IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Connection conn = JDBCUtils.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
for(int i = 0;i < args.length;i++){
ps.setObject(i+1,args[i]);
}
ResultSet rs = ps.executeQuery();
if (rs.next()) {
Player p = new Player();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
for(int i = 0;i < columnCount;i++) {
String columnName = rsmd.getColumnLabel(i + 1);
Object columnValue = rs.getObject(i + 1);
Field field = Player.class.getDeclaredField(columnName);
field.setAccessible(true);
field.set(p, columnValue);
}
return p;
}
return null;
}
public static void main(String[] args) throws ClassNotFoundException, SQLException, NoSuchFieldException, IllegalAccessException, IOException {
String sql = "\n" +
"SELECT id,`name`,birthday brithday,high height,wei weight,play\n" +
"FROM employees\n" +
"WHERE id = ?";
Player player = OneForQueryPlus.oneForQueryPlus(sql,5);
System.out.println(player);
}
}
我们将对应查找到的结果封装到了我们的自定义类Player中,下面我们给出Player类
package com.ffyc.bean;
import java.sql.Date;
public class Player {
private int id;
private String name;
private Date brithday;
private int height;
private String play;
private int teamId;
private int weight;
public Player(){
}
public Player(int id,String name,Date brithday,int height,String play,int teamId,int weight){
this.id = id;
this.name = name;
this.brithday = brithday;
this.play = play;
this.teamId = teamId;
this.weight = weight;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBrithday() {
return brithday;
}
public void setBrithday(Date brithday) {
this.brithday = brithday;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getPlay() {
return play;
}
public void setPlay(String play) {
this.play = play;
}
public int getTeamId() {
return teamId;
}
public void setTeamId(int teamId) {
this.teamId = teamId;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Player{" +
"id=" + id +
", name='" + name + '\'' +
", brithday=" + brithday +
", height=" + height +
", play='" + play + '\'' +
", teamId=" + teamId +
", weight=" + weight +
'}';
}
}
总结:
针对于数据库中的数据表中声明的字段名和java中对应的类的属性名不相同的情况:
- 必须在声明sql时使用类的属性名来命名查询的段的别名
- 使用ResultSetMetaData接口实现类的对象获取结果集中的列的别名的时候要使用getColumnLabel(int columnIndex)方法来代替getColumnName(int columnIndex)方法
如果在SQL语句中没有使用列的别名,这个时候我们使用getColumnLabel(int columnIndex)方法获得到的就是列名
ResultSet接口实现类中封装了结果集的数据内容,而ResultSetMetaData接口实现类的对象表示的是结果集的元数据,而元数据就是对数据进行修饰的数据,所以我们的ResultSetMetaData接口实现类的对象中封装的应该是修饰结果集中数据的数据 ----> 那么什么是修饰结果集中的数据的数据?
- 结果集中的数据是字段值,那么修饰字段值的当然就是字段名称,字段的数目等等
- 所以我们想要获得结果集中的字段值的时候我们就要使用ResultSet去获得,而我们如果想要获得结果集中的字段的名称或者字段的数目的时候我们就要通过ResultSetMetaData接口的实现类的对象
declared 英文含义: 声明
补充:
列的别名是相对于什么来说的?是相对于实际的数据库中的数据表还是相对于虚拟表?
- 是相对于虚拟表来说的,列的别名就是我们在查询操作中为结果集中的查询的列名起的一个别名,如果我们没有起别名这个时候查询的结果集中的列名默认就是和数据库中真实存在的数据表的列名相同
|