------------------------------
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文件初始化设置,该文件基本配置如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<loon>
<!--在loonframework中,配置会映射到一个对象实体进行操作,DAOFruit为数据驱动设定-->
<pojoid="dao"class="org.loon.framework.pojo.sys.DAOFruit">
<!--驱动别名,选填-->
<setname="alias"><valuetype="string">mysql</value></set>
<!--jdbc驱动类,可使用全写也支持'mysql'、'oralce'这样的简写方式-->
<setname="jdbcClass"><valuetype="string">org.gjt.mm.mysql.Driver</value></set>
<!--url地址--> <setname="url"><valuetype="string">jdbc:mysql://localhost:3306/test?useUnicode=true</value></set>
<!--用户名-->
<setname="use"><valuetype="string">ltest</value></set>
<!--密码-->
<setname="pwd"><valuetype="string"></value></set>
<!--最小连接数,选填。loonframework-dao内置有一个小型的连接池,可通过DAOManager类启动-->
<setname="minconnection"><valuetype="int">100</value></set>
<!--最大连接数,选填-->
<setname="maxconnection"><valuetype="int">100</value></set>
<!--超时设定-->
<setname="timeout"><valuetype="int">5</value></set>
</pojo>
<pojoid="jtds"class="org.loon.framework.pojo.sys.DAOFruit">
<setname="alias"><valuetype="string">jtds</value></set>
<setname="jdbcClass"><valuetype="string">net.sourceforge.jtds.jdbc.Driver</value></set>
<setname="url"><valuetype="string">jdbc:jtds:sqlserver://localhost:1433/test</value></set>
<setname="use"><valuetype="string">sa</value></set>
<setname="pwd"><valuetype="string"></value></set>
<setname="minconnection"><valuetype="int">100</value></set>
<setname="maxconnection"><valuetype="int">100</value></set>
<setname="timeout"><valuetype="int">5</value></set>
</pojo>
<!--LOGFruit为日志设定-->
<pojoid="log"class="org.loon.framework.pojo.sys.LOGFruit">
<!--此项为生成的文件名,可以设定相关路径,无设置以默认路径保存-->
<setname="file"><valuetype="string">log.txt</value></set>
<!--此项为log服务名,启动服务后有效-->
<setname="servername"><valuetype="string">logserver</value></set>
<!--服务器所在地址-->
<setname="host"><valuetype="string">127.0.0.1</value></set>
<!--服务器端口-->
<setname="port"><valuetype="string">8071</value></set>
<!--是否在控制台显示log中信息-->
<setname="filesys"><valuetype="boolean">true</value></set>
<!--是否保存log文件-->
<setname="filemark"><valuetype="boolean">false</value></set>
<!--是否允许log服务启动-->
<setname="netmark"><valuetype="boolean">false</value></set>
</pojo>
<!--此项为基础配置,在0.1.0版本中未实装-->
<pojoid="cfg"class="org.loon.framework.pojo.sys.CFGFruit">
<setname="encoding"><valuetype="string">utf-8</value></set>
<setname="cache"><valuetype="boolean">true</value></set>
<setname="timeout"><valuetype="long">60</value></set>
<setname="sleep"><valuetype="long">10</value></set>
</pojo>
</loon>
5.关于Loonframework-DAO的事务管理
packagetest;

importjava.sql.SQLException;

importorg.loon.framework.dao.DAOManager;
importorg.loon.framework.dao.DAOTransaction;
importorg.loon.framework.log.Log;
importorg.loon.framework.log.LogFactory;


