OR框架翻译过来就是对象关系映射框架,一提起OR框架,马上就会想起大名鼎鼎的Hibernate,Ibatis,以及其他的一些对象关系映射框架,并惊叹它的神奇。在惊叹之余,不免会产生兴趣一探他们的实现原理。下面我们就一起来实现一个简单的OR框架。
首先,我们为什么要使用OR框架?虽然现在OOA,OOP的思想已经成为软件编程的主流思想,但是关系型数据库依然是最主流、效率最高的数据库。所以问题来了,如何将我们面向对象思想程序中产生的数据持久化到关系型数据库中呢?当然了,方法很多,最直接的就是使用sql语言将数据依照他们的关系存到数据库当中,但是这样实现起来非常麻烦,为了实现一个简单的功能,常常需要我们写上几百行的代码,费时又费力;也可以使用流行ORM框架,例如Hibernate,Ibatis等,事实上,大多数的中小型公司的确是使用Hibernate作为自己的首选。Hibernate是一个非常优秀的OR框架,它对JDBC进行了轻量级的封装,使我们可以随心所欲的使用面向对象的思想来操纵数据库。下面,我们就来探究一下如何实现一个简单的OR框架,完成与Hibernate相同的功能。
为了说明实现的中心思想,我们先略去细枝末节。对实现做出以下规则:
VO对象的类名要对映数据库的表名,例:VO对象类名为User.java,则数据库表则为user;
VO对象的成员变量名对映数据库表的字段名,例:User中的成员变量为id,name,birthday,则数据库user表中字段名称也必须为id,name,birthday;
VO对象中成员变量的类型与数据库表中字段类型的对应关系为(我们使用的数据库为MYSQL数据库,请根据实际情况自定义规则):Integer对映int(8),Long对应int(16),Float对应float(10,2),Double对应double(16,4),Date对应timestamp,String对应text。
VO对象中必须包括一个Integer类型的成员变量id,数据库中相映的字段名为id,类型为int(8),主键,自动增长。
这里我们只贴一些关键性的代码,整体项目我已经长传到csdn,大家可以另行下载。
首先我们建一个VO类:
package com.zzb;
import java.util.Date;
public class User {
private Integer id;
private Float value;
private String name;
private Date date;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Float getValue() {
return value;
}
public void setValue(Float value) {
this.value = value;
}
}
这个类有一个Integer类型的id,另外还有其他三个成员变量,以及相应的get/set方法,是一个标准的POJO。
根据我们的OR对应规则,数据库中对映的表名为user,表中的字段名和字段类型为
id int(8) auto_increment primary key
name text
value float(8,2)
date timestamp
然后,我们需要一个通用的DAO类,通用DAO包括5个方法(列出的方法为主要方法,并且方法体已省略),代码如下:
public class BaseDAO {
public int add(Object o) throws Exception{}
public int update(Object o) throws Exception{}
public int delete(Object o) throws Exception{}
public List query(Object o) throws Exception{}
}
类中的四个方法分别对对象进行增、改、删、查四个操作。
接下来是我们的核心类,这个类的主要任务就是根据对象的增删改查四种情况产生对应的SQL语句,然后通过SQL语句进行数据库操作,从而完成OR映射。代码如下:
public class StandardSQL {
public String add(Object o) throws Exception{}
public String update(Object o) throws Exception{}
public String delete(Object o) throws Exception{}
public String query(Object o) throws Exception{}
}
add方法负责产生一个insert语句,运行add(user),则返回字符串:insert into user(name, value, date ) values('****', ****, '**********' );
update方法负责产生一个update语句,运行update(user),则返回字符串:update user set name='****', value=***, date='*********' where id=*;
delete方法负责产生一个delete语句,运行delete(user),返回字符串:delete from user where id=*;
query方法负责产生一个query语句,运行query(user),返回字符串:select name, value, id, date from user where name like '%****%';
另外,为了方便建表,我们还需要一个create方法,用来产生建表语句,将user作为参数传入后返回字符串:create table if not exists user(id int(8) auto_increment, name text, value float(8,2), date timestamp, primary key(id))
以上就是我们核心类要完成的功能。
接下来,我们写一个连接数据库的类,对连接操作简单封装一下:
package com.zzb;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DB {
public Connection getConnection(){
Connection conn =null;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/business", "root", "123");
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
public void releaseConnection(ResultSet rs,Statement stat,Connection conn){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
这里我的数据库名是business,用户名,密码分别是root和123,大家根据自己的情况自行修改,并且不要忘了引入mysql的jdbc。
最后我们建立一个test类测试一下是否成功。
package com.zzb;
import java.util.Date;
import java.util.List;
import org.junit.Test;
public class TestDB {
BaseDAO dao = new BaseDAO();
@Test
public void testcreate() throws Exception{
StandardSQL standardSQL = new StandardSQL();
String sql = standardSQL.create(new User());
System.out.println(sql);
dao.executeUpdate(sql);
}
@Test
public void testadd() throws Exception{
User user = new User();
user.setName("xiaohong");
user.setValue((float)45.60);
user.setDate(new Date());
dao.add(user);
}
@Test
public void testupdate() throws Exception{
User user = new User();
user.setId(1);
user.setName("xiaowang");
user.setValue((float)90.88);
user.setDate(new Date());
dao.update(user);
}
@Test
public void testquery() throws Exception{
User user = new User();
user.setName("xiaowang");
List<User> list = dao.query(user);
for(User u: list){
System.out.print(u.getId()+" ");
System.out.print(u.getName()+" ");
System.out.println(u.getDate());
}
}
@Test
public void testdel() throws Exception{
User user = new User();
user.setId(1);
dao.delete(user);
}
}
test类有5个方法,分别测试建表、插入、修改、查询、删除五个操作。
写到这里,我们已经看出,所谓的OR映射就是通过java的对象,使用反射得到对象的信息,然后产生SQL语句,再使用JDBC对数据库进行操作。在这个程序当中,我们没有做事务处理,没有使用连接池,没有做多表的映射,可移植性也做的不好,只是将一个简单的java对象持久化到数据库相应的表中,但作为一个练习,已经阐明了如何去实现自己的OR框架,希望各位看官读完以后能有所启发。写的不好,权当是抛砖引玉,欢迎各看官指点。