本文前置内容:JAVA & 数据库编程 & ORM工具(上)
一、ORM的数据库操作
1.链接数据库准备
public class YORM {
private static Connection connection;
public YORM() {
}
public static void initORM(String cfgPath) {
try {
PropertiesParse.loadProperties(cfgPath);
//利用Properties文件配制
Class.forName(PropertiesParse.getValue("driver"));
connection = DriverManager.getConnection(
PropertiesParse.getValue("url"),
PropertiesParse.getValue("user"),
PropertiesParse.getValue("password"));
} catch (PropertiesFileNotFoundException | IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
文件如图
注意url的书写,其中school是我用的数据库名。
关键操作
其实无论是增删改查,都是按照一定的步骤来的。
- 第一步,获取映射关系类
- 第二步,构建基本的sql语句结构
- 第三步,通过模板类,完善sql语句
- 第四步,执行操作,处理返回结果
这里面的一个需要注意的地方:由于模板类的成员是private保护,无法直接对其进行操作。
而使用field.setAccessible(true);会破坏其保护。但有趣的是,我们拥有set,get函数。而且其一般规则是
set方法 : set + 成员名(首字母大写)(成员类型){}
get方法:get + 成员名(首字母大写)(){}
所以我们可以通过**使用反射获取方法,来实现对成员的读写。
具体get
private Object getFieldValue(Class<?> kClass, Field field, Object object) {
String fieldName = field.getName();
//注意,由于成员是private保护,不能直接获取,但是可通过get函数获得
String methodName = "get" + fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
try {
Method method = kClass.getDeclaredMethod(methodName);
Object value = method.invoke(object, new Object[] {});
return value;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
具体set
private void initObject(ClassTableDefinition ctd, Object result, ResultSet resultSet) {
Class<?> modelKClass = result.getClass();
List<FieldCloumnDefinition> fdList = ctd.getfDefinitions();
for (FieldCloumnDefinition fd : fdList) {
try {
Object value = resultSet.getObject(fd.getCloumn());
System.out.println(value.getClass());
Field field = fd.getField();
String fieldName = field.getName();
//set
String methodName = "set" + fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
Method method = modelKClass.getDeclaredMethod(methodName, field.getType());
method.invoke(result, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、增
熟悉增加操作:INSERT INTO 表名([字段名1,字段名2,字段名3])VALUES(‘值1’,‘值2’,‘值3’),(‘1值1’,‘1值2’,‘1值3’)…
/**
* 从一个类中将一条完整的记录存储到数据库中。
* @param object
*/
public void save(Object object) {
//第一步,获取映射关系类
Class<?> kClass = object.getClass();
ClassTableDefinition ctd = ClassTableFactory.getCTD(kClass);
if (ctd == null) {
System.out.println("类[" + kClass.getName() + "]没有映射关系!");
}
StringBuffer sql = new StringBuffer();
//第二步,构建基本的sql语句结构
sql.append("INSERT INTO ").append(ctd.getTableName())
.append(" (").append(ctd.getCloumnList())
.append(") VALUES(");
for (int index = 0; index < ctd.getFieldCount(); index++) {
sql.append(index == 0 ? "" : ",").append("?");
}
sql.append(");");
PreparedStatement statement;
try {
statement = connection.prepareStatement(sql.toString());
//第三步,通过模板类,完善sql语句
//INSERT INTO student (student.id,student.name,student.age) VALUES(?,?,?); 上面获得sql语句
//接下来需要将?,一一修改成存储在模板类的数据
prepareStatment(ctd, statement, object);
//第四步,执行操作
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void prepareStatment(ClassTableDefinition ctd, PreparedStatement statement, Object object) {
Class<?> kClass = object.getClass();
List<FieldCloumnDefinition> fdList = ctd.getfDefinitions();
int index = 0;
for (FieldCloumnDefinition fd : fdList) {
Field field = fd.getField();
//获取到每个成员的值,完成sql语言
Object value = getFieldValue(kClass, field, object);
try {
System.out.println(value);
statement.setObject(index + 1, value);
} catch (SQLException e) {
e.printStackTrace();
}
index++;
}
}
3、删
熟悉删除操作:语法: DELETE FROM 表名 [WHERE 条件]
/**
* 通过主键值,删除某一条记录
* @param kClass
* @param id
*/
public void delete(Class<?> kClass,Object id) {
ClassTableDefinition ctd = ClassTableFactory.getCTD(kClass);
if (ctd == null) {
System.out.println("类[" + kClass.getName() + "]没有映射关系!");
return;
}
StringBuffer sql = new StringBuffer();
sql.append("DELETE ").append("FROM ").append(ctd.getTableName())
.append(" WHERE ").append(ctd.getPrimaryKey().getCloumn())
.append("=?;");
//DELETE FROM student WHERE id=?;
try {
PreparedStatement statement = connection.prepareStatement(sql.toString());
statement.setObject(1, id);
statement.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
4、改
熟悉修改操作:UPDATE 表名 SET colnum_name = value,[colnum_name = value, …] where [条件]
/**
* 修改一个记录
* @param object
*/
public void update(Object object) {
Class<?> kClass = object.getClass();
ClassTableDefinition ctd = ClassTableFactory.getCTD(kClass);
//第一步
if (ctd == null) {
System.out.println("类[" + kClass.getName() + "]没有映射关系!");
}
StringBuffer sql = new StringBuffer();
sql.append("UPDATE ").append(ctd.getTableName())
.append(" SET");
List<FieldCloumnDefinition> fList = ctd.getfDefinitions();
boolean isFirst = true;
for (FieldCloumnDefinition fcd : fList) {
if (fcd.equals(ctd.getPrimaryKey())) {
continue;
}
String cloumnName = fcd.getCloumn();
sql.append(isFirst ? " ": ",").append(cloumnName)
.append("=?");
isFirst = false;
}
sql.append(" WHERE ").append(ctd.getPrimaryKey().getCloumn()).append("=?;");
//第二步完成
//UPDATE student SET name=?,age=? WHERE id=?;
try {
PreparedStatement statement = connection.prepareStatement(sql.toString());
int index = 0;
for (FieldCloumnDefinition fd : fList) {
if (fd.equals(ctd.getPrimaryKey())) {
continue;
}
//第三步关键
Object value = getFieldValue(kClass, fd.getField(), object);
statement.setObject(++index, value);
}
Object idValue = getFieldValue(kClass, ctd.getPrimaryKey().getField(), object);//get
statement.setObject(++index, idValue);
//第四步执行
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
5、查
查目前提供两种,查一条匹配记录,和查表中所有记录。
查一条:SELECT 字段名, 字段名… FROM 表名 WHERE[条件]
/**
* 根据某一条件,查询一条完整的记录
* @param <T>
* @param kClass SELECT查询结果生成的对象
* @param id WHERE 使用的主键条件
* @return
*/
@SuppressWarnings("unchecked")
public <T>T get(Class<?> kClass, Object id){
//第一步
ClassTableDefinition ctd = ClassTableFactory.getCTD(kClass);
if (ctd == null) {
System.out.println("类[" + kClass.getName() + "]没有映射关系!");
return null;
}
//生成查询语句,第二步
StringBuffer sql = new StringBuffer();
sql.append("SELECT ").append(ctd.getCloumnList())
.append(" FROM ").append(ctd.getTableName())
.append(" WHERE ").append(ctd.getPrimaryKey().getCloumn()).append("=?;");
//SELECT student.id,student.name,student.age FROM student WHERE id=?;
Object result = null;
try {
PreparedStatement statement = connection.prepareStatement(sql.toString());
statement.setObject(1, id);//第三步简单
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
result = newInstance(ctd, resultSet);//将数据保存到模板类中
}
} catch (Exception e) {
e.printStackTrace();
}
return (T) result;
}
private Object newInstance(ClassTableDefinition ctd, ResultSet resultSet)
throws InstantiationException, IllegalAccessException {
Class<?> kClass = ctd.getModelClass();
Object result = kClass.newInstance();
initObject(ctd, result, resultSet);//set
return result;
}
查询所有记录SELECT * FROM student
/**
* 获得表中所有数据
* @param <T>
* @param kClass
* @return
*/
@SuppressWarnings("unchecked")
public <T> List<T> list(Class<?> kClass){
ClassTableDefinition ctd = ClassTableFactory.getCTD(kClass);
if (ctd == null) {
System.out.println("类[" + kClass.getName() + "]没有映射关系!");
return null;
}
StringBuffer sql = new StringBuffer();
sql.append("SELECT ").append("* ")
.append("FROM ").append(ctd.getTableName());
//SELECT * FROM student
List<T> result = new ArrayList<T>();
try {
PreparedStatement statement = connection.prepareStatement(sql.toString());
ResultSet rs = statement.executeQuery();
while (rs.next()) {
T element = (T) newInstance(ctd, rs);
result.add(element);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
二、小总结
其实虽然完成了增删改查,但还是又不少地方有待完善。比如说排序,比如查询指定记录的少数列数据。
因为上述操作都是针对一条完整记录。不过从整体而言,只要规范好sql语句的搭建,就能实现基本功能。所以称之为工具不为过。当然,工具也是越用越好用。(不断完善)
笔者水平有限,目前只能描述以上问题,如果有其他情况,可以留言,有错误,请指教,有继续优化的,请分享,谢谢!
本篇文章是否有所收获?阅读是否舒服?又什么改进建议?希望可以给我留言或私信,您的的分享,就是我的进步。谢谢。
2020.10.24 网安院2楼