publicclassDAOTransactionTest...{

finalstaticprivateLoglog=LogFactory.getInstance(DAOTransactionTest.class);


publicstaticvoidmain(String[]args)...{
//获得默认事务
DAOTransactiontransaction=DAOManager.getDefaultTransaction();

try...{
System.out.println(transaction.getTransactionConnection().isClosed());

}catch(SQLExceptione)...{
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的数据源配置
Engineengine=Engine.begin("dao");
//获得一个Execute操作
Executeexecute=engine.makeExecute();
Execute接口如下:

Execute接口是一个基于JDBC的常用CRUD操作封装,他将所有的SQLException封装为精简的LException异常进行处理,并提供了一个复刻ResultSet的Query结果集。
Query接口如下(部分,基本为ResultSet复刻):

Query结果集没有数据库依赖,是一个存在于内存中的ResultSet缓存,我们完全可以关闭数据库后如常使用Query接口,但这也意味着Query中的数据量始终不能保存过大,否则过多的Query将导致内存耗尽。在下一版本会提出解决方案。
Query接口基本用法如下:
//选择名为dao的数据源配置
Engineengine=Engine.begin("dao");
//获得一个Execute操作
Executeexecute=engine.makeExecute();
Queryquery=execute.sqlQuery("select*fromltest");


while(query.isNext())...{
//输出数据
System.out.println(query.getString(0));
System.out.println(query.getString("name"));
}
我们可以看出,Query接口缓存ResultSet后滚动结果集的方式几乎与ResultSet接口相同;区别在于,Query接口内部是通过数组及Map实现的,所以索引由0开始。
由于Query本质上是由一个数组内部封装Map实现,所以也提供了很多集合操作功能,如叠代器操作。

for(Iteratorit=query.iterator();it.hasNext();)...{
System.out.println(((Map)it.next()).get("id"));
}
Query甚至可以通过makeTo方法直接自身匹配为目标类型
//将query中数据映射到指定类中自动匹配,并返回对象数组
Object[]ltests=query.makeTo(Ltest.class);
//ArrayIterator为loonframework提供的数组叠代器
ArrayIteratorit=newArrayIterator(ltests);

for(;it.hasNext();)...{
System.out.println("name="+((Ltest)it.next()).getName());
}
在Execute接口的辅助工具中,还有如Select类这样的存在。
Select是一个简单的xml文件配置查询器,他用于查询及返回存在于xml中的sql语句。
比如,我有已配置好的sql语句如下:
<loon>
<sql>
<listid="list1"><![CDATA[select*fromltest]]></list>
<listid="list2"><![CDATA[select*fromltestwhereid>#id#andnamelike'%#name#%']]></list>
<listid="list3"><![CDATA[selectcount(id)fromltest]]></list>
</sql>
</loon>
借助Select类可以这样获得动态的sql语句:
Selectselect=newSelect();
//或者Selectselect=Select("/sql.lf.xml");
//初始一个xml文档
select.initializeConfigure("/sql.lf.xml");
//以getSelect方式获得指定名称的节点数据
Listlist=execute.sqlQueryToList(select.getSelect("list1"));

for(Iteratorit=list.iterator();it.hasNext();)...{
System.out.println(((Map)it.next()).get("id"));
}
Select还可以根据不同的设置读取任意xml文档,比如有ibatis演示用例的Account.xml:
<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEsqlMap
PUBLIC"-//ibatis.apache.org//DTDSQLMap2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMapnamespace="Account">

<!--Usetypealiasestoavoidtypingthefullclassnameeverytime.-->
<typeAliasalias="Account"type="com.mydomain.domain.Account"/>

<!--Resultmapsdescribethemappingbetweenthecolumnsreturned
fromaquery,andtheclassproperties.Aresultmapisn't
necessaryifthecolumns(oraliases)matchtotheproperties
exactly.-->
<resultMapid="AccountResult"class="Account">
<resultproperty="id"column="ACC_ID"/>
<resultproperty="firstName"column="ACC_FIRST_NAME"/>
<resultproperty="lastName"column="ACC_LAST_NAME"/>
<resultproperty="emailAddress"column="ACC_EMAIL"/>
</resultMap>

<!--SelectwithnoparametersusingtheresultmapforAccountclass.-->
<selectid="selectAllAccounts"resultMap="AccountResult">
select*fromACCOUNT
</select>

<!--Asimplerselectexamplewithouttheresultmap.Notethe
aliasestomatchthepropertiesofthetargetresultclass.-->
<selectid="selectAccountById"parameterClass="int"resultClass="Account">
select
ACC_IDasid,
ACC_FIRST_NAMEasfirstName,
ACC_LAST_NAMEaslastName,
ACC_EMAILasemailAddress
fromACCOUNT
whereACC_ID=#id#
</select>

<!--Insertexample,usingtheAccountparameterclass-->
<insertid="insertAccount"parameterClass="Account">
insertintoACCOUNT(
ACC_ID,
ACC_FIRST_NAME,
ACC_LAST_NAME,
ACC_EMAIL
values(
#id#,#firstName#,#lastName#,#emailAddress#
)
</insert>

<!--Updateexample,usingtheAccountparameterclass-->
<updateid="updateAccount"parameterClass="Account">
updateACCOUNTset
ACC_FIRST_NAME=#firstName#,
ACC_LAST_NAME=#lastName#,
ACC_EMAIL=#emailAddress#
where
ACC_ID=#id#
</update>

<!--Deleteexample,usinganintegerastheparameterclass-->
<deleteid="deleteAccountById"parameterClass="int">
deletefromACCOUNTwhereACC_ID=#id#
</delete>

</sqlMap>
//也可用于读取其他框架中通过xml进行的sql设置
select.initializeConfigure("/Account.xml","sqlMap","select","id");
System.out.println(select.getSelect("account"));
此时我们只要知道目标节点,下属子节点名以及属性就可以检索其中的sql语句
Select类也允许将object中数据自动匹配到获得的sql的#?#标记中
Ltesttest=newLtest();
System.out.println(select.matchObject(test,"list2"));
此时,会自动匹配所有符合条件的数据到sql中,完成sql语句。
2.通过Handle实现进行操作
该接口目前设置如下:

Handle是Execute的二次封装,他将Execute抽象为针对pojo映射进行操作。
Engineengine=Engine.begin();
//与Execute相同,Handle也需要通过Engine获得
Handlehandle=engine.makeHandle();
获得Handle后,假设我有如下pojo对象。

publicclassRole...{

intcaseid;

Stringname;

longsex;

Dateday;

booleandie;

Stringdeath;


publicintgetCaseid()...{
returncaseid;
}


publicvoidsetCaseid(intcaseid)...{
this.caseid=caseid;
}


publicDategetDay()...{
returnday;
}


publicvoidsetDay(Dateday)...{
this.day=day;
}


publicStringgetDeath()...{
returndeath;
}


publicvoidsetDeath(Stringdeath)...{
this.death=death;
}


publicbooleanisDie()...{
returndie;
}


publicvoidsetDie(booleandie)...{
this.die=die;
}


publicStringgetName()...{
returnname;
}


publicvoidsetName(Stringname)...{
this.name=name;
}


publiclonggetSex()...{
returnsex;
}


publicvoidsetSex(longsex)...{
this.sex=sex;
}

}
这时要求我针对此pojo进行一次insert操作到数据库中。
对于这种easy的需求,我们只需要设定如下语句即可轻松完成。
Engineengine=Engine.begin();
//与Execute相同,Handle也需要通过Engine获得
Handlehandle=engine.makeHandle();
Rolerole=newRole();
role.setName("鹏凌三千");
role.setSex(1);
role.setDay(newDate());
role.setDeath("ABC");
role.setDie(false);

try......{
//插入role到数据库中,主键自动增长
handle.doInsert(role,true);
//提交数据
handle.commit();

}catch(LExecuteExceptione)......{
//异常则回滚
handle.rollback();
}
此时查询mysql,得知数据增加结果如下:

可以看到,我们没有对pojo进行任何描述,也没有在外部设置任何的对应文档,就成功地将一条数据插入到数据库中。
原理大家都非常清楚,就在于我们在数据库创建表格时,都会对table的主键等参数进行描述,利用jdbc我们可以得到这些设置,只要将这些设置反作用于pojo对象,就可以实现基本操作零配置进行.
通过loonframework-log,我们可以得知操作流程如下:

其它操作同样原理:

但这时就有一个问题,对于简单的CRUD我们虽然可以采取如上操作,但对于略为复杂的操作,比如删除pojo在某一范围内的区域,或者要限定删除或变更对象怎么办呢?
这时,loonframework-DAO提供了一个基于VO接口的解决方案。
VO接口内容如下:
packageorg.loon.framework.dao.object;

importorg.loon.framework.core.LSerializable;


/***//**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:VO接口,需要在其中规定调用sql的依据条件。当实现的返回结果为null或""时,
*将自动引用table为pojo作自动实现。
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*@authorchenpeng
*@email:[email protected]
*@version0.1
*/

publicinterfaceVOextendsLSerializable...{


/***//**
*表名
*
*@return
*/
publicStringgetTableName();


/***//**
*主键
*
*@return
*/
publicObject[]getPrimaryKeys();


/***//**
*连接语句
*
*@paramsequence
*/
publicObjectgetJoin();


/***//**
*允许的条件
*
*@return
*/
publicObjectgetCondition();


/***//**
*允许的列名
*
*@return
*/
publicObject[]getColumn();

}
我们令刚才的Role类实现VO接口(红字处将为生效区域)。

publicclassRoleimplementsVO...{


/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;

intcaseid;

Stringname;

longsex;

Dateday;

booleandie;

Stringdeath;


publicintgetCaseid()...{
returncaseid;
}


publicvoidsetCaseid(intcaseid)...{
this.caseid=caseid;
}


publicDategetDay()...{
returnday;
}


publicvoidsetDay(Dateday)...{
this.day=day;
}


publicStringgetDeath()...{
returndeath;
}


publicvoidsetDeath(Stringdeath)...{
this.death=death;
}


publicbooleanisDie()...{
returndie;
}


publicvoidsetDie(booleandie)...{
this.die=die;
}


publicStringgetName()...{
returnname;
}


publicvoidsetName(Stringname)...{
this.name=name;
}


publiclonggetSex()...{
returnsex;
}


publicvoidsetSex(longsex)...{
this.sex=sex;
}


publicObject[]getColumn()...{

returnnewObject[]...{"name","caseid"};
}


publicObjectgetCondition()...{
return"name<>'鹏凌三千'";
}


publicObjectgetJoin()...{
returnnull;
}


publicObject[]getPrimaryKeys()...{
returnnull;
}


publicStringgetTableName()...{
returnnull;
}

}
此时我们无需更改任何操作代码,执行如下操作:
Engineengine=Engine.begin();
//与Execute相同,Handle也需要通过Engine获得
Handlehandle=engine.makeHandle();
Rolerole=newRole();
role.setName("正常人");
role.setSex(1);
role.setDay(newDate());
role.setDeath("ABC");
role.setDie(false);

try...{
//变更
handle.doUpdate(role);
//提交数据
handle.commit();

}catch(LExecuteExceptione)...{
//异常则回滚
handle.rollback();
}
此时再查看控制台输出的日志,我们会发现自动生成的sql语句已经有了变化。

此时将自动以VO实现中的设置为优先,令较为复杂的查询得以实现。
如果我们提供相应接口的set方法,就可以动态的设定操作,只需要变更pojo对象,而无需改变操作代码本身。
当然,现在只是一个简单的实现模型,更复杂的操作,将会在后续版本中提供。
7.关于Loonframework-DAO中的其它相关包
在此发布的,除了DAO相关部分之外,还有一些有依赖关系的相关包.
比如自制的Log,Xml,Cache,Collection等部分,但与Loonframework-DAO一样,这些部分并非第三方工具提供,而是个人杜撰而成,并没有经过任何项目的实际运作,也没有经过必要的测试,无法保证其稳定可靠,建议在正式项目中不要使用。
——————————————————————————————————
目前Loonframework三个子项目中DAO及GAME原型系统已经建立,会陆续的发布出来,而WEB方面还在构建中,希望有闲的,想令自己智商上的优越感油然而生的(一般人看到这样的代码都敢发布,都会有这种感觉的^^)先生们女士们能自觉自愿的加盟到此项目中来,以期共同进步。
个人认为做开源项目,除了有想要“提升技术”、“出名”等因素外,更主要的还是为了开阔眼界,了解不同的思路,跟更多的人接触,打破原有意识形态束缚。
世人常说“求同存异”,殊不知天下之兴在“有异”而不在“有同”,“求异存同”才是开源的真正核心价值所在,我常自诩“史上最差程序员”,这么弱的人都敢发开源项目,别人还有什么不敢干,不能干的?
重复发明轮子,当然不是想要替代轮子。假如我能够作的比Hibernate、Spring、Struts等已近乎标准的框架优秀,那不如直接加入这些团队,直接优化原项目,也让他们知道中国人有多牛……
就是因为技术及思想上达不到,才会想自己做开源,从而发现及改进自身的漏洞与不足,所谓授人以鱼,只供一餐,授人以渔,可享一生。此之谓也。
有兴趣加盟项目的[有爱人士]们……
可以通过:ceponline@yahoo.com.cn与我联系。
或者hotmail:[email protected](此msn通常只有晚6:30以后可能在线)
项目地址:
https://sourceforge.net/projects/looframework
目前未分子项目,只创建了DAO一个项目的Alpha版本。
相关文章: