代码实现:
/**
* 根据主键查询数据。
* 要求实体类型的属性名称和数据库表的字段名称完全一致。
* 要求实体类型的类名于数据库的表名有直接关系
* 表名 : tb_类名
* @param clazz : 要查询的数据的java类型。 直接可以代表数据 库中的表名和字段名。
* @param id : 要查询的数据的主键。 主键数据为id字段。
*/
@Override
public Object getObjectById(Class clazz, Serializable id) {
// 要执行的查询语句
String sql = "";
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
// 查询结果
Object result = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "test", "test");
conn.setAutoCommit(false);
sql = createGetObjectByIdSQL(clazz);
System.out.println("sql : " + sql);
pstm = conn.prepareStatement(sql);
pstm.setObject(1, id);
rs = pstm.executeQuery();
// 处理结果集。
if(rs.next()){
// 缺少字段和对象属性的映射
// Object columnValue = rs.getObject("字段名");
Method[] methods = clazz.getMethods();
// 检索方法中的set方法。 将查询的字段值,注入到对象中。
result = clazz.newInstance();
for(Method method : methods){
String methodName = method.getName();
if(methodName.startsWith("set") && methodName.length() > 3){
// 获取字段名称
String columnName = methodName.substring(3);
// 获取方法的参数表, 判断参数类型。 决定调用什么方法获取字段数据。
// 如: 参数类型是Integer, 调用getInt方法。
Object columnValue = null;
Class[] parameterTypes = method.getParameterTypes();
if(parameterTypes.length == 1){
Class type = parameterTypes[0];
if(type == Integer.class){
columnValue = rs.getInt(columnName);
}else if(type == String.class){
columnValue = rs.getString(columnName);
}else if(type == Double.class){
columnValue = rs.getDouble(columnName);
}else if(type == int.class){
columnValue = rs.getInt(columnName);
}
}
// 根据字段名称获取字段数据
// 将查询结果保存在对象result的属性中。
method.invoke(result, columnValue);
}
}
}
conn.commit();
}catch(Exception e){
e.printStackTrace();
如果出现异常回滚
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
//关闭资源
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(pstm != null){
try {
pstm.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return result;
}
反射拼接 sql 字符串
private String createGetObjectByIdSQL(Class clazz){
// 缺少SQL语法
StringBuilder builder = new StringBuilder("select ");
// 拼接字段名, 字段名就是类型的属性名
// 获取所有方法。 循环方法的数组。 查询已get/set命名的方法。
Method[] methods = clazz.getMethods();
String[] columnNames = new String[methods.length];
for(int i = 0; i < methods.length; i++){
String methodName = methods[i].getName();
if(methodName.startsWith("get") && methodName.length() > 3 && !methodName.equals("getClass")){
// 当前方法是需要分析的方法。 将方法名称前缀get去除,其余部分为字段名
String columnName = methodName.substring(3);
columnNames[i] = columnName;
builder.append(columnName);
builder.append(",");
}
}
// 上述的SQL语法末尾多一个逗号
builder.deleteCharAt(builder.length() - 1);
// 拼接表名, 表名是tb_类名
String className = clazz.getName();
// 截取类的名称。 className : package.name.ClassName
className = className.substring(className.lastIndexOf(".")+1);
builder.append(" from tb_"+className);
// 拼接条件。 条件是主键查询
builder.append(" where id = ? ");
return builder.toString();
}