------------------------------
Loonframework-DAO-Alpha-0.1.0 - 2008年2月24日
------------------------------
开发JDK: JDK1.4(所以此版本不支持Annotation)
文件名称:Loonframework-DAO-Alpha-0.1.0.jar
Loonframework-DAO-Alpha-0.1.0-src.zip
版本声明:此为测试用版本,是一个供测试与调整用的系统原型,不保证现有接口或函数实现在可见的未来无变更,不保证运行效率及错误会得到有效处理,强烈反对任何个人或组织将此版本投入到实际或自认为有用的项目中……
版权声明:Loonframework下属所有源码遵循Apache License 2.0协议,保留对其下代码的版权,任何对源代码的改进和变动,请告知原作者;不能将Loonframework全部或部分编译后再以其他项目名义发布, 不得经简单修改单独商品化销售.所有对Loonframework源码与文档的引用和转载请注明出处.
1.什么是Loonframework
Loonframework由三个子项目构成,分别对应DAO框架实现,WEB框架实现,以及一个2D的GAME框架实现,全部完成后将作为一个快速开发用综合框架而存在;目前三部分都尚处于开发阶段。
2.关于Loonframework-DAO
Loonframework-DAO是loonframework项目下的DAO实现,是一个轻量级、低外部依赖度的实现;为实现小规模项目的快速开发而诞生,目前提供了jdbc数据接口的封装及简单的pojo应用处理能力(但并不是彻底的orm)。loonframework-DAO本身是一个试验性质的项目,内部提供了事务、日志、Cache、异常处理等方面的简单实现,能够不依赖于任何第三方项目而单独运行,当然也可以通过接口选择和其它项目并用,将会陆续提供支持第三方的template以供调用。
3.关于Loonframework-DAO的文件构成
本次公开测试的代码部分如上图所示。
4.关于Loonframework-DAO的初始化设置
Loonframework-DAO通过读取cfg.lf.xml文件初始化设置,该文件基本配置如下:
xml version="1.0" encoding="UTF-8"
?>
<
loon
>
<
pojo
id
="dao"
class
="org.loon.framework.pojo.sys.DAOFruit"
>
<
set
name
="alias"
><
value
type
="string"
>
mysql
value
>
set
>
<
set
name
="jdbcClass"
><
value
type
="string"
>
org.gjt.mm.mysql.Driver
value
>
set
>
<
set
name
="url"
><
value
type
="string"
>
jdbc:mysql://localhost:3306/test?useUnicode=true
value
>
set
>
<
set
name
="use"
><
value
type
="string"
>
ltest
value
>
set
>
<
set
name
="pwd"
><
value
type
="string"
>
value
>
set
>
<
set
name
="minconnection"
><
value
type
="int"
>
100
value
>
set
>
<
set
name
="maxconnection"
><
value
type
="int"
>
100
value
>
set
>
<
set
name
="timeout"
><
value
type
="int"
>
5
value
>
set
>
pojo
>
<
pojo
id
="jtds"
class
="org.loon.framework.pojo.sys.DAOFruit"
>
<
set
name
="alias"
><
value
type
="string"
>
jtds
value
>
set
>
<
set
name
="jdbcClass"
><
value
type
="string"
>
net.sourceforge.jtds.jdbc.Driver
value
>
set
>
<
set
name
="url"
><
value
type
="string"
>
jdbc:jtds:sqlserver://localhost:1433/test
value
>
set
>
<
set
name
="use"
><
value
type
="string"
>
sa
value
>
set
>
<
set
name
="pwd"
><
value
type
="string"
>
value
>
set
>
<
set
name
="minconnection"
><
value
type
="int"
>
100
value
>
set
>
<
set
name
="maxconnection"
><
value
type
="int"
>
100
value
>
set
>
<
set
name
="timeout"
><
value
type
="int"
>
5
value
>
set
>
pojo
>
<
pojo
id
="log"
class
="org.loon.framework.pojo.sys.LOGFruit"
>
<
set
name
="file"
><
value
type
="string"
>
log.txt
value
>
set
>
<
set
name
="servername"
><
value
type
="string"
>
logserver
value
>
set
>
<
set
name
="host"
><
value
type
="string"
>
127.0.0.1
value
>
set
>
<
set
name
="port"
><
value
type
="string"
>
8071
value
>
set
>
<
set
name
="filesys"
><
value
type
="boolean"
>
true
value
>
set
>
<
set
name
="filemark"
><
value
type
="boolean"
>
false
value
>
set
>
<
set
name
="netmark"
><
value
type
="boolean"
>
false
value
>
set
>
pojo
>
<
pojo
id
="cfg"
class
="org.loon.framework.pojo.sys.CFGFruit"
>
<
set
name
="encoding"
><
value
type
="string"
>
utf-8
value
>
set
>
<
set
name
="cache"
><
value
type
="boolean"
>
true
value
>
set
>
<
set
name
="timeout"
><
value
type
="long"
>
60
value
>
set
>
<
set
name
="sleep"
><
value
type
="long"
>
10
value
>
set
>
pojo
>
loon
>
5.关于Loonframework-DAO的事务管理
package
test;
import
java.sql.SQLException;
import
org.loon.framework.dao.DAOManager;
import
org.loon.framework.dao.DAOTransaction;
import
org.loon.framework.log.Log;
import
org.loon.framework.log.LogFactory;
public
class
DAOTransactionTest
...
{
final static private Log log=LogFactory.getInstance(DAOTransactionTest.class);
public static void main(String[]args)...{
//获得默认事务
DAOTransaction transaction= DAOManager.getDefaultTransaction();
try ...{
System.out.println(transaction.getTransactionConnection().isClosed());
} catch (SQLException e) ...{
log.debug(e.getMessage());
}
}
}
通过
DAOManager,我们得到了一个通过连接池获取的,简化了的事务操作。
DAOManager提供的部分方法如下:
利用
DAOTransaction接口,我们可以构建一个简单的事务管理实现。
除了DAOManager外,本项目还提供了一个
javax.transaction.Transaction
的实现,位于org.loon.framework.dao.jta下,需要用户提供UserTransaction实现。
6.关于Loonframework-DAO中的Engine
在Loonframework-DAO中,原则上所有的数据操作都要通过Engine类派生。此类位于org.loon.framework.dao下。
其中静态方法如下:
我们可以通过读取默认配置,设置connection、datasource、daofruit或者选择配置文件中指定的pojo创建Engine。
在
Engine中,目前提供了两种数据处理模式可供选择。
1.通过Execute实现进行操作
//
选择名为dao的数据源配置
Engine engine
=
Engine.begin(
"
dao
"
);
//
获得一个Execute操作
Execute execute
=
engine.makeExecute();
Execute接口如下:
Execute接口是一个基于JDBC的常用CRUD操作封装,他将所有的SQLException封装为精简的LException异常进行处理,并提供了一个复刻ResultSet的Query结果集。
Query接口如下(部分,基本为ResultSet复刻):
Query结果集没有数据库依赖,是一个存在于内存中的ResultSet缓存,我们完全可以关闭数据库后如常使用Query接口,但这也意味着Query中的数据量始终不能保存过大,否则过多的Query将导致内存耗尽。在下一版本会提出解决方案。
Query接口基本用法如下:
//
选择名为dao的数据源配置
Engine engine
=
Engine.begin(
"
dao
"
);
//
获得一个Execute操作
Execute execute
=
engine.makeExecute();
Query query
=
execute.sqlQuery(
"
select * from ltest
"
);
while
(query.isNext())
...
{
//输出数据
System.out.println(query.getString(0));
System.out.println(query.getString("name"));
}
我们可以看出,Query接口缓存ResultSet后滚动结果集的方式几乎与ResultSet接口相同;区别在于,Query接口内部是通过数组及Map实现的,所以索引由0开始。
由于Query本质上是由一个数组内部封装Map实现,所以也提供了很多集合操作功能,如叠代器操作。
for
(Iterator it
=
query.iterator();it.hasNext();)
...
{
System.out.println(((Map)it.next()).get("id"));
}
Query甚至可以通过makeTo方法直接自身匹配为目标类型
//
将query中数据映射到指定类中自动匹配,并返回对象数组
Object[] ltests
=
query.makeTo(Ltest.
class
);
//
ArrayIterator为loonframework提供的数组叠代器
ArrayIterator it
=
new
ArrayIterator(ltests);
for
(;it.hasNext();)
...
{
System.out.println("name="+((Ltest)it.next()).getName());
}
在Execute接口的辅助工具中,还有如Select类这样的存在。
Select是一个简单的xml文件配置查询器,他用于查询及返回存在于xml中的sql语句。
比如,我有已配置好的sql语句如下:
<
loon
>
<
sql
>
<
list
id
="list1"
>
select * from ltest
]]>
list
>
<
list
id
="list2"
>
select * from ltest where id>#id# and name like '%#name#%'
]]>
list
>
<
list
id
="list3"
>
select count(id) from ltest
]]>
list
>
sql
>
loon
>
借助Select类可以这样获得动态的sql语句:
Select select
=
new
Select();
//
或者Select select=Select("/sql.lf.xml");
//
初始一个xml文档
select.initializeConfigure(
"
/sql.lf.xml
"
);
//
以getSelect方式获得指定名称的节点数据
List list
=
execute.sqlQueryToList(select.getSelect(
"
list1
"
));
for
(Iterator it
=
list.iterator();it.hasNext();)
...
{
System.out.println(((Map)it.next()).get("id"));
}
Select还可以根据不同的设置读取任意xml文档,比如有ibatis演示用例的Account.xml:
xml version="1.0" encoding="UTF-8"
?>
DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd"
>
<
sqlMap
namespace
="Account"
>
<
typeAlias
alias
="Account"
type
="com.mydomain.domain.Account"
/>
<
resultMap
id
="AccountResult"
class
="Account"
>
<
result
property
="id"
column
="ACC_ID"
/>
<
result
property
="firstName"
column
="ACC_FIRST_NAME"
/>
<
result
property
="lastName"
column
="ACC_LAST_NAME"
/>
<
result
property
="emailAddress"
column
="ACC_EMAIL"
/>
resultMap
>
<
select
id
="selectAllAccounts"
resultMap
="AccountResult"
>
select * from ACCOUNT
select
>
<
select
id
="selectAccountById"
parameterClass
="int"
resultClass
="Account"
>
select
ACC_ID as id,
ACC_FIRST_NAME as firstName,
ACC_LAST_NAME as lastName,
ACC_EMAIL as emailAddress
from ACCOUNT
where ACC_ID = #id#
select
>
<
insert
id
="insertAccount"
parameterClass
="Account"
>
insert into ACCOUNT (
ACC_ID,
ACC_FIRST_NAME,
ACC_LAST_NAME,
ACC_EMAIL
values (
#id#, #firstName#, #lastName#, #emailAddress#
)
insert
>
<
update
id
="updateAccount"
parameterClass
="Account"
>
update ACCOUNT set
ACC_FIRST_NAME = #firstName#,
ACC_LAST_NAME = #lastName#,
ACC_EMAIL = #emailAddress#
where
ACC_ID = #id#
update
>
<
delete
id
="deleteAccountById"
parameterClass
="int"
>
delete from ACCOUNT where ACC_ID = #id#
delete
>
sqlMap
>
//
也可用于读取其他框架中通过xml进行的sql设置
select.initializeConfigure(
"
/Account.xml
"
,
"
sqlMap
"
,
"
select
"
,
"
id
"
);
System.out.println(select.getSelect(
"
account
"
));
此时我们只要知道目标节点,下属子节点名以及属性就可以检索其中的sql语句
Select类也允许将object中数据自动匹配到获得的sql的#?#标记中
Ltest test
=
new
Ltest();
System.out.println(select.matchObject(test,
"
list2
"
));
此时,会自动匹配所有符合条件的数据到sql中,完成sql语句。
2.通过Handle实现进行操作
该接口目前设置如下:
Handle是Execute的二次封装,他将Execute抽象为针对pojo映射进行操作。
Engine engine
=
Engine.begin();
//
与Execute相同,Handle也需要通过Engine获得
Handle handle
=
engine.makeHandle();
获得Handle后,假设我有如下pojo对象。
public
class
Role
...
{
int caseid;
String name;
long sex;
Date day;
boolean die;
String death;
public int getCaseid() ...{
return caseid;
}
public void setCaseid(int caseid) ...{
this.caseid = caseid;
}
public Date getDay() ...{
return day;
}
public void setDay(Date day) ...{
this.day = day;
}
public String getDeath() ...{
return death;
}
public void setDeath(String death) ...{
this.death = death;
}
public boolean isDie() ...{
return die;
}
public void setDie(boolean die) ...{
this.die = die;
}
public String getName() ...{
return name;
}
public void setName(String name) ...{
this.name = name;
}
public long getSex() ...{
return sex;
}
public void setSex(long sex) ...{
this.sex = sex;
}
}
这时要求我针对此pojo进行一次insert操作到数据库中。
对于这种easy的需求,我们只需要设定如下语句即可轻松完成。
Engine engine=Engine.begin();
//与Execute相同,Handle也需要通过Engine获得
Handle handle=engine.makeHandle();
Role role=
new
Role();
role.setName("鹏凌三千");
role.setSex(1);
role.setDay(
new
Date());
role.setDeath("ABC");
role.setDie(
false
);
try
...
...
{
//插入role到数据库中,主键自动增长
handle.doInsert(role,true);
//提交数据
handle.commit();
}
catch
(LExecuteException e) ...
...
{
//异常则回滚
handle.rollback();
}
此时查询mysql,得知数据增加结果如下:
可以看到,我们没有对pojo进行任何描述,也没有在外部设置任何的对应文档,就成功地将一条数据插入到数据库中。
原理大家都非常清楚,就在于我们在数据库创建表格时,都会对table的主键等参数进行描述,利用jdbc我们可以得到这些设置,只要将这些设置反作用于pojo对象,就可以实现基本操作零配置进行.
通过loonframework-log,我们可以得知操作流程如下:
其它操作同样原理:
但这时就有一个问题,对于简单的CRUD我们虽然可以采取如上操作,但对于略为复杂的操作,比如删除pojo在某一范围内的区域,或者要限定删除或变更对象怎么办呢?
这时,loonframework-DAO提供了一个基于VO接口的解决方案。
VO接口内容如下:
我们令刚才的Role类实现VO接口(红字处将为生效区域)。
public
class
Role
implements
VO
...
{
/** *//**
*
*/
private static final long serialVersionUID = 1L;
int caseid;
String name;
long sex;
Date day;
boolean die;
String death;
public int getCaseid() ...{
return caseid;
}
public void setCaseid(int caseid) ...{
this.caseid = caseid;
}
public Date getDay() ...{
return day;
}
public void setDay(Date day) ...{
this.day = day;
}
public String getDeath() ...{
return death;
}
public void setDeath(String death) ...{
this.death = death;
}
public boolean isDie() ...{
return die;
}
public void setDie(boolean die) ...{
this.die = die;
}
public String getName() ...{
return name;
}
public void setName(String name) ...{
this.name = name;
}
public long getSex() ...{
return sex;
}
public void setSex(long sex) ...{
this.sex = sex;
}
public Object[] getColumn() ...{
return new Object[]...{"name","caseid"};
}
public Object getCondition() ...{
return "name<>'鹏凌三千'";
}
public Object getJoin() ...{
return null;
}
public Object[] getPrimaryKeys() ...{
return null;
}
public String getTableName() ...{
return null;
}
}
此时我们无需更改任何操作代码,执行如下操作:
Engine engine=Engine.begin();
//与Execute相同,Handle也需要通过Engine获得
Handle handle=engine.makeHandle();
Role role=
new
Role();
role.setName("正常人");
role.setSex(1);
role.setDay(
new
Date());
role.setDeath("ABC");
role.setDie(
false
);
try
...
{
//变更
handle.doUpdate(role);
//提交数据
handle.commit();
}
catch
(LExecuteException e)
...
{
//异常则回滚
handle.rollback();
}
此时再查看控制台输出的日志,我们会发现自动生成的sql语句已经有了变化。
此时将自动以VO实现中的设置为优先,令较为复杂的查询得以实现。
如果我们提供相应接口的set方法,就可以动态的设定操作,只需要变更pojo对象,而无需改变操作代码本身。
当然,现在只是一个简单的实现模型,更复杂的操作,将会在后续版本中提供。
7.关于Loonframework-DAO中的其它相关包
在此发布的,除了DAO相关部分之外,还有一些有依赖关系的相关包.
比如自制的Log,Xml,Cache,Collection等部分,但与Loonframework-DAO一样,这些部分并非第三方工具提供,而是个人杜撰而成,并没有经过任何项目的实际运作,也没有经过必要的测试,无法保证其稳定可靠,建议在正式项目中不要使用。
——————————————————————————————————
目前Loonframework三个子项目中DAO及GAME原型系统已经建立,会陆续的发布出来,而WEB方面还在构建中,希望有闲的,想令自己智商上的优越感油然而生的(一般人看到这样的代码都敢发布,都会有这种感觉的^^)先生们女士们能自觉自愿的加盟到此项目中来,以期共同进步。
个人认为做开源项目,除了有想要“提升技术”、“出名”等因素外,更主要的还是为了开阔眼界,了解不同的思路,跟更多的人接触,打破原有意识形态束缚。
世人常说“求同存异”,殊不知天下之兴在“有异”而不在“有同”,“求异存同”才是开源的真正核心价值所在,我常自诩“史上最差程序员”,这么弱的人都敢发开源项目,别人还有什么不敢干,不能干的?
重复发明轮子,当然不是想要替代轮子。假如我能够作的比Hibernate、Spring、Struts等已近乎标准的框架优秀,那不如直接加入这些团队,直接优化原项目,也让他们知道中国人有多牛……
就是因为技术及思想上达不到,才会想自己做开源,从而发现及改进自身的漏洞与不足,所谓授人以鱼,只供一餐,授人以渔,可享一生。
此之谓也。
有兴趣加盟项目的[有爱人士]们……
可以通过:
[email protected]与我联系。
或者
hotmail:[email protected](此msn通常只有晚6:30以后可能在线)
项目地址:
https://sourceforge.net/projects/looframework
目前未分子项目,只创建了DAO一个项目的Alpha版本。