发布一个自用的Java简易版ORM框架
看过Hibernate和iBatis的强大,也见过最原始的BaseDAO使用的痛苦。有的时候我感觉很纳闷,既然要主张DAO的灵活,那就不可能将复杂的SQL都支持或支持得非常好;又要主张ORM,那就又得作一些限制。于是,我只能依着自己的实际来写一套自己的简易版ORM框架,去除Hibernate这类框架的复杂关联映射,仅支持单表的持久化映射动作。目前这个简易版ORM框架在Oracle/MySQL/MS SQL Server中均通过初步测试,既可以中规中矩地使用GenericsDAO这个类来完成常用的DAO动作(CRUD),又可以破框架直接继承GenericsBaseDAO这个类来完成复杂查询条件的DAO类的编写。下面的图片中就演示了这两个方面的应用:
1、GenericsDAO这个类来完成常用的DAO动作(CRUD)
通过上面的这些DAO方法,我们就可以完成常用的CRUD动作了。SQLParameterWrapper这个包装器是用于对SQL(条件)参数的封装,采用可变参数调用,这样,我们可以根据实际情况添加多个查询条件。并且,我也推荐使用SQLParameterWrapper包装器来构建查询条件,如果入口参数是POJO对象,那么,框架也就自动将POJO中非null值的成员变量映射为对应的SQLParameterWrapper对象。因此,直接使用当然效率会高一些。不过经过测试,效率的损失很少,可以忽略不计。下面演示了一些调用实例:
package com.china.codingmouse.cmsdk4j.example;
import java.util.List;
import com.china.codingmouse.cmsdk4j.dao.genericsdao.GenericsDAO;
import com.china.codingmouse.cmsdk4j.dao.genericsdao.IGenericsDAO;
import com.china.codingmouse.cmsdk4j.dao.parameter.SQLParameterWrapper;
import com.china.codingmouse.cmsdk4j.example.pojo.AccountPOJO;
/**
* 泛型数据访问测试类
* TestGenericsDAO
* @author CodingMouse
* @version 1.0 2009-6-20
*/
public class TestGenericsDAO {
public static void main(String[] args) {
IGenericsDAO<AccountPOJO> dao = new GenericsDAO<AccountPOJO>();
try {
// 0、查询所有POJO
// List<AccountPOJO> list = dao.find(AccountPOJO.class);
// for (AccountPOJO account : list) {
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// }
// 1、查询多个POJO
// List<AccountPOJO> list = dao.find(
// AccountPOJO.class,
// SQLParameterWrapper.build("accountstate", 0));
// for (AccountPOJO account : list) {
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// }
// 2、查询单个POJO(多条件查询)
// AccountPOJO account = dao.get(
// AccountPOJO.class,
// SQLParameterWrapper.build("accountstate", 1),
// SQLParameterWrapper.build("birthday", java.sql.Date.valueOf("1984-12-26")));
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// 3、模糊查询多个POJO
// List<AccountPOJO> list = dao.find(
// AccountPOJO.class,
// SQLParameterWrapper.build("accountname", "邓/%"),
// SQLParameterWrapper.build("email", "like", "%@gmail.com"));
// for (AccountPOJO account : list) {
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// }
// 4、模糊查询单个POJO
// AccountPOJO account = dao.get(
// AccountPOJO.class,
// SQLParameterWrapper.build("accountname", "/%超"));
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// 5、运算符查询多个POJO
// List<AccountPOJO> list = dao.find(
// AccountPOJO.class,
// SQLParameterWrapper.build("onlinecount", ">=", 500),
// SQLParameterWrapper.build("email", "zh/%"));
// for (AccountPOJO account : list) {
// System.out.println(account.getAccountid()
// + " | " + account.getAccountname()
// + " | " + account.getEmail()
// + " | " + account.getBirthday());
// }
// 6、运算符查询指定区间的POJO
// List<AccountPOJO> list = dao.find(
// AccountPOJO.class,
// SQLParameterWrapper.build("birthday", ">", java.sql.Date.valueOf("1982-01-01")),
// SQLParameterWrapper.build("birthday", "<", java.sql.Date.valueOf("1984-12-31")));
// for (AccountPOJO account : list) {
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// }
// 7、查询单个POJO(通过ID列)
// AccountPOJO account = dao.get(AccountPOJO.class, 5);
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// 8、根据条件POJO查询单个POJO
// AccountPOJO account = dao.get(new AccountPOJO(5, null, 1321, java.sql.Date.valueOf("1987-10-21"), null, null, null, true));
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// 9、根据条件POJO查询多个POJO
// AccountPOJO conditionModel = new AccountPOJO();
// conditionModel.setLoginpassword("/%pwd");
// conditionModel.setAccountstate(true);
// List<AccountPOJO> list = dao.find(conditionModel);
// for (AccountPOJO account : list) {
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// }
// 10、分页查询多个POJO
// List<AccountPOJO> list = dao.findPage(AccountPOJO.class, 3, 12);
// for (AccountPOJO account : list) {
// System.out.println(
// account.getAccountid() + " | "
// + account.getAccountname() + " | "
// + account.getEmail() + " | "
// + account.getBirthday());
// }
// 11、根据SQL条件对象分页查询多个POJO
List<AccountPOJO> list = dao.findPage(
AccountPOJO.class, 1, 10,
SQLParameterWrapper.build("email", "/%@gmail.com"));
for (AccountPOJO account : list) {
System.out.println(account);
AccountPOJO other = new AccountPOJO();
other.setAccountid(account.getAccountid());
other.setAccountname(account.getAccountname());
other.setAccountstate(account.getAccountstate());
other.setBirthday((java.sql.Date)account.getBirthday().clone());
other.setEmail(account.getEmail());
other.setLoginname(account.getLoginname());
other.setLoginpassword(account.getLoginpassword());
other.setOnlinecount(account.getOnlinecount());
System.out.print("hashCode = " + (account.hashCode() + " | " + other.hashCode()));
System.out.println(", equals = " + account.equals(other));
}
// 12、根据条件POJO分页查询多个POJO
// AccountPOJO conditionModel = new AccountPOJO();
// conditionModel.setLoginpassword("/%6");
// conditionModel.setAccountstate(true);
// List<AccountPOJO> list = dao.findPage(conditionModel, 3, 15);
// for (AccountPOJO account : list) {
// System.out.println(account.getAccountid() + " | " + account.getAccountname() + " | " + account.getEmail() + " | " + account.getBirthday());
// }
// 1、添加单个POJO
// AccountPOJO account = new AccountPOJO(null, "测试添加1", 1, java.sql.Date.valueOf("1982-02-01"), "test1", "test1pwd", "test1@test.com", true);
// if (dao.save(account)) {
// System.out.println("添加 " + account.getAccountname() + " 成功!");
// } else {
// System.out.println("添加 " + account.getAccountname() + " 失败!");
// }
// 2、批量添加多个POJO
// List<AccountPOJO> list = new Vector<AccountPOJO>();
// for (int i = 0; i < 10000; i++) {
// list.add(new AccountPOJO(null, (i%3==0 ? "新保存的数据" : "批量添加测试") + (i+1), 1, java.sql.Date.valueOf("1986-02-01"), "NewTest" + (i+1), "newtestpwd" + (i+1), "newtest" + (i+1) + "@gmail.com", true));
// }
// long time = System.currentTimeMillis();
// if (dao.saveBatch(list)) {
// System.out.println(list.size() + "条测试数据批处理添加成功!");
// } else {
// System.out.println(list.size() + "条测试数据批处理添加失败!");
// }
// System.out.println("累计耗时:" + (System.currentTimeMillis() - time) + "毫秒!");
// 3、非批量方式添加多个POJO
// List<AccountPOJO> list = new Vector<AccountPOJO>();
// for (int i = 0; i < 10000; i++) {
// list.add(new AccountPOJO(null, "新建测试数据" + (i+1), 1, java.sql.Date.valueOf("1986-02-01"), "NewTest" + (i+1), "newtestpwd" + (i+1), "newtest" + (i+1) + "@gmail.com", true));
// }
// long time = System.currentTimeMillis();
// for (AccountPOJO accountPOJO : list) {
// if (!dao.save(accountPOJO)) {
// System.out.println("测试数据使用非批处理方式添加失败! -- " + accountPOJO.getAccountname());
// }
// }
// System.out.println(list.size() + "条测试数据使用非批处理方式添加成功!");
// System.out.println("累计耗时:" + (System.currentTimeMillis() - time) + "毫秒!");
// 1、修改单个POJO(先加载后修改)
// try {
// AccountPOJO persistenceModel = dao.get(AccountPOJO.class, 123);
// persistenceModel.setAccountname("潘美辰123");
// persistenceModel.setOnlinecount(666);
// persistenceModel.setEmail("mm28@gmail.com");
// System.out.println("修改是否成功?" + dao.update(persistenceModel));
// } catch (Exception e) {
// e.printStackTrace();
// }
// 2、修改多个POJO(先加载后修改)
// try {
// AccountPOJO persistenceModel1 = dao.get(AccountPOJO.class, 121);
// persistenceModel1.setAccountname("潘长江121");
// persistenceModel1.setOnlinecount(111);
// persistenceModel1.setEmail("changjiang121@gmail.com");
// AccountPOJO persistenceModel2 = dao.get(AccountPOJO.class, 123);
// persistenceModel2.setAccountname("潘长江123");
// persistenceModel2.setOnlinecount(222);
// persistenceModel2.setEmail("changjiang123@gmail.com");
// List<AccountPOJO> persistenceModelList = new Vector<AccountPOJO>();
// persistenceModelList.add(persistenceModel1);
// persistenceModelList.add(persistenceModel2);
// System.out.println("批量修改是否成功?" + dao.updateBatch(persistenceModelList));
// } catch (Exception e) {
// e.printStackTrace();
// }
// 1、根据模型ID移除单个实体模型
// try {
// int accountId = 122;
// if (dao.delete(AccountPOJO.class, accountId)) {
// System.out.println("删除编号为 " + accountId + " 的账户成功!");
// } else {
// System.out.println("删除编号为 " + accountId + " 的账户失败!");
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// 2、根据查询条件移除单个/多个实体模型
// try {
// int count = dao.delete(AccountPOJO.class, SQLParameterWrapper.build("loginname", "/%11"));
// System.out.println("删除了 " + count + " 条账户信息!");
// } catch (Exception e) {
// e.printStackTrace();
// }
// 3、根据查询条件模型移除单个/多个实体模型
// try {
// AccountPOJO account = new AccountPOJO();
// account.setAccountname("/%00");
// account.setEmail("/%@gmail.com");
// int count = dao.delete(account);
// System.out.println("删除了 " + count + " 条账户信息!");
// } catch (Exception e) {
// e.printStackTrace();
// }
// 4、批量移除模型有序集合中的所有模型
// try {
// AccountPOJO account1 = new AccountPOJO();
// account1.setAccountname("/%013");
// account1.setEmail("/%@gmail.com");
// AccountPOJO account2 = new AccountPOJO();
// account2.setAccountname("/%014");
// account2.setEmail("/%@gmail.com");
// List<AccountPOJO> modelList = new Vector<AccountPOJO>();
// modelList.add(account1);
// modelList.add(account2);
// if (dao.deleteBatch(modelList)) {
// System.out.println("批量删除账户信息成功!");
// } else {
// System.out.println("批量删除账户信息失败!");
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
} catch (Exception e) {
e.printStackTrace();
}
}
}
与上面的测试相关的POJO代码内容由我之前发布的POJO代码生成器自动从数据库表反转生成得来,其内容如下:
package com.china.codingmouse.cmsdk4j.example.pojo;
import java.io.Serializable;
import java.sql.Date;
/**
* AccountPOJO
* @author CodingMouse's POJOGenerator
* @version v1.0.0.1 2009-08-08 02:51:55
*/
public class AccountPOJO implements Serializable {
/*
* Private Fields
*/
private static final long serialVersionUID = -2019752403L;
private Integer accountid;
private String accountname;
private Integer onlinecount;
private Date birthday;
private String loginname;
private String loginpassword;
private String email;
private Boolean accountstate;
/**
* Default Constructor
*/
public AccountPOJO() {
super();
}
/**
* Full Constructor
* @param accountid
* @param accountname
* @param onlinecount
* @param birthday
* @param loginname
* @param loginpassword
* @param email
* @param accountstate
*/
public AccountPOJO(
Integer accountid,
String accountname,
Integer onlinecount,
Date birthday,
String loginname,
String loginpassword,
String email,
Boolean accountstate) {
super();
this.accountid = accountid;
this.accountname = accountname;
this.onlinecount = onlinecount;
this.birthday = birthday;
this.loginname = loginname;
this.loginpassword = loginpassword;
this.email = email;
this.accountstate = accountstate;
}
/**
* Private field accountid Getter method.
* @return accountid
*/
public Integer getAccountid() {
return this.accountid;
}
/**
* Private field accountid Setter method.
* @param accountid
*/
public void setAccountid(Integer accountid) {
this.accountid = accountid;
}
/**
* Private field accountname Getter method.
* @return accountname
*/
public String getAccountname() {
return this.accountname;
}
/**
* Private field accountname Setter method.
* @param accountname
*/
public void setAccountname(String accountname) {
this.accountname = accountname;
}
/**
* Private field onlinecount Getter method.
* @return onlinecount
*/
public Integer getOnlinecount() {
return this.onlinecount;
}
/**
* Private field onlinecount Setter method.
* @param onlinecount
*/
public void setOnlinecount(Integer onlinecount) {
this.onlinecount = onlinecount;
}
/**
* Private field birthday Getter method.
* @return birthday
*/
public Date getBirthday() {
return this.birthday;
}
/**
* Private field birthday Setter method.
* @param birthday
*/
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
/**
* Private field loginname Getter method.
* @return loginname
*/
public String getLoginname() {
return this.loginname;
}
/**
* Private field loginname Setter method.
* @param loginname
*/
public void setLoginname(String loginname) {
this.loginname = loginname;
}
/**
* Private field loginpassword Getter method.
* @return loginpassword
*/
public String getLoginpassword() {
return this.loginpassword;
}
/**
* Private field loginpassword Setter method.
* @param loginpassword
*/
public void setLoginpassword(String loginpassword) {
this.loginpassword = loginpassword;
}
/**
* Private field email Getter method.
* @return email
*/
public String getEmail() {
return this.email;
}
/**
* Private field email Setter method.
* @param email
*/
public void setEmail(String email) {
this.email = email;
}
/**
* Private field accountstate Getter method.
* @return accountstate
*/
public Boolean getAccountstate() {
return this.accountstate;
}
/**
* Private field accountstate Setter method.
* @param accountstate
*/
public void setAccountstate(Boolean accountstate) {
this.accountstate = accountstate;
}
/**
* The object's equivalence test method.
* @param otherObject Another object
* @return Whether the current object equal to another object.
*/
@Override
public boolean equals(Object otherObject) {
if (this == otherObject) return true;
if (otherObject == null) return false;
if (this.getClass() != otherObject.getClass()) return false;
AccountPOJO other = (AccountPOJO) otherObject;
return this.accountid.equals(other.accountid)
&& this.accountname.equals(other.accountname)
&& this.onlinecount.equals(other.onlinecount)
&& this.birthday.equals(other.birthday)
&& this.loginname.equals(other.loginname)
&& this.loginpassword.equals(other.loginpassword)
&& this.email.equals(other.email)
&& this.accountstate.equals(other.accountstate);
}
/**
* The object's hash code generation method.
* @return AccountPOJO hash code
*/
@Override
public int hashCode() {
int hash = 0;
hash += (this.accountid != null ? this.accountid.hashCode() : 0);
hash += (this.accountname != null ? this.accountname.hashCode() : 0);
hash += (this.onlinecount != null ? this.onlinecount.hashCode() : 0);
hash += (this.birthday != null ? this.birthday.hashCode() : 0);
hash += (this.loginname != null ? this.loginname.hashCode() : 0);
hash += (this.loginpassword != null ? this.loginpassword.hashCode() : 0);
hash += (this.email != null ? this.email.hashCode() : 0);
hash += (this.accountstate != null ? this.accountstate.hashCode() : 0);
return hash;
}
/**
* The object's string representation method.
* @return AccountPOJO string representation
*/
@Override
public String toString() {
String content = "";
content += "[ accountid = " + this.accountid;
content += ", accountname = " + this.accountname;
content += ", onlinecount = " + this.onlinecount;
content += ", birthday = " + this.birthday;
content += ", loginname = " + this.loginname;
content += ", loginpassword = " + this.loginpassword;
content += ", email = " + this.email;
content += ", accountstate = " + this.accountstate + " ]";
return content;
}
}
以下是映射档的内容:
<?xml version="1.0" encoding="utf-8"?>
<!--
CmSdk4j Identity Column Notify Document
-->
<cmsdk4j-notify>
<pojo type="com.china.codingmouse.cmsdk4j.example.pojo.AccountPOJO" table="account">
<!-- For MS SQL Server Or MySQL -->
<id name="accountid" generator="identity" />
<!-- For Oracle -->
<!--<id name="accountid" generator="sequence">seq_account_id</id>-->
</pojo>
<pojo type="com.china.codingmouse.cmsdk4j.example.pojo.SalaryPOJO" table="salary">
<!-- For MS SQL Server Or MySQL -->
<id name="salaryid" generator="identity" />
<!-- For Oracle -->
<!--<id name="salaryid" generator="sequence">seq_salary_id</id>-->
</pojo>
</cmsdk4j-notify>
对于上面的映射档,主要作用是通知框架POJO对应的数据库表名称及ID列名称(或Oracle中的sequence标识对象),以便于框架中的SQLGenerator这个SQL命令生成器自动构建SQL命令及赋予SQL参数值。
2、继承GenericsBaseDAO这个类来完成复杂查询条件的DAO类的编写
首先写一个DAO类让它直接继承GenericsBaseDAO,以获得基本的JDBC浅封装方法调用权。
package com.china.codingmouse.test.dao;
import java.util.List;
import com.china.codingmouse.cmsdk4j.dao.genericsdao.base.GenericsBaseDAO;
import com.china.codingmouse.test.pojo.AccountPOJO;
public class AccountDAO extends GenericsBaseDAO<AccountPOJO> {
public List<AccountPOJO> findAllGmailAccount() throws Exception {
return super.executeQuery(AccountPOJO.class, "select * from account where email like '%gmail.com'");
}
}
下面是AccountDAO的调用测试:
package com.china.codingmouse.test.dao;
import java.util.List;
import com.china.codingmouse.test.pojo.AccountPOJO;
public class TestAccountDAO {
public static void main(String[] args) {
AccountDAO dao = new AccountDAO();
try {
List<AccountPOJO> list = dao.findAllGmailAccount();
for (AccountPOJO accountPOJO : list) {
System.out.println(accountPOJO);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
以上仅为演示,所以SQL查询条件给得并不复杂,可以根据实际情况调配。
上面的DAO数据库连接均由以下配置档负责管理:
<?xml version="1.0" encoding="utf-8"?>
<!--
CmSdk4j DataBase Connection Configuration Document
-->
<cmsdk4j-configuration>
<base-setting>
<default-dbserver>SQL2000</default-dbserver>
<reconnect-timeout>10000</reconnect-timeout>
<show-sql>true</show-sql>
<show-poolstate>false</show-poolstate>
</base-setting>
<dbserver-list>
<server id="SQL2000">
<description>Microsoft SQL Server 2000 DataBase Connection Configuration</description>
<display-name>Microsoft SQL Server 2000</display-name>
<connection-url>jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=CmSdk4jTestDatabase</connection-url>
<driver-class>com.microsoft.jdbc.sqlserver.SQLServerDriver</driver-class>
<user-name>sa</user-name>
<user-password>sql2000</user-password>
</server>
<server id="SQL2005">
<description>Microsoft SQL Server 2005 DataBase Connection Configuration</description>
<display-name>Microsoft SQL Server 2005</display-name>
<connection-url>jdbc:sqlserver://localhost:1433;DatabaseName=CmSdk4jTestDatabase</connection-url>
<driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class>
<user-name>sa</user-name>
<user-password>sql2005</user-password>
</server>
<server id="ORACLE">
<description>Oracle 8/8i/9i/10g/11g DataBase Connection Configuration</description>
<display-name>Oracle 8/8i/9i/10g/11g</display-name>
<connection-url>jdbc:oracle:thin:@localhost:1521:orcl</connection-url>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<user-name>cm</user-name>
<user-password>cm</user-password>
</server>
<server id="DB2">
<description>IBM DB2 DataBase Connection Configuration</description>
<display-name>IBM DB2</display-name>
<connection-url>jdbc:db2://localhost:50000/sample</connection-url>
<driver-class>com.ibm.db2.jdbc.app.DB2Driver</driver-class>
<user-name>db2admin</user-name>
<user-password>db2</user-password>
</server>
<server id="MySQL">
<description>MySQL DataBase Connection Configuration</description>
<display-name>MySQL</display-name>
<connection-url>jdbc:mysql://localhost:3306/CmSdk4jTestDatabase</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<user-password>mysql</user-password>
</server>
</dbserver-list>
<connection-pool>
<initial-capacity>10</initial-capacity>
<max-capacity>2000</max-capacity>
<hold-time>60000</hold-time>
<expansion-step>5</expansion-step>
<scan-interval>3000</scan-interval>
</connection-pool>
</cmsdk4j-configuration>
可以看到,里面还包括我模拟的一个简易版数据库连接池的配置,当然,在这里,我强制性地让所有DAO都使用这个简易版数据库连接池来获取数据库连接,准备在下一个测试版中给用户自由选择的权利 。配置档中的<show-sql>节点为true时代表要求在控制台输出SQL生成器自动创建的SQL语句及参数信息,正式运行或做批量添加测试时请设置为false。
好了!今天就大致介绍到这里。这个简易版的ORM框架jar包及演示视频我已经上传,有兴趣的朋友可以自行下载测试,欢迎提出宝贵意见和建议。纯属爱好,谢绝“重复造轮子”之类的评论,我只是热爱Java、热爱自己敲代码封装一些代表性功能。
文章jar包下载地址:
完整压缩包(含演示视频)下载(由于文件太大,CSDN上传又老是不成功,就上传在RayFile网盘上了,下载需要安装RayFile下载客户端工具)
文件名: CmSdk4j ORM Framework Beta Edition 1.0.zip
下载地址: http://www.rayfile.com/files/51d4eb99-a753-11de-a488-0014221b798a/
新增网盘Http直接下载地址:http://www.xun6.com/file/3ea49ff11/CmSdk4j+ORM+Framework+Beta+Edition+1.0.zip.html
By CodingMose
2009.9.5