选择显示字体大小

深入浅出persistence layer(2)

<h3 class=title>深入浅出persistence layer(2)<br><font size=2>from martin的blog: </font><a href=&quot;http://www.matrix.org.cn/blog/martin/&quot;><font size=2>http://www.matrix.org.cn/blog/martin/</font></a></h3>
<p>主流的persistence layer都有自己的配置文件,用于存储对象类与数据库的映射信息。执行save,delete,update,retrieve等操作时,persistence layer会自动生成所需要的sql语句并执行。这一核心过程是persistence layer的灵魂,orm、jdo、ejb均无能例外。深入篇讲述pl的 映射-&gt;装载-&gt;生成sql 全过程。</p><a name=more></a>
<p>一.准备<br>二.映射<br>三.装载<br>四.生成</p>
<p>一.准备<br>1.下载pl项目<br>下载<a href=&quot;http://player.sourceforge.net/&quot;><font color=#888888>artem rudoy的开源项目pl</font></a>,这是根据scott w. ambler的论文实现的orm。解压缩到某个路径。</p>
<p>2.安装数据库<br>安装<a href=&quot;http://www.mysql.com/&quot;><font color=#888888>mysql数据库</font></a>,建议使用v3.23以上的版本。同时下载<a href=&quot;http://mmmysql.sourceforge.net/&quot;><font color=#888888>mysql jdbc driver</font></a>。将它加到classpath中。</p>
<p>3.创建测试数据库<br>在mysql数据库中创建pltest数据库,执行解压缩路径下的test\mysqltest.sql,创建测试的数据表。</p>
<p>4.修改数据库连接属性<br>打开解压缩路径下的test\mysqltest.xml,修改user和password,其他不变。</p>
<p><br>二.映射<br>解压缩路径下的test\schema.xml,是pl的映射文件。<br>以下是映射文件的一个片段:</p>
<p><img height=503 alt=映射文件 src=&quot;http://www.matrix.org.cn/blog/martin/archives/image/orm2_2.jpg&quot; width=536 border=0></p>
<p>顶层是map节点,map节点包含class和association子节点。<br>class节点代表一个类,class节点包含class-name,table-name,database-name和attribute子节点。<br>association节点代表一个关联关系。(关联信息的处理在此不作深入,将另文叙述)</p>
<p>三.装载</p>
<p>pl.test.test 是pl提供的测试类中的其中一个, 这个测试类很小但是测试内容却不少,包含:<br>1)单一对象和事务的测试<br>2)单一继承对象的测试<br>3)关联支持的测试<br>4)空条件、简单条件、复杂条件的测试<br>5)乐观锁定测试<br>6)代理对象、代理对象条件测试<br>...</p>
<p>pl虽小,却是五脏俱全!</p>
<p><br>1.读映射文件</p>
<p>pl装载映射信息是通过persistencebroker.loadconfig()方法完成的。<br>如下是pl.test.test类的代码</p>
<p>public void performtest()<br>{<br>try<br>{<br>persistencebroker.getinstance().setdebug(true);<br>persistencebroker.getinstance().init();</p>
<p>string dir = &quot;d:\\workspace\\persisterlayer\\test\\&quot;;<br>// 装载数据库信息<br><font color=blue>persistencebroker.getinstance().loadconfig(new xmlconfigloader(dir + &quot;mysqltest.xml&quot;));</font> <br>// 装载类-数据表映射信息<br><font color=blue>persistencebroker.getinstance().loadconfig(new xmlconfigloader(dir + &quot;schema.xml&quot;));</font></p>
<p>跟踪persistencebroker.loadconfig()方法,发现其调用了configloader.loadconfig()方法,而configloader是一个接口,conxmlconfigloader才是实现。<br>因此查看 xmlconfigloader.loadconfig方法:</p>
<p>public void loadconfig(persistencebroker broker) throws plexception<br>{<br>this.broker = broker;<br>try<br>{<br>documentbuilderfactory dbf = documentbuilderfactory.newinstance();<br>dbf.setvalidating(false);<br>documentbuilder db = dbf.newdocumentbuilder();<br>document document = db.parse(in);</p>
<p>element root = getfirstnamedchildelement(document, &quot;map&quot;);<br>if(root == null)<br>throw new plexception(&quot;invalid xml document. no map definition found&quot;);<br><br>element child = null;<br><br>// 获取数据库连接信息<br>child = getfirstnamedchildelement(root, &quot;database&quot;);<br>while(child != null)<br>{<br><font color=blue>pl.sql.relationaldatabase pm = getrelationaldatabase(child);<br>broker.addrelationaldatabase(pm);</font> <br>child = getnextnamedsiblingelement(child, &quot;database&quot;);<br>}<br><br>// 获取映射类信息<br>child = getfirstnamedchildelement(root, &quot;class&quot;);<br>while(child != null)<br>{<br><font color=blue>classmap cm = getclassmap(child);<br>broker.addclassmap(cm);</font> <br>child = getnextnamedsiblingelement(child, &quot;class&quot;);<br>}</p>
<p><br>可以看到, 这个方法通过getrelationaldatabase(child)方法创建一个pl.sql.relationaldatabase对象(存储数据库信息),然后通过<br>broker.addrelationaldatabase(pm) 将 relationaldatabase对象保存在 persistencebroker类中。<br>类的映射信息也类似,先通过 getclassmap(child) 构造 classmap 对象,然后 调用broker.addclassmap(cm) 将classmap对象保存在<br>persistencebroker类中。</p>
<p>2. 内存中的映射信息</p>
<p>查看xmlconfigloader的getclassmap方法,可以看出pl是怎样在内存中构造映射类的.<br>下图是映射类的关系图:<br><img height=403 alt=映射类的关系 src=&quot;http://www.matrix.org.cn/blog/martin/archives/image/orm2_1.jpg&quot; width=550 border=0></p>
<p><br>1)为每一个database创建一个databasemap;<br>2)为每一个table创建一个tablemap;tablemap中存储了对databasemap的关联;<br>3)为每一个表字段(column)创建一个columnmap;columnmap中存储了对tablemap的关联<br>4)为每一个class创建一个classmap; classmap中用arraylist attributemaps 来存放类的属性列表<br>5)为每一个类的属性(attribute)创建一个attributemap;attributemap中存储了对columnmap的关联。</p>
<p><br>四.生成</p>
<p>pl生成sql语句是分别在两个阶段完成。第一个阶段是在初始化阶段,从映射文件schema.xml读取映射信息,这个阶段生成的是基本的sql语句。 第二阶段是运行阶段,从程序调用中取得实际值(如查询的条件,更新的字段值等),从而生成真实运行的sql语句。</p>
<p>1.初始化阶段</p>
<p>查看persistencebroker.addclassmap方法, 如下,<br>public void addclassmap(classmap classmap) throws plexception<br>{<br>classmap.init();<br>classmaps.put(classmap.getname(), classmap);<br>}<br>它先执行classmap.init()方法,然后将classmap存放到persistencebroker的私有对象classmaps中,classmaps是一个treemap。</p>
<p>classmap.init是一个非常重要的方法,一个classmap类只执行一次。这个方法初始化了对这个classmap所有操作的sql语句。<br>(读入配置文件时就可以构造所有要操作的sql语句?简直象玩魔术啊!可行吗?请思考!)</p>
<p><br>我们知道对一个数据表的操作有select,insert,delete,update四种操作,每一种操作在pl中使用sqlstatement类保存其sql语句 。<br>classmap类中则为每一个操作定义了一个私有的sqlstatement对象。如下是classmap类的定义:</p>
<p>public class classmap<br>{<br>private string name = null;<br>private sqlstatement selectstatement = null;<br>private sqlstatement selectproxystatement = null;<br>private sqlstatement selecttimestampstatement = null;<br>private sqlstatement insertstatement = null;<br>private sqlstatement deletestatement = null;<br>private sqlstatement updatestatement = null;</p>
<p>classmap一共有6个sqlstatement对象, 除了crud4个操作外,还有selectproxystatement(用来实现代理),selecttimestampstatement(用来实现最后修改的记录)。</p>
<p><br>init方法就是用来初始化这些sqlstatement对象的,初始化了这些sqlstatement对象,也就有了基本的sql语句了。<br>如下是classmap的init方法<br>public synchronized void init() throws pl.plexception<br>{<br>// we don't have to init class map twice<br>if(isinited)<br>return;<br>// init all statements<br>//<br>// init select statement<br>//<br><font color=blue>selectstatement = getselectsql();</font><br>// add 'from' and 'where' clauses to the select statement<br>selectstatement.addsqlclause(&quot; &quot;);<br><font color=blue>selectstatement.addsqlstatement(getfromandwheresql());</font></p>
<p>现在我们来看看sqlstatement是怎样获得sql语句的。<br>从上面代码可以看出构造selectstatement的sql语句关键方法有两个:getselectsql和getfromandwheresql。<br>上面代码执行完将selectstatement打印出来可以看到sql为: select person.id, person.name from person where person.id=?</p>
<p>1.取select部分<br>下面是getselectsql的代码:<br>public sqlstatement getselectsql() throws plexception<br>{<br>// create new statement<br>sqlstatement statement = new sqlstatement();</p>
<p>// add 'select' clause to the select statement <br><font color=blue>statement.addsqlclause(getrelationaldatabase().getclausestringselect() + &quot; &quot;);</font><br>// add clauses for all attributes. do not add &quot;, &quot; before the first attribute<br>boolean isfirst = true;<br>classmap classmap = this;<br>do<br>{<br>for (int i = 0; i &lt; classmap.getsize(); i++)<br>{<br>statement.addsqlclause((isfirst ? &quot;&quot; : &quot;, &quot;) +<br><font color=blue>classmap.getattributemap(i).getcolumnmap().getfullyqualifiedname());</font> <br>isfirst = false;<br>}<br>其中的 getrelationaldatabase().getclausestringselect() 取到 &quot; select &quot;<br>而classmap.getattributemap(i).getcolumnmap().getfullyqualifiedname()) 将分别取到 person.id 和 person.name</p>
<p>2.取where部分<br>下面是getfromandwheresql的代码<br>public sqlstatement getfromandwheresql() throws plexception<br>{<br>// create new statement<br>sqlstatement statement = new sqlstatement();</p>
<p>// add 'from' clause to the select statement<br><font color=blue>statement.addsqlclause(&quot; &quot; + getrelationaldatabase().getclausestringfrom() + &quot; &quot;);</font> <br>boolean isfirst = true;<br>classmap classmap = this;<br>do<br>{<br>attributemap map = classmap.getattributemap(0);<br>if (map != null)<br>{<br><font color=blue>statement.addsqlclause((isfirst ? &quot;&quot; : &quot;, &quot;) + map.getcolumnmap().gettablemap().getname());</font><br>}<br>classmap = classmap.getsuperclass();<br>isfirst = false;<br>}<br>// add 'where key=?' to the select statement<br>if(getkeysize() &gt; 0 inheritanceassociations.length() &gt; 0)<br>{<br>statement.addsqlclause(&quot; &quot;);</p>
<p>statement.addsqlclause(getrelationaldatabase().getclausestringwhere() + &quot; &quot;);<br>for(int i = 0; i &lt; getkeysize(); i++)<br>{<br><font color=blue>statement.addsqlclause((i &gt; 0 ? &quot; &quot; + getrelationaldatabase().getclausestringand() + &quot; &quot; : &quot;&quot;) +<br>getkeyattributemap(i).getcolumnmap().getfullyqualifiedname() + &quot;=?&quot;);</font> <br>}</p>
<p>}</p>
<p>其中的 getrelationaldatabase().getclausestringfrom() 取到 &quot; from &quot;,<br>map.getcolumnmap().gettablemap().getname() 取到 表名&quot;person&quot;<br>getrelationaldatabase().getclausestringwhere() 取到 &quot;where&quot;<br>getkeyattributemap(i).getcolumnmap().getfullyqualifiedname() 取到 person.id </p>
<p>2.运行阶段<br>(con...)</p>


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons