自已动手写ORM框架(1)——幼儿园
ORM即Object,Relation,Mapping的缩写,什么意思呢?先从一个例子说起。
现在需要开发一个学生成绩管理系统,要求可以进行信息的增删改查,首先进行需求分析:一个学校有不同的年级,一个年级有不同的班,一个班有不同的学生,每个学生又学习不同的科目,每个科目对应着成绩。。。。需求分析的结果确定数据库中需要四张表: t_student、t_class、t_grade、t_course,分别代表存储学生信息,班级信息,成绩信息,课程信息,那在实际的程中也对应四个类,而且,这个四个类的属性要和表中的字段一一对应。如果没有ORM,那么你要为四张表分别写一份操作数据库的代码来完成查询和存储功能,这样就会代码冗余。这时ORM框架作为一个中间层就显示其强大的威力了。在ORM接品层,不管调用者会传来什么对像,我只用一份代码,统一进行解析,得到相关信息,然后动态组建SQL语句来操作数据库。在应用层,我不管是要存储学生,班级,还是成绩,我都调用一个接口,把对像传给它,让ORM去组建对应的SQL语句通过JDBC来完成数据插入,然而这和类名和表名有什么关系呢?
当然有,如果类名和表名具有相同的名子,那我就可以根据你传过来的对像的类名来获得对应的表名,从而知道数据要插入哪张表,这样这份代码就有了“动态执行”的功能,而不是一个特定的写死的功能。
数据库中的表结构和代码中的类对应,表中的字段和类中的属性对应,表中的记录和类的对像对应。
原则:JavaBean的属性名和数据类型尽量和数据库一致。
关系:表中一条记录对应一个对像,用容器(List,Set,Map)存储的多个对像就对应多条记录,那最终,容器可以看成和表对应起来。
在正式开始学习ORM之前,先看一下怎样使用数组,List,Set,Map等容器存储表中的记录。
一、使用容器和Object数组来存储数据库表中的记录。
1. 首先,使用Object数组来封装一条记录
//SQL语句
String sql = "select * from t_employee where id=?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
//创建一个Object数组,存储一条记录中的各个字段
Object[] obj = new Object[3];
conn = DbUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setObject(1, 1);
rs = pstmt.executeQuery();
while(rs.next()){
//获取记录字段
obj[0] = rs.getObject("empname");
obj[1] = rs.getObject("age");
obj[2] = rs.getObject("address");
}
//打印这条记录
System.out.println(""+obj[0]+obj[1]+obj[2]);
上面代码中,通过JDBC获取的表的字段的值存储在Object类型的数组中,这样就达到了使用数组来封装一条数据记录的目的。
2. 使用List容器和Object数组来封装多条记录 如果List容器中的类型是Object类型,不就能完成多条记录的封装吗?
//SQL语句,查询表中的所有记录
String sql = "select * from t_employee";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
//创建一个List容器,里面存储的是一条记录
ArrayList rows = new ArrayList();
conn = DbUtil.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while(rs.next()){
//创建Object数组
Object[] obj = new Object[3];
obj[0] = rs.getObject("empname");
obj[1] = rs.getObject("age");
obj[2] = rs.getObject("address");
//将Object数组中存储的一条数据记录添加到List容器中
rows.add(obj);
}
//打印List中的记录
for(Object[] obj: rows)
{
System.out.println(""+obj[0]+obj[1]+obj[2]);
}
二、使用Map来存储表中的记录
1. 使用Map来存储一条记录
map中的key即表中字段的名子,value即为字段的值。
//创建一个Map容器,里面存储的是一条记录
HashMap map = new HashMap();
while(rs.next()){
map.put("empname",rs.getObject("empname"));
map.put("age", rs.getObject("age"));
map.put("address", rs.getObject("address"));
}
//获取记录值所在的Set集合
Set set = map.keySet();
for(String s: set)
{
//打印记录的内容
System.out.print(map.get(s) + "\t");
}
2. 使用List容器和Map来存储多条记录
//创建一个List容器,里面存储的是多条记录
ArrayList> list = new ArrayList<>();
while(rs.next()){
//创建一个Map封装一条记录
HashMap map = new HashMap();
map.put("empname",rs.getObject("empname"));
map.put("age", rs.getObject("age"));
map.put("address",rs.getObject("address"));
//将该条记录添加到List中
list.add(map);
}
//遍历List集合,多条记录
for(HashMap row: list)
{
//输出Map的内容,即一条记录
for(String s: row.keySet())
{
System.out.print(row.get(s));
}
System.out.println();
}
上面的代码中,外层是List容器,内层一条记录的存储对应的是map,当然了还可以反过来。
3. 使用Map容器和Map存储多条记录
内层一个map对应一条记录,外层还是一个map容器,采用ID作为Key。
//创建一个Map容器,里面存储的是多条记录
Map> maps = new HashMap<>();
while(rs.next()){
//创建一个Map封装一条记录
HashMap map = new HashMap();
map.put("empname",rs.getObject("empname"));
map.put("age", rs.getObject("age"));
map.put("address",rs.getObject("address"));
//将该条记录添加到Map中,以ID作为Key
maps.put(rs.getInt("id"),map);
}
//遍历Map集合,多条记录
for(int id: maps.keySet())
{
//获得一行记录
Map row = maps.get(id);
//输出Map的内容,即一条记录
for(String s: row.keySet())
{
System.out.print(row.get(s));
}
System.out.println();
}
事实上,在上面的两种方式中来封装记录时,都不具有通用性,因为,他们都是操作已经知道表结构的表,通常我们并不知道你操作的表名子,表结构,表字段名子,所以要想写出通用的ORM工具,还需要依靠反射和JavaBean,后面再详细讨论。
总结一下:
数据库中的一个表有不同的字段,所以可以采用JAVA中的超类Object来存储各个不同的字段,这何尝不是多态思想的体现呢?
对于表中的一条记录,可以采用object数组来存储,那多条记录不就是一个元素类型为Object数据的Object数组吗?通常我们不这样用,所以转化为元素类型为Object[]的List集合。
集合容器不仅仅限于List,Map也可以完成这个功能,那Map外层套什么?可以套List,还可以再套一个Map,所以,总的来说就是这些基本功能的使用。