使用注释将JDBC ResultSet映射到对象
使用Annotations以通用方式将JDBC ResultSet映射到Object的简单代码
介绍
本技巧演示了如何使用Annotations将JDBC ResultSet映射到Object
背景
本技巧使用Annotations和Reflection。所以这些基础知识将有所帮助。
使用代码
首先,我们需要一个带注释的POJO(Plain Old Java Object)来保存在ResultSet中检索的值
属性名称可以是任何内容,注释“column”指定SQL列名称。需要注释“Entity”来标记能够保存数据库值的类
下面是SamplePojo.java
隐藏 收缩 复制代码
import javax.persistence.Column;
import javax.persistence.Entity;
@Entity
public class SamplePojo {
@Column(name="User_Id")
private int id;
@Column(name="User_Name")
private String name;
@Column(name="Address")
private String address;
@Column(name="Gender")
private boolean gender;
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
@Override
public String toString() {
return "id: " + id + "\n" +
"name: " + name + "\n"+
"address: " + address + "\n" +
"gender: " + (gender ? "Male" : "Female") + "\n\n";
}
}
将ResultSet映射到Object的代码 - ResultSetMapper.java
下面是将ResultSet映射到此SamplePojo的Object并返回包含SamplePojo对象的ArrayList的代码
隐藏 收缩 复制代码
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import org.apache.commons.beanutils.BeanUtils;
public class ResultSetMapper<T> {
@SuppressWarnings("unchecked")
public List<T> mapRersultSetToObject(ResultSet rs, Class outputClass) {
List<T> outputList = null;
try {
// make sure resultset is not null
if (rs != null) {
// check if outputClass has 'Entity' annotation
if (outputClass.isAnnotationPresent(Entity.class)) {
// get the resultset metadata
ResultSetMetaData rsmd = rs.getMetaData();
// get all the attributes of outputClass
Field[] fields = outputClass.getDeclaredFields();
while (rs.next()) {
T bean = (T) outputClass.newInstance();
for (int _iterator = 0; _iterator < rsmd
.getColumnCount(); _iterator++) {
// getting the SQL column name
String columnName = rsmd
.getColumnName(_iterator + 1);
// reading the value of the SQL column
Object columnValue = rs.getObject(_iterator + 1);
// iterating over outputClass attributes to check if any attribute has 'Column' annotation with matching 'name' value
for (Field field : fields) {
if (field.isAnnotationPresent(Column.class)) {
Column column = field
.getAnnotation(Column.class);
if (column.name().equalsIgnoreCase(
columnName)
&& columnValue != null) {
BeanUtils.setProperty(bean, field
.getName(), columnValue);
break;
}
}
}
}
if (outputList == null) {
outputList = new ArrayList<T>();
}
outputList.add(bean);
}
} else {
// throw some error
}
} else {
return null;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return outputList;
}
}
函数mapRersultSetToObject将resultset映射到SamplePojo类型的ArrayList。它首先检查outputClass是否具有'Entity'注释。该函数的核心逻辑是,它获取outputClass中具有注释“Column”的属性。如果此属性具有“列”注释,其“name”值与SQL列名称相同,则SQL列的值将设置为outputClass中的当前属性。
使用ResultSetMapper类
隐藏 收缩 复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
public class SampleMain {
public static void main(String ...args){
try {
ResultSetMapper<SamplePojo> resultSetMapper = new ResultSetMapper<SamplePojo>();
ResultSet resultSet = null;
// simple JDBC code to run SQL query and populate resultSet - START
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String database = "jdbc:odbc:AkDb";
Connection connection = DriverManager.getConnection( database ,"","");
PreparedStatement statement = connection.prepareStatement("SELECT * FROM UsersSample");
resultSet = statement.executeQuery();
// simple JDBC code to run SQL query and populate resultSet - END
List<SamplePojo> pojoList = resultSetMapper.mapRersultSetToObject(resultSet, SamplePojo.class);
// print out the list retrieved from database
if(pojoList != null){
for(SamplePojo pojo : pojoList){
System.out.println(pojo);
}
}else{
System.out.println("ResultSet is empty. Please check if database table is empty");
}
connection.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
兴趣点
不使用任何框架(ibatis / hibernate等),可以避免从ResultSet映射单个列的痛苦。如果要映射更多列,只需向POJO添加更多属性,使用正确的列名称对它们进行注释即可完成!
如果查询很复杂,可能非常复杂,包含很多列的大量连接,只需使用SQL别名重命名每个列的唯一名称,并在注释POJO时使用此列别名
请随时分享您的意见,补充或投诉。