﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-性格决定命运 气度影响格局</title><link>http://www.blogjava.net/anwenhao/</link><description /><language>zh-cn</language><lastBuildDate>Wed, 29 Apr 2026 00:55:41 GMT</lastBuildDate><pubDate>Wed, 29 Apr 2026 00:55:41 GMT</pubDate><ttl>60</ttl><item><title>JDO 的使用和集成</title><link>http://www.blogjava.net/anwenhao/archive/2011/05/15/350280.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Sun, 15 May 2011 09:19:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2011/05/15/350280.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/350280.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2011/05/15/350280.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/350280.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/350280.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt;"><span style="font-family: 微软雅黑;"><span style="font-family: 宋体;"><span style="font-family: Tahoma;"><span style="font-family: Arial;"><span style="font-family: Times New Roman;"><span style="font-family: Arial;">JDO 的使用和集成<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这里不想讨论JDO和JPA的区别，也不讨论JDO的规范，单只是从JDO的使用和与应用的集成角度来概述。<br />
<br />
1. 下载JDO规范的实现开源包。目前主流的JDO实现有：<br />
*.TJDO http://tjdo.sf.net<br />
*.Speedo http://speedo.objectweb.org<br />
*.JORM http://jorm.objectweb.org<br />
*.XORM http://xorm.sourceforge.net<br />
*.JPOX http://jpox.sourceforge.net<br />
*.OJB http://db.apache.org/ojb/<br />
*.DataNucleus http://www.datanucleus.org/ <br />
&nbsp;<br />
2. 这里选择DataNucleus为JDO的实现，因为个人认为datanucleus大有一统O/R Mapping天下的架势。前端支持JDO/JPA规范，后面能接多种数据存储平台(RDBMS, ODBMS, Map-based, Web-based, documents, etc) . 并且直接可与bigtable、hbase等分布式数据库集成。实在强大。<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 下载DataNucleus程序包<br />
&nbsp;&nbsp;&nbsp;&nbsp; * 下载DataNucleus在eclipse下的扩展插件<br />
<br />
3. 如果使用dataNucleus连接DBMS数据库(Mysql)需要加入以下几个jar包：<br />
&nbsp;&nbsp;&nbsp;&nbsp; datanucleus-enhancer-3.0.0-m4.jar&nbsp;&nbsp; jdo-api-3.1-SNAPSHOT-20110319.jar&nbsp; datanucleus-api-jdo-3.0.0-m4.jar&nbsp; datanucleus-jdo-query-3.0.0-m2.jar&nbsp;&nbsp;&nbsp; asm.jar<br />
&nbsp;&nbsp;&nbsp;&nbsp; mysql-connector-java-5.0.4-bin.jar&nbsp; datanucleus-cache-3.0.0-m2.jar&nbsp;&nbsp;&nbsp; datanucleus-management-1.0.2.jar datanucleus-core-3.0.0-m4.jar&nbsp;&nbsp;&nbsp;&nbsp; datanucleus-rdbms-3.0.0-m4.jar<br />
<br />
4. 创建一个entity class 并配置映射文件 如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp; entity class :<br />
@PersistenceCapable<br />
public class Person {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @PrimaryKey<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String name ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int age ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String mail ;<br />
&nbsp;&nbsp;&nbsp;&nbsp; .......<br />
}<br />
&nbsp;&nbsp; mapping xml<br />
&lt;jdo&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;package name="com.jdo.data.nucleus.model"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;class name="Person"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name="name" persistence-modifier="persistent"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column length="100" /&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/field&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name="age" persistence-modifier="persistent"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name="mail" persistence-modifier="persistent"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/package&gt;<br />
&lt;/jdo&gt;<br />
<br />
5.创建JDO操作类：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Map&lt;String,String&gt; JDOConfig = new HashMap&lt;String,String&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOConfig.put( "javax.jdo.PersistenceManagerFactoryClass" ,"org.datanucleus.api.jdo.JDOPersistenceManagerFactory" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOConfig.put("javax.jdo.option.ConnectionURL", "jdbc:mysql://localhost/acegi" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOConfig.put( "javax.jdo.option.ConnectionDriverName" , "com.mysql.jdbc.Driver" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOConfig.put( "javax.jdo.option.ConnectionUserName" , "root");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOConfig.put( "javax.jdo.option.ConnectionPassword" , "root");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOConfig.put( "javax.jdo.option.NontransactionalRead" , "true");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOConfig.put( "javax.jdo.option.NontransactionalWrite" , "true");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JDOConfig.put( "datanucleus.autoCreateSchema" , "true" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(JDOConfig);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PersistenceManager pm = pmf.getPersistenceManager();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Person person = null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System. out.println("Insert iterm into DB. " );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //insert<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; person = new Person("wenhao" ,123,"wenhao@gmail.com");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pm.makePersistent(person);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //select<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getPersonsFromDB(pm);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //update<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; person.setMail( "wenhao@sina.com.cn");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pm.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; person.setAge(1000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System. out.println("instance level : " + person.getAge());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pmf = JDOHelper. getPersistenceManagerFactory(JDOConfig);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pm = pmf.getPersistenceManager();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;Person&gt; updatePersons = getPersonsFromDB(pm);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(updatePersons != null &amp;&amp; updatePersons.size() &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(Person updatePerson : updatePersons)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //delete<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pm.deletePersistent(updatePerson);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System. out.println("Delete iterms from DB." );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pm.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //select<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Query q = pm.newQuery( "SELECT FROM " + Person.class.getName() + " WHERE name == 'wenhao'" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;Person&gt; updatePersons = (List)q.execute();<br />
<br />
6. 运行JDO操作类，这时直接运行会报如下的错误：<br />
This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这个错误的是因为没有对Entity class进行jdo的enhance来增强entity的二进制代码。故需要在project上增加datanucleus支持。并运行enhancer tool来enhance entity。运行后可通过反编译工具来查看transform后的class。可发现多了一些属性和方法。这些都是对JDO entity的扩展。<br />
<br />
7.正常运行<br />
&nbsp;&nbsp;&nbsp;&nbsp; 会发现在person.setMail( "wenhao@sina.com.cn" );会更改到底层的数据库中，而person.setAge(1000);并不会更改数据库字段。其实很容易理解。类似hibernate的entity的几个状态，自由态&#183;持久态&#183;游离态。 当pm.close();后person处于自由态，修改的属性只有在instance内部有效。而在pm cloase或transaction.commit之前时，entity仍处理持久化状态，直接修改属性，会持久化到底层数据库中。<br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
8.JDO对象的多对多关系实现。多对多和hibernate的配置类似，主要还是在配置文件上做一些配置。配置文件如下：<br />
Person.jdo:<br />
&lt;jdo&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;package name="com.jdo.data.nucleus.model"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;class name="Person"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name="name" persistence-modifier="persistent"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column length="100" jdbc-type="VARCHAR" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/field&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name="age" persistence-modifier="persistent"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name="mail" persistence-modifier="persistent"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: red;">&lt;field name="roles" persistence-modifier="persistent" table="PERSON_RULE"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;collection element-type="com.jdo.data.nucleus.model.Role" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;join&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="name" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/join&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;element&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="roleName" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/element&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/field&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/package&gt;<br />
&lt;/jdo&gt;<br />
Role.jdo:<br />
&lt;jdo&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;package name="com.jdo.data.nucleus.model"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;class name="Role"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name="roleName" persistence-modifier="persistent"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column length="100" jdbc-type="VARCHAR" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/field&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;field name="roleDesc" persistence-modifier="persistent"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: red;">&lt;field name="persons" persistence-modifier="persistent" table="PERSON_RULE"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;collection element-type="com.jdo.data.nucleus.model.Person" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;join&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="roleName" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/join&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;element&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="name" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/element&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/field&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/package&gt;<br />
&lt;/jdo&gt;<br />
Person.java:<br />
@PersistenceCapable<br />
public class Person {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @PrimaryKey<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String name ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private int age ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String mail ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Element<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Set&lt;Role&gt; roles ;<br />
}<br />
Role.java:<br />
@PersistenceCapable<br />
public class Role {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @PrimaryKey<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String roleName ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String roleDesc ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Element<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Set&lt;Person&gt; persons ;<br />
}<br />
以上配置可实现多对多的关系。并能够进行关联查询。<br />
<br />
</span></span></span></span></span></span></span><img src ="http://www.blogjava.net/anwenhao/aggbug/350280.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2011-05-15 17:19 <a href="http://www.blogjava.net/anwenhao/archive/2011/05/15/350280.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>给大家推荐一款超酷的软件原型设计工具-Balsamiq Mockups</title><link>http://www.blogjava.net/anwenhao/archive/2009/02/25/256600.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Wed, 25 Feb 2009 06:02:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2009/02/25/256600.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/256600.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2009/02/25/256600.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/256600.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/256600.html</trackback:ping><description><![CDATA[<p align="left">做软件产品设计时经常会涉及到原型设计，用纸笔画废纸，用Visio画废劲。而且今年产品要做大的调整与换代，原型设计更为棘手，决定花力气找一款得心应手的原型设计工具，而 <strong>&#8220;</strong> <a href="http://www.balsamiq.com/products/mockups"><strong>Balsamiq Mockups</strong></a> <strong>&#8221;</strong>让我眼前一亮！迫不急待，进行了一翻在线试用，呵！对于软件原型构造来说，可真是&#8220;随心所欲、信手拈来&#8221;，中肯的说比纸和笔更为方便。</p>
<p>附</p>
<p>网址： <a href="http://www.balsamiq.com/">http://www.balsamiq.com/</a>&nbsp;</p>
<p>在线演示地址： <a href="http://www.balsamiq.com/products/mockups">http://www.balsamiq.com/products/mockups</a></p>
<p>试用网址： <a href="http://www.balsamiq.com/demos/mockups/Mockups.html">http://www.balsamiq.com/demos/mockups/Mockups.html</a></p>
<p>整体截图：</p>
<p>&nbsp; <img height="280" alt="mockupstour.jpg" src="http://www.blogjava.net/images/blogjava_net/allen-zhe/mockupstour.jpg" width="341" border="0" /></img></p>
<p align="left">功能和亮点：</p>
<ol type="1">
    <li>操作方面：拖拽，控件分组，甚至元素之间的对齐都做得很到位；
    <li>预制了六十多个界面元素，从简单的输入框，下拉框，到经常用得到的导航条，日历，表格，到复杂的Tag Cloud，Cover Flow, 地图，WYSWYG的格式工具栏等，有了这些不用从头画起，其实比用白板都快；
    <li>界面元素的修改很简单，比如导航条的几个标签页的label，就是用逗号分隔的文字，下拉框的选项就是分行的文字；
    <li>使用xml语言来记录和保存界面元素和布局，从而使其能够快速的导入到你所需的任何一个项目中，或其他工具中。
    <li>可以将设计导出成PNG格式的图片；
    <li>随着使用的熟练，快捷键便派上用场，超过一半的元素均有快捷方式，这更有助于原型的快速构造，几乎几分钟便可实现一个满意的而复杂的原型设计；
    <li>跨平台，Balsamiq Mokups是用Flex和Air实现的，所以在Mac OS, Linux和Windows下都能使用；
    <li>不仅仅有桌面版本，还有能集成在Confluence，JIRA，和XWiki中的版本，使得异地在线协作更方便有效； </li>
</ol>
<p>&nbsp;&nbsp; <img height="403" alt="tour_controls.jpg" src="http://www.blogjava.net/images/blogjava_net/allen-zhe/tour_controls.jpg" width="760" border="0" /></img></p>
<p>&nbsp; <img height="439" alt="3179518234_47b7d81a11.jpg" src="http://www.blogjava.net/images/blogjava_net/allen-zhe/3179518234_47b7d81a11.jpg" width="500" border="0" /></img></p>
<br />
这么好的一款软件是不是免费的呢？当然不是，但是软件的作者有N多种方式让你得到free license 的方法。<br />
<br />
<br />
<p>To get a free license key, you can do one of the following:</p>
<ul class="inp">
    <li>If your company bought Mockups for Confluence, JIRA or XWiki, ask your IT admin for your company's license information and use it FREE of charge.
    <li>If you are a do-gooder of any sort (non-profit, charity, open-source contributor, you get the idea), <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#97;&#114;&#105;&#97;&#104;&#64;&#98;&#97;&#108;&#115;&#97;&#109;&#105;&#113;&#46;&#99;&#111;&#109;">email Mariah</a> with a short blurb and she'll send you a license, FREE of charge.
    <li>If you are a blogger / journalist / maven willing to write us up (honest reviews are the most useful to us) <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#97;&#114;&#105;&#97;&#104;&#64;&#98;&#97;&#108;&#115;&#97;&#109;&#105;&#113;&#46;&#99;&#111;&#109;">email Mariah</a> a short blurb with the link to your blog and she'll send you a license, FREE of charge, so that you can evaluate Mockups properly.
    <li>If you are willing to demo Mockups to an audience of at least 15 people (at a user group, a conference, a BarCamp), <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#97;&#114;&#105;&#97;&#104;&#64;&#98;&#97;&#108;&#115;&#97;&#109;&#105;&#113;&#46;&#99;&#111;&#109;">email Mariah</a> your info and she'll give you two licenses, one for you to keep and one to give away at the event, FREE of charge.
    <li>If you teach a high-school class, <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#97;&#114;&#105;&#97;&#104;&#64;&#98;&#97;&#108;&#115;&#97;&#109;&#105;&#113;&#46;&#99;&#111;&#109;">email Mariah</a> the name of your school and your class, plus the number of students in your class. Mariah will send you a license for all of them.
    <li><strong>A note to university students and professors:</strong> we currently do not offer free licenses to universities, but we'll be happy to offer you an additional 50% off any orders of 10 or more licenses. <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#97;&#114;&#105;&#97;&#104;&#64;&#98;&#97;&#108;&#115;&#97;&#109;&#105;&#113;&#46;&#99;&#111;&#109;">Let us know</a> if you're interested and we'll set up a discount code for you. </li>
</ul>
<br />
<br />
你做到以上的任何一条。你就可以得到免费的许可证了。<br />
嘿嘿，终于暴露目的了&#8230;&#8230; 不过这么好的软件，不推荐一下也实在说不过去。 <br />
<br /><img src ="http://www.blogjava.net/anwenhao/aggbug/256600.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2009-02-25 14:02 <a href="http://www.blogjava.net/anwenhao/archive/2009/02/25/256600.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RAIDb的理解</title><link>http://www.blogjava.net/anwenhao/archive/2008/12/10/245569.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Wed, 10 Dec 2008 13:35:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2008/12/10/245569.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/245569.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2008/12/10/245569.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/245569.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/245569.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-align: left" align="left"><span style="font-family: 宋体">RAIDb</span><span style="font-family: 宋体">的目标：</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">通过将多个廉价的数据库实例组合到一个数据库阵列，提供比单台数据库更好的性能和容错性。</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">隐藏分布式数据库的复杂性，提供给数据库客户端一个独立的数据库。</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">在RAIDb中，一个控制器在其他资源的前面。客户发送他们的请求到RAIDb控制器，这个控制器将他们分发给一组RDBMS后端。</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">有不同的RAIDb级别或数据分发方案可用，它提供不同的费用，性能，或者容错权衡。</span></p>
<p style="text-align: left" align="left"><strong><span style="font-family: 宋体">全分割(RAIDb-0)</span></strong></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">RAIDb-0 </span><span style="font-family: 宋体">分割数据库表到一个数据库后端节点集。</span></p>
<ul type="disc">
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">一个表本身不能再分割了。但是不同的表可以分布在不同的后端节点上。</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">RAIDb-0 </span><span style="font-family: 宋体">需要至少两个数据库后端。</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">RAIDb-0 </span><span style="font-family: 宋体">当前只能和一个控制器配置一起使用。</span></li>
    <li style="color: red; text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">RAIDb-0 </span><span style="font-family: 宋体">提供了一定的性能扩展，但不支持容错功能。</span></li>
</ul>
<p style="color: red; text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体"><img height="261" alt="" src="http://www.blogjava.net/images/blogjava_net/anwenhao/raidb-0.JPG" width="509" border="0" /></span></p>
<p style="text-align: left" align="left"><strong><span style="font-family: 宋体">注意：</span></strong></p>
<p style="text-align: left" align="left"><em><span style="color: red; font-family: 宋体">当前的实现不支持分布式join。也就是说如果你想在表t1和t2间进行join操作，你必须确保t1和t2在同一台机器上。</span></em></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">扩展性的提升取决于表的数目和各个表的负载情况：</span></p>
<ul type="disc">
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">如果你的数据库很大，没有单个节点有足够的容量存放整个数据库，那么RAIDb-0允许你把一个数据库分布存储到到一组节点上。</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">此外，每个数据库引擎处理一个小的数据集可以尽可能的提高缓存利用率，因为总是请求那几个表。</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">RAIDb-0</span><span style="font-family: 宋体">存储的使用率是最高的，因为没有重复的信息。</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">RAIDb-0</span><span style="font-family: 宋体">需要控制器知道那个表在哪台服务器上，以便把请求导向正确的节点。因为没有重复的表，一直一个后端会执行一个特定的请求。这些信息也可以静态配置到配置文件中，也可以从每个数据库中抓取其schema来动态构建。</span></li>
</ul>
<p style="text-align: left" align="left"><strong><span style="font-family: 宋体">全复制 (RAIDb-1)</span></strong></p>
<ul type="disc">
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">RAIDb-1 </span><span style="font-family: 宋体">在一组后端上提供了一个数据库的全镜像。</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">RAIDb-1 </span><span style="font-family: 宋体">需要至少两个后端节点，但是理论上后端的数量没有上限的限制。每个后端必须有足够的空间运行整个数据库。</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">RAIDb-1 </span><span style="font-family: 宋体">允许在集群配置中使用几个控制器来为关键系统获得高可用性。</span></li>
</ul>
<p style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体"><img height="252" alt="" src="http://www.blogjava.net/images/blogjava_net/anwenhao/raidb-1.JPG" width="527" border="0" /></span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">RAIDb-1</span><span style="font-family: 宋体">的扩展能力取决于控制器广播更新所有节点的能力。如果有大量后端数据库，使用复合RAIDb可以获得更好的扩展性。</span></p>
<p style="text-align: left" align="left"><span style="color: red; font-family: 宋体">RAIDb-1</span><span style="color: red; font-family: 宋体">提供了对读查询的加速，因为他们可以被均衡到所有后端上。另一方面，它对写操作没有加速（update,insert,delete请求），因为他们必须广播到所有节点。写操作在所有的后端并行执行。</span><span style="font-family: 宋体">所以，在写的角度来看，RAIDb-1可能比不上一个单独的节点，但是从读的角度来看，性能会随着后端节点的增加而线性增长。</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">RAIDb-1</span><span style="font-family: 宋体">有很好的容错性，因为系统即使只有一个后端可用时也可以保持工作。</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">不像RAIDb-0，RAIDb-1控制器不需要知道数据库的结构，因为所有的节点都有能力处理任何请求。然后，RAIDb-1提供了一个缓存，它需要数据库结构来维护缓存的一致性。</span></p>
<p style="text-align: left" align="left"><strong><span style="font-family: 宋体">部分复制 (RAIDb-2)</span></strong></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">RAIDb-2</span><span style="font-family: 宋体">可以看作是RAIDb-0 和 RAIDb-1权衡下的一个中庸的解决方案。它支持调整每个数据库表的部分复制程度，以获得一个做好的读写性能。</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">RAIDb-2:</span></p>
<ul type="disc">
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">要求至少三个数据库后端；</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">要求每个数据库表在至少两个后端上可用以解决单点故障问题。</span></li>
    <li style="text-align: left; tab-stops: list 36.0pt"><span style="font-family: 宋体">不要求任何一个节点可以运行整个数据库。</span></li>
</ul>
<p style="text-align: left" align="left"><span style="font-family: 宋体">下面是RAIDb-2的典型应用：<br />
</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体"><br />
<img height="251" alt="" src="http://www.blogjava.net/images/blogjava_net/anwenhao/raidb-2.JPG" width="504" border="0" /><br />
<br />
没有或者只有少数几个节点运行整个数据库，一组节点各自运行这数据库的一部分。</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">下图中的例子显示了RAIDb-2的部分复制，数据库包含3个表：x,y,和z.第一个后端包含整个数据库，但是其他节点都只包含一个或两个表。表x 和 y有3份拷贝,表z有两份拷贝。任一节点失败，仍然可以从其他的存活节点中找到数据。</span></p>
<p style="text-align: left" align="left"><span style="color: red; font-family: 宋体">RAIDb-2</span><span style="color: red; font-family: 宋体">对于异构数据库非常有用。一个已有的企业数据库使用商业数据库，但是要建立一个全拷贝无论是从存储上还是从增加许可的费用上来说，都太贵了。有了RAIDb-2就好办了，你可以增加几个小型开源数据库来各自运行整个数据库中的某些部分来代替整个数据库，这样也可以获得更好的容错性。</span></p>
<p style="text-align: left" align="left"><span style="font-family: 宋体">RAIDb-2</span><span style="font-family: 宋体">容错性没有RAIDb-1好，但是它有效的改善了写操作的效率。跟RAIDb-0类似，RAIDb-2也要求控制器知道所有数据库的结构，以便将请求定向到适当的节点。</span></p><img src ="http://www.blogjava.net/anwenhao/aggbug/245569.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2008-12-10 21:35 <a href="http://www.blogjava.net/anwenhao/archive/2008/12/10/245569.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入介绍什么是java虚拟机</title><link>http://www.blogjava.net/anwenhao/archive/2008/01/13/174972.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Sun, 13 Jan 2008 05:37:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2008/01/13/174972.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/174972.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2008/01/13/174972.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/174972.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/174972.html</trackback:ping><description><![CDATA[<p>&nbsp; </p>
<p><span style="font-family: 宋体">一、什么是</span><a href="http://java.chinaitlab.com/" target="_blank"><span style="color: windowtext; text-decoration: none; text-underline: none">Java</a></span><span style="font-family: 宋体">虚拟机</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当你谈到</span><a href="http://java.chinaitlab.com/" target="_blank"><span style="color: windowtext; text-decoration: none; text-underline: none">Java</a></span><span style="font-family: 宋体">虚拟机时，你可能是指：</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">、抽象的</span>Java<span style="font-family: 宋体">虚拟机规范</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">、一个具体的</span>Java<span style="font-family: 宋体">虚拟机实现</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">、一个运行的</span>Java<span style="font-family: 宋体">虚拟机实例</span><br />
<span style="font-family: 宋体">二、</span>Java<span style="font-family: 宋体">虚拟机的生命周期</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">一个运行中的</span>Java<span style="font-family: 宋体">虚拟机有着一个清晰的任务：执行</span>Java<span style="font-family: 宋体">程序。程序开始执行时他才运行，程序结束时他就停止。你在同一台机器上运行三个程序，就会有三个运行中的</span>Java<span style="font-family: 宋体">虚拟机。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机总是开始于一个</span>main()<span style="font-family: 宋体">方法，这个方法必须是公有、返回</span>void<span style="font-family: 宋体">、直接受一个字符串数组。在程序执行时，你必须给</span>Java<span style="font-family: 宋体">虚拟机指明这个包换</span>main()<span style="font-family: 宋体">方法的类名。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Main()<span style="font-family: 宋体">方法是程序的起点，他被执行的线程初始化为程序的初始线程。程序中其他的线程都由他来启动。</span>Java<span style="font-family: 宋体">中的线程分为两种：守护线程</span> <span style="font-family: 宋体">（</span>daemon<span style="font-family: 宋体">）和普通线程（</span>non-daemon<span style="font-family: 宋体">）。守护线程是</span>Java<span style="font-family: 宋体">虚拟机自己使用的线程，比如负责垃圾收集的线程就是一个守护线程。当然，你也可</span> <span style="font-family: 宋体">以把自己的程序设置为守护线程。包含</span>Main()<span style="font-family: 宋体">方法的初始线程不是守护线程。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">只要</span>Java<span style="font-family: 宋体">虚拟机中还有普通的线程在执行，</span>Java<span style="font-family: 宋体">虚拟机就不会停止。如果有足够的权限，你可以调用</span>exit()<span style="font-family: 宋体">方法终止程序。</span><br />
<span style="font-family: 宋体">三、</span>Java<span style="font-family: 宋体">虚拟机的体系结构</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">在</span>Java<span style="font-family: 宋体">虚拟机的规范中定义了一系列的子系统、内存区域、数据类型和使用指南。这些组件构成了</span>Java<span style="font-family: 宋体">虚拟机的内部结构，他们不仅仅为</span>Java<span style="font-family: 宋体">虚拟机的实现提供了清晰的内部结构，更是严格规定了</span>Java<span style="font-family: 宋体">虚拟机实现的外部行为。</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">每一个</span>Java<span style="font-family: 宋体">虚拟机都由一个类加载器子系统（</span>class loader subsystem<span style="font-family: 宋体">），负责加载程序中的类型（类和接口），并赋予唯一的名字。每一个</span>Java<span style="font-family: 宋体">虚拟机都有一个执行引擎（</span>execution engine<span style="font-family: 宋体">）负责执行被加载类中包含的指令。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">程序的执行需要一定的内存空间，如字节码、被加载类的其他额外信息、程序中的对象、方法的参数、返回值、本地变量、处理的中间变量等等。</span>Java<span style="font-family: 宋体">虚拟机将</span> <span style="font-family: 宋体">这些信息统统保存在数据区（</span>data areas<span style="font-family: 宋体">）中。虽然每个</span>Java<span style="font-family: 宋体">虚拟机的实现中都包含数据区，但是</span>Java<span style="font-family: 宋体">虚拟机规范对数据区的规定却非常的抽象。许多结构上的细节部分都留给了</span> Java<span style="font-family: 宋体">虚拟机实现者自己发挥。不同</span>Java<span style="font-family: 宋体">虚拟机实现上的内存结构千差万别。一部分实现可能占用很多内存，而其他以下可能只占用很少的内存；一些实现可</span> <span style="font-family: 宋体">能会使用虚拟内存，而其他的则不使用。这种比较精炼的</span>Java<span style="font-family: 宋体">虚拟机内存规约，可以使得</span>Java<span style="font-family: 宋体">虚拟机可以在广泛的平台上被实现。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">数据区中的一部分是整个程序共有，其他部分被单独的线程控制。每一个</span>Java<span style="font-family: 宋体">虚拟机都包含方法区（</span>method area<span style="font-family: 宋体">）和堆（</span>heap<span style="font-family: 宋体">），他们都被整个程序共享。</span>Java<span style="font-family: 宋体">虚拟机加载并解析一个类以后，将从类文件中解析出来的信息保存与方法区中。程序执行时创建的</span> <span style="font-family: 宋体">对象都保存在堆中。</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当一个线程被创建时，会被分配只属于他自己的</span>PC<span style="font-family: 宋体">寄存器</span>&#8220;pc register&#8221;<span style="font-family: 宋体">（程序计数器）和</span>Java<span style="font-family: 宋体">堆栈（</span>Java stack<span style="font-family: 宋体">）。当线程不掉用本地方法时，</span>PC<span style="font-family: 宋体">寄存器中保存线程执行的下一条指令。</span>Java<span style="font-family: 宋体">堆栈保存了一个线程调用方法时的状态，包括本地变量、调用方法的</span> <span style="font-family: 宋体">参数、返回值、处理的中间变量。调用本地方法时的状态保存在本地方法堆栈中（</span>native method stacks<span style="font-family: 宋体">），可能再寄存器或者其他非平台独立的内存中。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">堆栈有堆栈块（</span>stack frames (or frames)<span style="font-family: 宋体">）组成。堆栈块包含</span>Java<span style="font-family: 宋体">方法调用的状态。当一个线程调用一个方法时，</span>Java<span style="font-family: 宋体">虚拟机会将一个新的块压到</span>Java<span style="font-family: 宋体">堆栈中，当这个方法运行结束时，</span>Java<span style="font-family: 宋体">虚拟机会将对应的块弹出并抛弃。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机不使用寄存器保存计算的中间结果，而是用</span>Java<span style="font-family: 宋体">堆栈在存放中间结果。这是的</span>Java<span style="font-family: 宋体">虚拟机的指令更紧凑，也更容易在一个没有寄存器的设备上实现</span>Java<span style="font-family: 宋体">虚拟机。</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">图中的</span>Java<span style="font-family: 宋体">堆栈中向下增长的，</span>PC<span style="font-family: 宋体">寄存器中线程三为灰色，是因为它正在执行本地方法，他的下一条执行指令不保存在</span>PC<span style="font-family: 宋体">寄存器中。</span><br />
<span style="font-family: 宋体">四、数据类型（</span>Data Types<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">所有</span>Java<span style="font-family: 宋体">虚拟机中使用的数据都有确定的数据类型，数据类型和操作都在</span>Java<span style="font-family: 宋体">虚拟机规范中严格定义。</span>Java<span style="font-family: 宋体">中的数据类型分为原始数据类型</span> <span style="font-family: 宋体">（</span>primitive types<span style="font-family: 宋体">）和引用数据类型（</span>reference type<span style="font-family: 宋体">）。引用类型依赖于实际的对象，但不是对象本身。原始数据类型不依赖于任何东西，他们就是本身表示的数据。</span><br />
<span style="font-family: 宋体">所有</span>Java<span style="font-family: 宋体">程序语言中的原始</span> <span style="font-family: 宋体">数据类型，都是</span>Java<span style="font-family: 宋体">虚拟机的原始数据类型，除了布尔型（</span>boolean<span style="font-family: 宋体">）。当编译器将</span>Java<span style="font-family: 宋体">源代码编译为自己码时，使用整型（</span>int<span style="font-family: 宋体">）或者字节型</span> <span style="font-family: 宋体">（</span>byte<span style="font-family: 宋体">）去表示布尔型。在</span>Java<span style="font-family: 宋体">虚拟机中使用整数</span>0<span style="font-family: 宋体">表示布尔型的</span>false<span style="font-family: 宋体">，使用非零整数表示布尔型的</span>true<span style="font-family: 宋体">，布尔数组被表示为字节数组，虽然他</span> <span style="font-family: 宋体">们可能会以字节数组或者字节块（</span>bit fields<span style="font-family: 宋体">）保存在堆中。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">除了布尔型，其他</span>Java<span style="font-family: 宋体">语言中的原始类型都是</span>Java<span style="font-family: 宋体">虚拟机中的数据类型。在</span>Java<span style="font-family: 宋体">中数据类型被分为：整形的</span>byte<span style="font-family: 宋体">，</span>short<span style="font-family: 宋体">，</span>int<span style="font-family: 宋体">，</span>long<span style="font-family: 宋体">；</span>char<span style="font-family: 宋体">和浮点型的</span>float<span style="font-family: 宋体">，</span>double<span style="font-family: 宋体">。</span>Java<span style="font-family: 宋体">语言中的数据类型在任何主机上都有同样的范围。</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">在</span>Java<span style="font-family: 宋体">虚拟机中还存在一个</span>Java<span style="font-family: 宋体">语言中不能使用的原始数据类型返回值类型（</span>returnValue<span style="font-family: 宋体">）。这种类型被用来实现</span>Java<span style="font-family: 宋体">程序中的</span>&#8220;finally clauses&#8221;<span style="font-family: 宋体">，具体的参见</span>18<span style="font-family: 宋体">章的</span>&#8220;Finally Clauses&#8221;<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">引用类型可能被创建为：类类型（</span>class type<span style="font-family: 宋体">），接口类型（</span>interface type<span style="font-family: 宋体">），数组类型（</span>array type<span style="font-family: 宋体">）。他们都引用被动态创建的对象。当引用类型引用</span>null<span style="font-family: 宋体">时，说明没有引用任何对象。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机规范只定义了每一种数据类型表示的范围，没有定义在</span><a href="http://www.storworld.com/" target="_blank"><span style="color: windowtext; font-family: 宋体; text-decoration: none; text-underline: none">存储</a></span><span style="font-family: 宋体">时每种类型占用的空间。他们如何</span><a href="http://www.storworld.com/" target="_blank"><span style="color: windowtext; font-family: 宋体; text-decoration: none; text-underline: none">存储</a></span><span style="font-family: 宋体">由</span>Java<span style="font-family: 宋体">虚拟机的实现者自己决定。关于浮点型更多信息参见</span>14<span style="font-family: 宋体">章</span>&#8220;Floating Point Arithmetic&#8221;<span style="font-family: 宋体">。</span> </p>
<p>TypeRange<br />
byte8-bit signed two's complement integer (-27 to 27 - 1, inclusive)<br />
short16-bit signed two's complement integer (-215 to 215 - 1, inclusive)<br />
int32-bit signed two's complement integer (-231 to 231 - 1, inclusive)<br />
long64-bit signed two's complement integer (-263 to 263 - 1, inclusive)<br />
char16-bit unsigned Unicode character (0 to 216 - 1, inclusive)<br />
float32-bit IEEE 754 single-precision float<br />
double64-bit IEEE 754 double-precision float<br />
returnValueaddress of an opcode within the same method<br />
referencereference to an object on the heap, or null</p>
<p><span style="font-family: 宋体">五、字节长度</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机中最小的数据单元式字（</span>word<span style="font-family: 宋体">），其大小由</span>Java<span style="font-family: 宋体">虚拟机的实现者定义。但是一个字的大小必须足够容纳</span>byte<span style="font-family: 宋体">，</span>short<span style="font-family: 宋体">，</span>int<span style="font-family: 宋体">，</span> char<span style="font-family: 宋体">，</span>float<span style="font-family: 宋体">，</span>returnValue<span style="font-family: 宋体">，</span>reference<span style="font-family: 宋体">；两个字必须足够容纳</span>long<span style="font-family: 宋体">，</span>double<span style="font-family: 宋体">。所以虚拟机的实现者至少提供的字不能小</span> <span style="font-family: 宋体">于</span>31bits<span style="font-family: 宋体">的字，但是最好选择特定平台上最有效率的字长。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">在运行时，</span>Java<span style="font-family: 宋体">程序不能决定所运行机器的字长。字长也不会影响程序的行为，他只是在</span>Java<span style="font-family: 宋体">虚拟机中的一种表现方式。</span><br />
<span style="font-family: 宋体">六、类加载器子系统</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机中的类加载器分为两种：原始类加载器（</span>primordial class loader<span style="font-family: 宋体">）和类加载器对象（</span>class loader objects<span style="font-family: 宋体">）。原始类加载器是</span>Java<span style="font-family: 宋体">虚拟机实现的一部分，类加载器对象是运行中的程序的一部分。不同类加载器加载的类被不同的命名空间所分割。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">类加载器调用了许多</span>Java<span style="font-family: 宋体">虚拟机中其他的部分和</span>java.lang<span style="font-family: 宋体">包中的很多类。比如，类加载对象就是</span>java.lang.ClassLoader<span style="font-family: 宋体">子类</span> <span style="font-family: 宋体">的实例，</span>ClassLoader<span style="font-family: 宋体">类中的方法可以访问虚拟机中的类加载机制；每一个被</span>Java<span style="font-family: 宋体">虚拟机加载的类都会被表示为一个</span> java.lang.Class<span style="font-family: 宋体">类的实例。像其他对象一样，类加载器对象和</span>Class<span style="font-family: 宋体">对象都保存在堆中，被加载的信息被保存在方法区中。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">、加载、连接、初始化（</span>Loading, Linking and Initialization<span style="font-family: 宋体">）</span><br />
<span style="font-family: 宋体">类加载子系统不仅仅负责定位并加载类文件，他按照以下严格的步骤作了很多其他的事情：（具体的信息参见第七章的</span>&#8220;<span style="font-family: 宋体">类的生命周期</span>&#8221;<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">）、加载：寻找并导入指定类型（类和接口）的二进制信息</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">）、连接：进行验证、准备和解析</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">①</span><span style="font-family: 宋体">验证：确保导入类型的正确性</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">②</span><span style="font-family: 宋体">准备：为类型分配内存并初始化为默认值</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">③</span><span style="font-family: 宋体">解析：将字符引用解析为直接饮用</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">）、初始化：调用</span>Java<span style="font-family: 宋体">代码，初始化类变量为合适的值</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">、原始类加载器（</span>The Primordial Class Loader<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">每个</span>Java<span style="font-family: 宋体">虚拟机都必须实现一个原始类加载器，他能够加载那些遵守类文件格式并且被信任的类。但是，</span>Java<span style="font-family: 宋体">虚拟机的规范并没有定义如何加载类，这由</span> Java<span style="font-family: 宋体">虚拟机实现者自己决定。对于给定类型名的类型，原始莱加载器必须找到那个类型名加</span>&#8220;.class&#8221;<span style="font-family: 宋体">的文件并加载入虚拟机中。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">、类加载器对象</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">虽然类加载器对象是</span>Java<span style="font-family: 宋体">程序的一部分，但是</span>ClassLoader<span style="font-family: 宋体">类中的三个方法可以访问</span>Java<span style="font-family: 宋体">虚拟机中的类加载子系统。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">）、</span>protected final Class defineClass(&#8230;)<span style="font-family: 宋体">：使用这个方法可以出入一个字节数组，定义一个新的类型。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">）、</span>protected Class findSystemClass(String name)<span style="font-family: 宋体">：加载指定的类，如果已经加载，就直接返回。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">）、</span>protected final void resolveClass(Class c)<span style="font-family: 宋体">：</span>defineClass()<span style="font-family: 宋体">方法只是加载一个类，这个方法负责后续的动态连接和初始化。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">具体的信息，参见第八章</span>&#8220;<span style="font-family: 宋体">连接模型</span>&#8221;<span style="font-family: 宋体">（</span> The Linking Model<span style="font-family: 宋体">）。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 4<span style="font-family: 宋体">、命名空间</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当多个类加载器加载了同一个类时，为了保证他们名字的唯一性，需要在类名前加上加载该类的类加载器的标识。具体的信息，参见第八章</span>&#8220;<span style="font-family: 宋体">连接模型</span>&#8221;<span style="font-family: 宋体">（</span> The Linking Model<span style="font-family: 宋体">）。</span><br />
<span style="font-family: 宋体">七、方法区（</span>The Method Area<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">在</span>Java<span style="font-family: 宋体">虚拟机中，被加载类型的信息都保存在方法区中。这写信息在内存中的组织形式由虚拟机的实现者定义，比如，虚拟机工作在一个</span>&#8220;little- endian&#8221;<span style="font-family: 宋体">的处理器上，他就可以将信息保存为</span>&#8220;little-endian&#8221;<span style="font-family: 宋体">格式的，虽然在</span>Java<span style="font-family: 宋体">类文件中他们是以</span>&#8220;big-endian&#8221;<span style="font-family: 宋体">格式保</span> <span style="font-family: 宋体">存的。设计者可以用最适合并地机器的表示格式来存储数据，以保证程序能够以最快的速度执行。但是，在一个只有很小内存的设备上，虚拟机的实现者就不会占用</span> <span style="font-family: 宋体">很大的内存。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">程序中的所有线程共享一个方法区，所以访问方法区信息的方法必须是线程</span><a href="http://security.chinaitlab.com/" target="_blank"><span style="color: windowtext; font-family: 宋体; text-decoration: none; text-underline: none">安全</a></span><span style="font-family: 宋体">的。如果你有两个线程都去加载一个叫</span>Lava<span style="font-family: 宋体">的类，那只能由一个线程被容许去加载这个类，另一个必须等待。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">在程序运行时，方法区的大小是可变的，程序在运行时可以扩展。有些</span>Java<span style="font-family: 宋体">虚拟机的实现也可以通过参数也订制方法区的初始大小，最小值和最大值。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">方法区也可以被垃圾收集。因为程序中的内由类加载器动态加载，所有类可能变成没有被引用（</span>unreferenced<span style="font-family: 宋体">）的状态。当类变成这种状态时，他就可</span> <span style="font-family: 宋体">能被垃圾收集掉。没有加载的类包括两种状态，一种是真正的没有加载，另一个种是</span>&#8220;unreferenced&#8221;<span style="font-family: 宋体">的状态。详细信息参见第七章的类的生命周期</span> <span style="font-family: 宋体">（</span>The Lifetime of a Class<span style="font-family: 宋体">）。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">、类型信息（</span>Type Information<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">每一个被加载的类型，在</span>Java<span style="font-family: 宋体">虚拟机中都会在方法区中保存如下信息：</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">）、类型的全名（</span>The fully qualified name of the type<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">）、类型的父类型的全名（除非没有父类型，或者弗雷形式</span>java.lang.Object<span style="font-family: 宋体">）（</span>The fully qualified name of the type&#237;s direct superclass<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">）、给类型是一个类还是接口（</span>class or an interface<span style="font-family: 宋体">）（</span>Whether or not the type is a class <span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4<span style="font-family: 宋体">）、类型的修饰符（</span>public<span style="font-family: 宋体">，</span>private<span style="font-family: 宋体">，</span>protected<span style="font-family: 宋体">，</span>static<span style="font-family: 宋体">，</span>final<span style="font-family: 宋体">，</span>volatile<span style="font-family: 宋体">，</span>transient<span style="font-family: 宋体">等）（</span>The type&#237;s modifiers<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5<span style="font-family: 宋体">）、所有父接口全名的列表（</span>An ordered list of the fully qualified names of any direct superinterfaces<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">类型全名保存的数据结构由虚拟机实现者定义。除此之外，</span>Java<span style="font-family: 宋体">虚拟机还要为每个类型保存如下信息：</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">）、类型的常量池（</span>The constant pool for the type<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">）、类型字段的信息（</span>Field information<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">）、类型方法的信息（</span>Method information<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4<span style="font-family: 宋体">）、所有的静态类变量（非常量）信息（</span>All class (static) variables declared in the type, except constants<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5<span style="font-family: 宋体">）、一个指向类加载器的引用（</span>A reference to class ClassLoader<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6<span style="font-family: 宋体">）、一个指向</span>Class<span style="font-family: 宋体">类的引用（</span>A reference to class Class<span style="font-family: 宋体">）</span></p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">）、类型的常量池（</span>The constant pool for the type<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">常量池中保存中所有类型是用的有序的常量集合，包含直接常量（</span>literals<span style="font-family: 宋体">）如字符串、整数、浮点数的常量，和对类型、字段、方法的符号引用。常量池</span> <span style="font-family: 宋体">中每一个保存的常量都有一个索引，就像数组中的字段一样。因为常量池中保存中所有类型使用到的类型、字段、方法的字符引用，所以它也是动态连接的主要对</span> <span style="font-family: 宋体">象。详细信息参见第六章</span>&#8220;The Java Class File&#8221;<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">）、类型字段的信息（</span>Field information<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">字段名、字段类型、字段的修饰符（</span>public<span style="font-family: 宋体">，</span>private<span style="font-family: 宋体">，</span>protected<span style="font-family: 宋体">，</span>static<span style="font-family: 宋体">，</span>final<span style="font-family: 宋体">，</span>volatile<span style="font-family: 宋体">，</span>transient<span style="font-family: 宋体">等）、字段在类中定义的顺序。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">）、类型方法的信息（</span>Method information<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">方法名、方法的返回值类型（或者是</span>void<span style="font-family: 宋体">）、方法参数的个数、类型和他们的顺序、字段的修饰符（</span>public<span style="font-family: 宋体">，</span>private<span style="font-family: 宋体">，</span>protected<span style="font-family: 宋体">，</span>static<span style="font-family: 宋体">，</span>final<span style="font-family: 宋体">，</span>volatile<span style="font-family: 宋体">，</span>transient<span style="font-family: 宋体">等）、方法在类中定义的顺序</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">如果不是抽象和本地本法还需要保存</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">方法的字节码、方法的操作数堆栈的大小和本地变量区的大小（稍候有详细信息）、异常列表（详细信息参见第十七章</span>&#8220;Exceptions&#8221;<span style="font-family: 宋体">。）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4<span style="font-family: 宋体">）、类（静态）变量（</span>Class Variables<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">类变量被所有类的实例共享，即使不通过类的实例也可以访问。这些变量绑定在类上（而不是类的实例上），所以他们是类的逻辑数据的一部分。在</span>Java<span style="font-family: 宋体">虚拟机使用这个类之前就需要为类变量（</span>non-final<span style="font-family: 宋体">）分配内存</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">常量（</span>final<span style="font-family: 宋体">）的处理方式于这种类变量（</span>non-final<span style="font-family: 宋体">）不一样。每一个类型在用到一个常量的时候，都会复制一份到自己的常量池中。常量也像类变</span> <span style="font-family: 宋体">量一样保存在方法区中，只不过他保存在常量池中。（可能是，类变量被所有实例共享，而常量池是每个实例独有的）。</span>Non-final<span style="font-family: 宋体">类变量保存为定义他的</span> <span style="font-family: 宋体">类型数据（</span>data for the type that declares them<span style="font-family: 宋体">）的一部分，而</span>final<span style="font-family: 宋体">常量保存为使用他的类型数据（</span>data for any type that uses them<span style="font-family: 宋体">）的一部分。详情参见第六章</span>&#8220;The Java Class FileThe Java Class File&#8221;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5<span style="font-family: 宋体">）、指向类加载器的引用（</span>A reference to class ClassLoader<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">每一个被</span>Java<span style="font-family: 宋体">虚拟机加载的类型，虚拟机必须保存这个类型是否由原始类加载器或者类加载器加载。那些被类加载器加载的类型必须保存一个指向类加载器的引</span> <span style="font-family: 宋体">用。当类加载器动态连接时，会使用这条信息。当一个类引用另一个类时，虚拟机必须保存那个被引用的类型是被同一个类加载器加载的，这也是虚拟机维护不同命</span> <span style="font-family: 宋体">名空间的过程。详情参见第八章</span>&#8220;The Linking Model&#8221;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6<span style="font-family: 宋体">）、指向</span>Class<span style="font-family: 宋体">类的引用（</span>A reference to class Class<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机为每一个加载的类型创建一个</span>java.lang.Class<span style="font-family: 宋体">类的实例。你也可以通过</span>Class<span style="font-family: 宋体">类的方法：</span><br />
public static Class forName(String className)<span style="font-family: 宋体">来查找或者加载一个类，并取得相应的</span>Class<span style="font-family: 宋体">类的实例。通过这个</span>Class<span style="font-family: 宋体">类的实例，我们可以访问</span>Java<span style="font-family: 宋体">虚拟机方法区中的信息。具体参照</span>Class<span style="font-family: 宋体">类的</span>JavaDoc<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">、方法列表（</span>Method Tables<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">为了更有效的访问所有保存在方法区中的数据，这些数据的存储结构必须经过仔细的设计。所有方法区中，除了保存了上边的那些原始信息外，还有一个为了加快存</span> <span style="font-family: 宋体">取速度而设计的数据结构，比如方法列表。每一个被加载的非抽象类，</span>Java<span style="font-family: 宋体">虚拟机都会为他们产生一个方法列表，这个列表中保存了这个类可能调用的所有实例</span> <span style="font-family: 宋体">方法的引用，报错那些父类中调用的方法。详情参见第八章</span>&#8220;The Linking Model&#8221;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong><span style="font-family: 宋体">八、堆</span></strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当</span>Java<span style="font-family: 宋体">程序创建一个类的实例或者数组时，都在堆中为新的对象分配内存。虚拟机中只有一个堆，所有的线程都共享他。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">、垃圾收集（</span>Garbage Collection<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">垃圾收集是释放没有被引用的对象的主要方法。它也可能会为了减少堆的碎片，而移动对象。在</span>Java<span style="font-family: 宋体">虚拟机的规范中没有严格定义垃圾收集，只是定义一个</span>Java<span style="font-family: 宋体">虚拟机的实现必须通过某种方式管理自己的堆。详情参见第九章</span>&#8220;Garbage Collection&#8221;<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">、对象存储结构（</span>Object Representation<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机的规范中没有定义对象怎样在堆中存储。每一个对象主要存储的是他的类和父类中定义的对象变量。对于给定的对象的引用，虚拟机必须嫩耨很快的</span> <span style="font-family: 宋体">定位到这个对象的数据。另为，必须提供一种通过对象的引用方法对象数据的方法，比如方法区中的对象的引用，所以一个对象保存的数据中往往含有一个某种形式</span> <span style="font-family: 宋体">指向方法区的指针。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">一个可能的堆的设计是将堆分为两个部分：引用池和对象池。一个对象的引用就是指向引用池的本地指针。每一个引用池中的条目都包含两个部分：指向对象池中对</span> <span style="font-family: 宋体">象数据的指针和方法区中对象类数据的指针。这种设计能够方便</span>Java<span style="font-family: 宋体">虚拟机堆碎片的整理。当虚拟机在对象池中移动一个对象的时候，只需要修改对应引用池中</span> <span style="font-family: 宋体">的指针地址。但是每次访问对象的数据都需要处理两次指针。下图演示了这种堆的设计。在第九章的</span>&#8220;<span style="font-family: 宋体">垃圾收集</span>&#8221;<span style="font-family: 宋体">中的</span>HeapOfFish Applet<span style="font-family: 宋体">演示了这种设计。</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">另一种堆的设计是：一个对象的引用就是一个指向一堆数据和指向相应对象的偏移指针。这种设计方便了对象的访问，可是对象的移动要变的异常复杂。下图演示了这种设计</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当程序试图将一个对象转换为另一种类型时，虚拟机需要判断这种转换是否是这个对象的类型，或者是他的父类型。当程序适用</span>instanceof<span style="font-family: 宋体">语句的时候也</span> <span style="font-family: 宋体">会做类似的事情。当程序调用一个对象的方法时，虚拟机需要进行动态绑定，他必须判断调用哪一个类型的方法。这也需要做上面的判断。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">无论虚拟机实现者使用哪一种设计，他都可能为每一个对象保存一个类似方法列表的信息。因为他可以提升对象方法调用的速度，对提升虚拟机的性能非常重要，但</span> <span style="font-family: 宋体">是虚拟机的规范中比没有要求必须实现类似的数据结构。下图描述了这种结构。图中显示了一个对象引用相关联的所有的数据结构，包括：</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">）、一个指向类型数据的指针</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">）、一个对象的方法列表。方法列表是一个指向所有可能被调用对象方法的指针数组。方法数据包括三个部分：操作码堆栈的大小和方法堆栈的本地变量区；方法的字节码；异常列表。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">每一个</span>Java<span style="font-family: 宋体">虚拟机中的对象必须关联一个用于同步多线程的</span>lock(mutex)<span style="font-family: 宋体">。同一时刻，只能有一个对象拥有这个对象的锁。当一个拥有这个这个对象</span> <span style="font-family: 宋体">的锁，他就可以多次申请这个锁，但是也必须释放相应次数的锁才能真正释放这个对象锁。很多对象在整个生命周期中都不会被锁，所以这个信息只有在需要时才需</span> <span style="font-family: 宋体">要添加。很多</span>Java<span style="font-family: 宋体">虚拟机的实现都没有在对象的数据中包含</span>&#8220;<span style="font-family: 宋体">锁定数据</span>&#8221;<span style="font-family: 宋体">，只是在需要时才生成相应的数据。除了实现对象的锁定，每一个对象还逻辑关联到一</span> <span style="font-family: 宋体">个</span>&#8220;wait set&#8221;<span style="font-family: 宋体">的实现。锁定帮组线程独立处理共享的数据，不需要妨碍其他的线程。</span>&#8220;wait set&#8221;<span style="font-family: 宋体">帮组线程协作完成同一个目标。</span>&#8220;wait set&#8221;<span style="font-family: 宋体">往往通过</span>Object<span style="font-family: 宋体">类的</span>wait()<span style="font-family: 宋体">和</span>notify()<span style="font-family: 宋体">方法来实现。</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">垃圾收集也需要堆中的对象是否被关联的信息。</span>Java<span style="font-family: 宋体">虚拟机规范中指出垃圾收集一个运行一个对象的</span>finalizer<span style="font-family: 宋体">方法一次，但是容许</span> finalizer<span style="font-family: 宋体">方法重新引用这个对象，当这个对象再次不被引用时，就不需要再次调用</span>finalize<span style="font-family: 宋体">方法。所以虚拟机也需要保存</span>finalize<span style="font-family: 宋体">方法</span> <span style="font-family: 宋体">是否运行过的信息。更多信息参见第九章的</span>&#8220;<span style="font-family: 宋体">垃圾收集</span>&#8221;<br />
&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">、数组的保存（</span>Array Representation<span style="font-family: 宋体">）</span><br />
<span style="font-family: 宋体">在</span>Java <span style="font-family: 宋体">中，数组是一种完全意义上的对象，他和对象一样保存在堆中、有一个指向</span>Class<span style="font-family: 宋体">类实例的引用。所有同一维度和类型的数组拥有同样的</span>Class<span style="font-family: 宋体">，数组的长</span> <span style="font-family: 宋体">度不做考虑。对应</span>Class<span style="font-family: 宋体">的名字表示为维度和类型。比如一个整型数据的</span>Class<span style="font-family: 宋体">为</span>&#8220;[I&#8221;<span style="font-family: 宋体">，字节型三维数组</span>Class<span style="font-family: 宋体">名为</span>&#8220;[[[B&#8221;<span style="font-family: 宋体">，两维对象数据</span> Class<span style="font-family: 宋体">名为</span>&#8220;[[Ljava.lang.Object&#8221;<span style="font-family: 宋体">。</span><br />
<span style="font-family: 宋体">多维数组被表示为数组的数组，如下图：</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">数组必须在堆中保存数组的长度，数组的数据和一些对象数组类型数据的引用。通过一个数组引用的，虚拟机应该能够取得一个数组的长度，通过索引能够访问特定</span> <span style="font-family: 宋体">的数据，能够调用</span>Object<span style="font-family: 宋体">定义的方法。</span>Object<span style="font-family: 宋体">是所有数据类的直接父类。更多信息参见第六章</span>&#8220;<span style="font-family: 宋体">类文件</span>&#8221;<span style="font-family: 宋体">。</span><br />
<strong><span style="font-family: 宋体">九、</span></strong><strong><span style="font-family: 'Calibri','sans-serif'">PC</span></strong><strong><span style="font-family: 宋体">寄存器（程序计数器）（</span></strong><strong><span style="font-family: 'Calibri','sans-serif'">The Program Counter</span></strong><strong><span style="font-family: 宋体">）</span></strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">每一个线程开始执行时都会被创建一个程序计数器。程序计数器只有一个字长（</span>word<span style="font-family: 宋体">），所以它能够保存一个本地指针和</span>returnValue<span style="font-family: 宋体">。当线程执行</span> <span style="font-family: 宋体">时，程序计数器中存放了正在执行指令的地址，这个地址可以使一个本地指针，也可以使一个从方法字节码开始的偏移指针。如果执行本地方法，程序计数器的值没</span> <span style="font-family: 宋体">有被定义。</span><br />
<strong><span style="font-family: 宋体">十、</span></strong><strong><span style="font-family: 'Calibri','sans-serif'">Java</span></strong><strong><span style="font-family: 宋体">堆栈（</span></strong><strong><span style="font-family: 'Calibri','sans-serif'">The Java Stack</span></strong><strong><span style="font-family: 宋体">）</span></strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当一个线程启动时，</span>Java<span style="font-family: 宋体">虚拟机会为他创建一个</span>Java<span style="font-family: 宋体">堆栈。</span>Java<span style="font-family: 宋体">堆栈用一些离散的</span>frame<span style="font-family: 宋体">类纪录线程的状态。</span>Java<span style="font-family: 宋体">虚拟机堆</span>Java<span style="font-family: 宋体">堆栈的操作只有两种：压入和弹出</span>frames<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">线程中正在执行的方法被称为当前方法（</span>current method<span style="font-family: 宋体">），当前方法所对应的</span>frame<span style="font-family: 宋体">被称为当前帧（</span>current frame<span style="font-family: 宋体">）。定义当前方法的类被称为当前类（</span>current class<span style="font-family: 宋体">），当前类的常量池被称为当前常量池（</span>current constant pool.<span style="font-family: 宋体">）。当线程执行时，</span>Java<span style="font-family: 宋体">虚拟机会跟踪当前类和当前常量池。但线程操作保存在帧中的数据时，他只操作当前帧的数据。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当线程调用一个方法时，虚拟机会生成一个新的帧，并压入线程的</span>Java<span style="font-family: 宋体">堆栈。这个新的帧变成当前帧。当方法执行时，他使用当前帧保存方法的参数、本地变</span> <span style="font-family: 宋体">量、中间结构和其他数据。方法有两种退出方式：正常退出和异常推出。无论方法以哪一种方式推出，</span>Java<span style="font-family: 宋体">虚拟机都会弹出并丢弃方法的帧，上一个方法的帧变</span> <span style="font-family: 宋体">为当前帧。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">所有保存在帧中的数据都只能被拥有它的线程访问，线程不能访问其他线程的堆栈中的数据。所以，访问方法的本地变量时，不需要考虑多线程同步。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">和方法区、堆一样，</span>Java<span style="font-family: 宋体">堆栈不需要连续的内存空间，它可以被保存在一个分散的内存空间或者堆上。堆栈具体的数据和长度都有</span>Java<span style="font-family: 宋体">虚拟机的实现者自己定义。一些实现可能提供了执行堆栈最大值和最小值的方法。</span><br />
<strong><span style="font-family: 宋体">十一、堆栈帧（</span></strong><strong><span style="font-family: 'Calibri','sans-serif'">The Stack Frame</span></strong><strong><span style="font-family: 宋体">）</span></strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">堆栈帧包含三部分：本地变量、操作数堆栈和帧数据。本地变量和操作数堆栈的大小都是一字（</span>word<span style="font-family: 宋体">）为单位的，他们在编译就已经确定。帧数据的大小取决于</span> <span style="font-family: 宋体">不同的实现。当程序调用一个方法时，虚拟机从类数据中取得本地变量和操作数堆栈的大小，创建一个合适大小和帧，然后压入</span>Java<span style="font-family: 宋体">堆栈中。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">、本地变量（</span>Local Variables<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">本地变量在</span>Java<span style="font-family: 宋体">堆栈帧中被组织为一个从</span>0<span style="font-family: 宋体">计数的数组，指令通过提供他们的索引从本地变量区中取得相应的值。</span>Int,float,reference, returnValue<span style="font-family: 宋体">占一个字，</span>byte,short,char<span style="font-family: 宋体">被转换成</span>int<span style="font-family: 宋体">然后存储，</span>long<span style="font-family: 宋体">和</span>doubel<span style="font-family: 宋体">占两个字。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">指令通过提供两个字索引中的前一个来取得</span>long,doubel<span style="font-family: 宋体">的值。比如一个</span>long<span style="font-family: 宋体">的值存储在索引</span>3<span style="font-family: 宋体">，</span>4<span style="font-family: 宋体">上，指令就可以通过</span>3<span style="font-family: 宋体">来取得这个</span>long<span style="font-family: 宋体">类型的值。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">本地变量区中包含了方法的参数和本地变量。编译器将方法的参数以他们申明的顺序放在数组的前面。但是编译器却可以将本地变量任意排列在本地变量数组中，甚至两个本地变量可以公用一个地址，比如，当两个本地变量在两个不交叠的区域内，就像循环变量</span>i,j<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">虚拟机的实现者可以使用任何结构来描述本地变量区中的数据，虚拟机规范中没有定义如何存储</span>long<span style="font-family: 宋体">和</span>doubel<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">、操作数堆栈（</span>Operand Stack<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">向本地变量一样，操作数堆栈也被组织为一个以字为单位的数组。但是不像本地变量那样通过索引访问，而是通过</span>push<span style="font-family: 宋体">和</span>pop<span style="font-family: 宋体">值来实现访问的。如果一个指令</span>push<span style="font-family: 宋体">一个值到堆栈中，那么下一个指令就可以</span>pop<span style="font-family: 宋体">并且使用这个值。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">操作数堆栈不像程序计数器那样不可以被指令直接访问，指令可以直接访问操作数堆栈。</span>Java<span style="font-family: 宋体">虚拟机是一个以堆栈为基础，而不是以寄存器为基础的，因为它的</span> <span style="font-family: 宋体">指令从堆栈中取得操作数，而不是同寄存器中。当然，指令也可以从其他地方去的操作数，比如指令后面的操作码，或者常量池。但是</span>Java<span style="font-family: 宋体">虚拟机指令主要是从</span> <span style="font-family: 宋体">操作数堆栈中取得他们需要的操作数。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机将操作数堆栈视为工作区，很多指令通过先从操作数堆栈中</span>pop<span style="font-family: 宋体">值，在处理完以后再将结果</span>push<span style="font-family: 宋体">回操作数堆栈。一个</span>add<span style="font-family: 宋体">的指令执行过程如</span> <span style="font-family: 宋体">下图所示：先执行</span>iload_0<span style="font-family: 宋体">和</span>iload_1<span style="font-family: 宋体">两条指令将需要相加的两个数，从本地方法区中取出，并</span>push<span style="font-family: 宋体">到操作数堆栈中；然后执行</span>iadd<span style="font-family: 宋体">指令，现</span> pop<span style="font-family: 宋体">出两个值，相加，并将结果</span>pusp<span style="font-family: 宋体">进操作数堆栈中；最后执行</span>istore_2<span style="font-family: 宋体">指令，</span>pop<span style="font-family: 宋体">出结果，赋值到本地方法区中。</span>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">、帧数据（</span>Frame Data<span style="font-family: 宋体">）</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">处理本地变量和操作数堆栈以外，</span>java<span style="font-family: 宋体">堆栈帧还包括了为了支持常量池，方法返回值和异常分发需要的数据，他们被保存在帧数据中。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当虚拟机遇到使用指向常量池引用的指令时，就会通过帧数据中指向常量区的指针来访问所需要的信息。前面提到过，常量区中的引用在最开始时都是符号引用。即使当虚拟机检查这些引用时，他们也是字符引用。所以虚拟机需要在这时转换这个引用。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">当一个方法正常返回时，虚拟机需要重建那个调用这个方法的方法的堆栈帧。如果执行完的方法有返回值，虚拟机就需要将这个值</span>push<span style="font-family: 宋体">进调用方法的哪个操作数堆栈中。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">帧数据中也包含虚拟机用来处理异常的异常表的引用。异常表定义了一个被</span>catch<span style="font-family: 宋体">语句保护的一段字节码。每一个异常表中的个体又包含了需要保护的字节玛的</span> <span style="font-family: 宋体">范围，和异常被捕捉到时需要执行的字节码的位置。当一个方法抛出一个异常时，</span>Java<span style="font-family: 宋体">虚拟机就是用异常表去判断如何处理这个异常。如果虚拟机找到了一个匹</span> <span style="font-family: 宋体">配的</span>catch<span style="font-family: 宋体">，他就会将控制权交给</span>catch<span style="font-family: 宋体">语句。如果没有找到匹配的</span>catch<span style="font-family: 宋体">，方法就会异常返回，然后再调用的方法中继续这个过程。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">除了以上的三个用途外，帧数据还可能包含一些依赖于实现的数据，比如调试的信息。</span><br />
<strong><span style="font-family: 宋体">十二、本地方法堆栈</span></strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">本地方法区依赖于虚拟机的不同实现。虚拟机的实现者可以自己决定使用哪一种机制去执行本地方法。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">任何本地方法接口（</span>Native Method Interface<span style="font-family: 宋体">）都使用某种形式的本地方法堆栈。</span>&nbsp;<br />
<strong><span style="font-family: 宋体">十三、执行引擎</span></strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">一个</span>java<span style="font-family: 宋体">虚拟机实现的核心就是执行引擎。在</span>Java<span style="font-family: 宋体">虚拟机规范，执行引擎被描述为一系列的指令。对于每一个指令，规范都描述了他们应该做什么，但是没有说要如何去做。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">、指令集</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">在</span>Java<span style="font-family: 宋体">虚拟机中一个方法的字节码流就是一个指令的序列。每一个指令由一个字节的操作码（</span>Opcode<span style="font-family: 宋体">）和可能存在的操作数（</span>Operands<span style="font-family: 宋体">）。操作</span> <span style="font-family: 宋体">码指示去做什么，操作数提供一些执行这个操作码可能需要的额外的信息。一个抽象的执行引擎每次执行一个指令。这个过程发生在每一个执行的线程中。</span><br />
<span style="font-family: 宋体">有时，执行引擎可能会遇到一个需要调用本地方法的指令，在这种情况下，执行引擎会去试图调用本地方法，但本地方法返回时，执行引擎会继续执行字节码流中的下一个指令。本地方法也可以看成对</span>Java<span style="font-family: 宋体">虚拟机中的指令集的一种扩充。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">决定下一步执行那一条指令也是执行引擎工作的一部分。执行引擎有三种方法去取得下一条指令。多数指令会执行跟在他会面的指令；一些像</span>goto<span style="font-family: 宋体">，</span> return<span style="font-family: 宋体">的指令，会在他们执行的时候决定他们的下一条指令；当一个指令抛出异常时，执行引擎通过匹配</span>catch<span style="font-family: 宋体">语句来决定下一条应该执行的指令。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">平台独立性、网络移动性、</span><a href="http://security.chinaitlab.com/" target="_blank"><span style="color: windowtext; font-family: 宋体; text-decoration: none; text-underline: none">安全</a></span><span style="font-family: 宋体">性左右了</span>Java<span style="font-family: 宋体">虚拟机指令集的设计。平台独立性是指令集设计的主要影响因素之一。基于堆栈的结构使得</span>Java<span style="font-family: 宋体">虚拟机可以在</span> <span style="font-family: 宋体">更多的平台上实现。更小的操作码，紧凑的结构使得字节码可以更有效的利用网络带宽。一次性的字节码验证，使得字节码更安全，而不影响太多的性能。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">、执行技术</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">许多种执行技术可以用在</span>Java<span style="font-family: 宋体">虚拟机的实现中：解释执行，及时编译（</span>just-in-time compiling<span style="font-family: 宋体">），</span>hot-spot compiling,native execution in silicon<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 3<span style="font-family: 宋体">、线程</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机规范定义了一种为了在更多平台上实现的线程模型。</span>Java<span style="font-family: 宋体">线程模型的一个目标时可以利用本地线程。利用本地线程可以让</span>Java<span style="font-family: 宋体">程序中的线程能过在多处理器机器上真正的同时执行。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">线程模型的一个代价就是线程优先级，一个</span>Java<span style="font-family: 宋体">线程可以在</span>1-10<span style="font-family: 宋体">的优先级上运行。</span>1<span style="font-family: 宋体">最低，</span>10<span style="font-family: 宋体">最高。如果设计者使用了本地线程，他们可能将这</span> 10<span style="font-family: 宋体">个优先级映射到本地优先级上。</span>Java<span style="font-family: 宋体">虚拟机规范只定义了，高一点优先级的线程可以却一些</span>cpu<span style="font-family: 宋体">时间，低优先级的线程在所有高优先级线程都堵塞时，也</span> <span style="font-family: 宋体">可以获取一些</span>cpu<span style="font-family: 宋体">时间，但是这没有保证：低优先级的线程在高优先级线程没有堵塞时不可以获得一定的</span>cpu<span style="font-family: 宋体">时间。因此，如果需要在不同的线程间协作，你必</span> <span style="font-family: 宋体">须使用的</span>&#8220;<span style="font-family: 宋体">同步（</span>synchronizatoin<span style="font-family: 宋体">）</span>&#8221;<span style="font-family: 宋体">。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">同步意味着两个部分：对象锁（</span>object locking<span style="font-family: 宋体">）和线程等待、激活</span>(thread wait and notify)<span style="font-family: 宋体">。对象锁帮助线程可以不受其他线程的干扰。线程等待、激活可以让不同的线程进行协作。</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">在</span>Java<span style="font-family: 宋体">虚拟机的规范中，</span>Java<span style="font-family: 宋体">线程被描述为变量、主内存、工作内存。每一个</span>Java<span style="font-family: 宋体">虚拟机的实例都有一个主内存，他包含了所有程序的变量：对象、数组合类变量。每一个线程都有自己的工作内存，他保存了哪些他可能用到的变量的拷贝。规则：</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">）、从主内存拷贝变量的值到工作内存中</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">）、将工作内存中的值写会主内存中</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">如果一个变量没有被同步化，线程可能以任何顺序更新主内存中的变量。为了保证多线程程序的正确的执行，必须使用同步机制。</span><br />
<strong><span style="font-family: 宋体">十四、本地方法接口（</span></strong><strong><span style="font-family: 'Calibri','sans-serif'">Native Method Interface</span></strong><strong><span style="font-family: 宋体">）</span></strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; Java<span style="font-family: 宋体">虚拟机的实现并不是必须实现本地方法接口。一些实现可能根本不支持本地方法接口。</span>Sun<span style="font-family: 宋体">的本地方法接口是</span>JNI(Java Native Interface)<span style="font-family: 宋体">。</span><br />
<strong><span style="font-family: 宋体">十五、现实中的机器（</span></strong><strong><span style="font-family: 'Calibri','sans-serif'">The Real Machine</span></strong><strong><span style="font-family: 宋体">）</span></strong><br />
<strong><span style="font-family: 宋体">十六、数学方法：仿真</span></strong><strong><span style="font-family: 'Calibri','sans-serif'">(Eternal Math : A Simulation)</span></strong></p><img src ="http://www.blogjava.net/anwenhao/aggbug/174972.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2008-01-13 13:37 <a href="http://www.blogjava.net/anwenhao/archive/2008/01/13/174972.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DB2 LOAD 命令(转载)</title><link>http://www.blogjava.net/anwenhao/archive/2007/09/05/142912.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Wed, 05 Sep 2007 07:19:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2007/09/05/142912.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/142912.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2007/09/05/142912.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/142912.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/142912.html</trackback:ping><description><![CDATA[当 DB2 的数据库启用了前滚恢复模式，即将日志由循环日志方式改为归档日志，以便用户在进行恢复操作时，可在恢复了数据库或表空间的备份后，再通过前滚归档日志中的事务，恢复数据库备份时间点之后提交的事务，最大程度的保护数据库的数据。<br />
<br />
而 DB2 的 LOAD 实用程序为实现快速导入数据的功能，除采用了通过直接向数据库中写入格式化的数据页装载数据，导入过程中不激活触发器，不会检查参考完整性和表检查约束当等方式外，还最小化了记录事务日志的操作。在 LOAD 的 LOAD、BUILD、DELETE 和 INDEX COPY 四个处理阶段中，仅在 DELETE 阶段记录对每个删除事件记日志，即只对每个违反唯一约束的行的删除操作记日志，因此整个 LOAD 操作仅记录了极少的日志。<br />
<br />
由于 LOAD 最小化了日志的记录，有因启用了前滚恢复的数据库在恢复在线备份时需要归档日志的特性，对于这种数据库的 LOAD 操作，为避免执行 LOAD 操作后，表在使用 ROLLFORWARD 命令前滚归档日志的过程中因缺少日志而被置为非正常状态，DB2 为 LOAD 命令提供了如下选项：<br />
<br />
&#183;COPY NO（缺省）<br />
&#183;COPY YES<br />
&#183;NONREVERABLE<br />
<br />
为更清楚地说明这些选项的作用，这里将以举例的方式进行说明。而在开始操作之前，首先了解一下 DB2 备份操作所产生的映象文件的形式和命名特点：<br />
<br />
在 UNIX 环境下是文件的形式： <br />
Databasealias.Type.Instancename.Nodename.Catnodename.Timestamp.number<br />
<br />
在 Windows 环境下是子目录及文件的形式：<br />
Databasealias.Type\Instancename\Node0000\Catn0000\yyyymmdd\hhmmss.number<br />
<br />
而其中的 Type 则因备份类型的不同而不同：<br />
<br />
0 -- 数据库全备份<br />
3 -- 表空间备份<br />
4 -- 由 LOAD 操作产生的备份<br />
<br />
<br />
1. 进行一次数据库的全备份：<br />
<br />
首先对已启用前滚恢复模式的 SAMPLE 数据库进行一次全备份：<br />
<br />
E:\TEST&gt;db2 backup db sample<br />
备份成功。此备份映像的时间戳记是：20051230174105<br />
<br />
这时看到在当前目录下产生了一个 SAMPLE.0 的子目录，表明产生的是一个数据库全备份。下面将对这些现象逐个予以举例说明：<br />
<br />
<br />
2. 关于 COPY NO：<br />
<br />
在 LOAD 操作结束时，将表所在的表空间置于&#8220;备份暂挂&#8221;状态，此时虽然其中的表可以进行 SELECT 操作，但不能进行 UPDATE 和 DELETE 操作。为使该表状态恢复正常，除去备份暂挂状态，必须手动对其表空间执行一个 BACKUP 命令。由于该选项为缺省选项，如果 LOAD 命令中未指明，则默认为使用该选项，如：<br />
<br />
E:\TEST&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 load from staff.del of del insert into staff<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
<br />
：<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0020<br />
详细解释：<br />
备份暂挂<br />
：<br />
<br />
E:\TEST&gt;db2 select count(*) from staff<br />
1<br />
-----------<br />
70<br />
1 条记录已选择。<br />
<br />
E:\TEST&gt;db2 update staff set id=335 where id=340<br />
DB21034E 该命令被当作 SQL 语句来处理，因为它不是有效的&#8220;命令行处理器&#8221;命令。在 SQL 处理期间，它返回：<br />
SQL0290N 不允许存取表空间。 SQLSTATE=55039<br />
<br />
在手动对 USERSPACE1 表空间进行一次备份操作后，表空间状态将正常，再次尝试更新操作就会成功：<br />
<br />
E:\TEST&gt;db2 backup db sample tablespace (userspace1)<br />
备份成功。此备份映像的时间戳记是：20051230184841 <br />
<br />
命令完成后可以在当前目录下看到产生了一个 SAMPLE.3 的子目录，表明产生的是一个表空间级的备份。<br />
<br />
E:\TEST&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0000<br />
详细解释：<br />
正常<br />
<br />
而所产生这份关于表空间的备份可在数据库因前滚操作将表空间置为&#8220;复原暂挂&#8221;状态时用于将表空间状态恢复为正常，并恢复 LOAD 操作对该表的修改。如当前滚数据库超过 LOAD 时间点后，表空间将被置为复原暂挂状态：<br />
<br />
E:\TEST&gt;db2 restore db sample taken at 20051230174105<br />
DB20000I RESTORE DATABASE 命令成功完成。<br />
<br />
E:\TEST&gt;db2 rollforward db sample to end of logs and stop<br />
SQL1271W 已恢复数据库 "SAMPLE"，但在节点 "0"上有一个或多个表空间脱机<br />
<br />
E:\TEST&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0100<br />
详细解释：<br />
复原暂挂<br />
<br />
此时可利用这一表空间级的备份进行恢复操作：<br />
<br />
E:\TEST&gt;db2 restore db sample tablespace (userspace1) taken at 20051230184841<br />
DB20000I RESTORE DATABASE 命令成功完成。<br />
<br />
E:\TEST&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
：<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0080<br />
详细解释：<br />
前滚暂挂<br />
：<br />
<br />
E:\TEST&gt;db2 rollforward db sample to end of logs and stop tablespace (userspace1)<br />
<br />
前滚状态<br />
<br />
输入数据库别名 = sample<br />
节点数已返回状态 = 1<br />
<br />
节点号 = 0<br />
前滚状态 = 未暂挂<br />
下一个要读取的日志文件 =<br />
已处理的日志文件 = -<br />
上次落实的事务 = 2005-12-30-10.47.10.000000<br />
<br />
DB20000I ROLLFORWARD 命令成功完成。<br />
<br />
E:\TEST&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
:<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0000<br />
详细解释：<br />
正常<br />
:<br />
<br />
E:\TEST&gt;db2 update staff set id=335 where id=340<br />
DB20000I SQL 命令成功完成。<br />
<br />
可见表空间状态已正常，表也可执行更新操作了。<br />
<br />
<br />
3. 关于 COPY YES：<br />
<br />
在 LOAD 操作结束时，DB2 自动对表所在的表空间进行一次备份操作，因而 LOAD 结束后，表所在的表空间不会再处于&#8220;备份暂挂&#8221;状态，而为&#8220;正常&#8221;状态。但由于要进行备份操作，所以这种 LOAD 操作的时间会较没有备份的长。如：<br />
<br />
E:\TEST&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 load from staff.del of del insert into staff copy yes to .<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
:<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0000<br />
详细解释：<br />
正常<br />
:<br />
<br />
E:\TEST&gt;db2 select count(*) from staff<br />
1<br />
-----------<br />
105<br />
1 条记录已选择。<br />
<br />
<br />
此时可在当前目录下看到一个 SAMPLE.4 的子目录，表明产生的是一个由 LOAD 操作生成的备份，而这份备份将在数据库进行前滚恢复操作时用于重新创建 LOAD 操作对数据库的修改。如：<br />
<br />
E:\TEST&gt;db2 restore db sample taken at 20051230174105<br />
DB20000I RESTORE DATABASE 命令成功完成。<br />
<br />
E:\TEST&gt;db2 rollforward db sample to end of logs and stop<br />
<br />
前滚状态<br />
<br />
输入数据库别名 = sample<br />
节点数已返回状态 = 1<br />
<br />
节点号 = 0<br />
前滚状态 = 未暂挂<br />
下一个要读取的日志文件 =<br />
已处理的日志文件 = S0000002.LOG - S0000003.LOG<br />
上次落实的事务 = 2005-12-30-11.48.26.000000<br />
<br />
DB20000I ROLLFORWARD 命令成功完成。<br />
<br />
E:\TEST&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
:<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0000<br />
详细解释：<br />
正常<br />
:<br />
<br />
E:\TEST&gt;db2 select count(*) from staff<br />
1<br />
-----------<br />
105<br />
1 条记录已选择。<br />
<br />
这表明在 SAMPLE.4 下的备份被用于了前滚恢复操作，而重新创建了 LOAD 操作对数据库插入的记录。<br />
<br />
<br />
4. 关于 NONRECOVERABLE：<br />
<br />
该选项会将 LOAD 操作标志为不可恢复，即数据库不能通过后续的前滚操作而被恢复。LOAD 操作结束后，数据库既不会处于&#8220;备份暂挂&#8221;状态，也不会产生任何的备份。<br />
<br />
E:\TEST&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 load from staff.del of del insert into staff nonrecoverable<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
:<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0000<br />
详细解释：<br />
正常<br />
:<br />
<br />
虽然 LOAD 之后表空间和表的状态都正常，但如果今后需要执行前滚命令恢复数据库时，前滚操作将跳过 LOAD 事务的处理，而将 LOAD 的表标记为无效，是对表的任何操作都不能进行。如：<br />
<br />
E:\TEST&gt;db2 restore db sample taken at 20051230174105<br />
DB20000I RESTORE DATABASE 命令成功完成。<br />
<br />
E:\TEST&gt;db2 rollforward db sample to end of logs and stop<br />
<br />
前滚状态<br />
<br />
输入数据库别名 = sample<br />
节点数已返回状态 = 1<br />
<br />
节点号 = 0<br />
前滚状态 = 未暂挂<br />
下一个要读取的日志文件 =<br />
已处理的日志文件 = S0000002.LOG - S0000003.LOG<br />
上次落实的事务 = 2005-12-30-12.19.55.000000<br />
<br />
DB20000I ROLLFORWARD 命令成功完成。<br />
<br />
E:\&gt;db2 connect to sample<br />
<br />
E:\TEST&gt;db2 list tablespaces<br />
:<br />
表空间标识 = 2<br />
名称 = USERSPACE1<br />
类型 = 系统管理空间<br />
内容 = 任何数据<br />
状态 = 0x0000<br />
详细解释：<br />
正常<br />
:<br />
<br />
E:\&gt;db2 select * from staff<br />
<br />
ID NAME DEPT JOB YEARS SALARY COMM<br />
------ --------- ------ ----- ------ --------- ---------<br />
SQL1477N 不能存取表 "LIWENLI.STAFF"。 SQLSTATE=55019<br />
<br />
这表明该表已不可操作，此时只有将表删除，重新构建，或使用 LOAD 操作时间点之后所做的数据库全备份或表空间备份来恢复该表。<br />
<br />
<br />
5. 关于注册表变量 DB2_LOAD_COPY_NO_OVERRIDE 的介绍：<br />
<br />
另外 DB2 还提供了一个注册表变量：DB2_LOAD_COPY_NO_OVERRIDE，可将 LOAD 的缺省选项 COPY NO 设置为 NONRECOVERABLE 或 COPY YES。具体使用方法举例为：<br />
<br />
设置为 COPY YES 的方法:<br />
<br />
E:\TEST&gt;db2set DB2_LOAD_COPY_NO_OVERRIDE="COPY YES TO E:\TEST"<br />
E:\TEST&gt;db2 terminate<br />
E:\TEST&gt;db2set<br />
DB2_LOAD_COPY_NO_OVERRIDE=COPY YES TO E:\TEST<br />
:<br />
<br />
E:\TEST&gt;db2 load from staff.del of del insert into staff<br />
SQL27966W DB2_LOAD_COPY_NO_OVERRIDE 注册表变量值 "COPY YES TO E:\TEST" 将覆盖在 Load 中指定的 COPY NO 参数。<br />
:<br />
:<br />
<br />
设置为 NONRECOVERABLE 的方法:<br />
<br />
E:\TEST&gt;db2set DB2_LOAD_COPY_NO_OVERRIDE=NONRECOVERABLE<br />
E:\TEST&gt;db2 terminate<br />
E:\TEST&gt;db2set<br />
DB2_LOAD_COPY_NO_OVERRIDE=NONRECOVERABLE<br />
:<br />
<br />
E:\TEST&gt;db2 load from staff.del of del insert into staff<br />
SQL27966W DB2_LOAD_COPY_NO_OVERRIDE 注册表变量值 "NONRECOVERABLE" 将覆盖在Load 中指定的 COPY NO 参数。<br />
:<br />
: <br />
<br />
<br />
通过上述对 LOAD 的 COPY NO，COPY YES 和 NONRECOVERABLE 参数，以及 DB2 注册表变量 DB2_LOAD_COPY_NO_OVERRIDE 的详细和举例说明，到此我们已经掌握了它们的功能和使用方法。由于 LOAD 操作几乎不记日志的特性，在对启用了前滚恢复的数据库实现 LOAD 操作时应注意从中选择适当的选项，以保证执行了 LOAD 操作的表的可用性。<img src ="http://www.blogjava.net/anwenhao/aggbug/142912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2007-09-05 15:19 <a href="http://www.blogjava.net/anwenhao/archive/2007/09/05/142912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决lucene在分布式检索下无法使用自定义排序规则的问题</title><link>http://www.blogjava.net/anwenhao/archive/2007/08/29/140838.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Wed, 29 Aug 2007 04:03:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2007/08/29/140838.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/140838.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2007/08/29/140838.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/140838.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/140838.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最近用lucene写一个多目录分布式检索的程序。不知道各位有没有遇到ParallelMultiSearcher无法使用自定排序的问题。我用indexseacher时验证我扩展的自定义排序是没有问题的。但是在ParallelMultiSearcher的情况下却始终不能按照我制定的排序规则去进行排序。郁闷至极，只好跟进lucene的源码中看个究竟。发现排序没有问题。只是PriorityQueue中堆栈总在我put 和 pop的情况下给doc的顺序改变了。没办法。只好自己扩展了堆栈放入和弹出部分代码。终于将问题解决了。下面是我修改的源码。附件上来。希望能帮助和我一样遇到问题的朋友。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lucene的自定义排序：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.blogjava.net/Files/anwenhao/DefaultSortImpl.txt">&nbsp;DefaultSortImpl.java</a><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ParallelMultiSearcher排序修改：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.blogjava.net/Files/anwenhao/ParallelMultiSearcher.txt">ParallelMultiSearcher.java<br></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.blogjava.net/Files/anwenhao/DefaultSortImpl.txt">DefaultSortImpl.java</a></p>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src ="http://www.blogjava.net/anwenhao/aggbug/140838.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2007-08-29 12:03 <a href="http://www.blogjava.net/anwenhao/archive/2007/08/29/140838.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在DB2上建立database Partition (原创)</title><link>http://www.blogjava.net/anwenhao/archive/2007/08/21/138407.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Tue, 21 Aug 2007 09:03:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2007/08/21/138407.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/138407.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2007/08/21/138407.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/138407.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/138407.html</trackback:ping><description><![CDATA[<p>&nbsp; </p>
<p><span>database Partition Feature </span><span>：</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The Database Partitioning Feature (DPF) is a value-added option available with DB2 Enterprise 9. It extends the capability of DB2 9 into the parallel, multi-partition environment, improving performance and scalability of very large databases. This allows very complex queries to be executed much faster. DB2 Enterprise 9 with DPF is an ideal solution for managing data warehousing and data mining environments, but can also be used for large online transaction processing (OLTP) workloads.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A database partition can be either logical or physical. Logical partitions reside on the same physical server and can take advantage of SMP architecture. Having a<br>partitioned database on a single machine with multiple logical nodes is know as having a shared-everything architecture, because the partitions use common memory, CPUs, disk controllers, and disks. Physical partitions consist of two or more physical servers and the database is partitioned across these servers. This is know as a shared-nothing architecture, because each partition has its own memory, CPU&#8217;s, disk controllers and disks.&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>创建</span><span>database partition&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1</span><span>、创建需要建立数据库分区的</span><span>db instance&nbsp;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>可使用命令建立</span><span>db instance </span><span>：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>db2icrt -s ESE -u db2admin,aaa123456 -h ANWENHAO DBINSTANCENAME</span></span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>创建完成对应的</span><span>instance </span><span>后需要重启</span><span>DB2 .</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2</span><span>、将新建的</span><span>db instance </span><span>加入到</span><span>DB2</span><span>中：</span></p>
<p><span>CATALOG LOCAL NODE DB2INST1 INSTANCE&nbsp;DB2INST1 SYSTEM&nbsp;ANWENHAO OSTYPE&nbsp;NT;</span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3</span><span>、在命令行中设置当前需要操作的</span><span>dbInstance </span></p>
<p><span>set db2instance=db2inst1</span></p>
<p><span>db2 get instance</span></p>
<p><span>db2 attach to db2inst1</span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</span><span>、创建</span><span>DBPartition </span><span>：</span></p>
<p><span>db2start dbpartitionnum 1 ADD DBPARTITIONNUM HOSTNAME ANWENHAO PORT 1 COMPUTER ANWENHAO USER db2admin PASSWORD aaa123456 WITHOUT TABLESPACES</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>5</span><span>、创建完成后需要重新启动</span><span>db2</span><span>。</span><span>DB2</span><span>在此时会增加一个</span><span>database partition </span><span>并进行</span> <span>redistribution </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>以上操作即完成</span><span>database partition </span><span>。</span><span> </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>创建</span><span>database partition group :</span></p>
<p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CREATE DATABASE PARTITION GROUP "NODE1" ON DBPARTITIONNUMS (1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;COMMENT ON DATABASE PARTITION GROUP "NODE1" IS 'ANWENHAO _1';</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>然后可以在建立</span><span>tablespace</span><span>时选择是否建立在一个</span><span>database partition group</span><span>中。这样我们就可以轻松使用</span><span>DB2</span><span>的</span><span>database Partition</span><span>建立集群的应用了。</span></p><img src ="http://www.blogjava.net/anwenhao/aggbug/138407.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2007-08-21 17:03 <a href="http://www.blogjava.net/anwenhao/archive/2007/08/21/138407.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分区表的优化策略</title><link>http://www.blogjava.net/anwenhao/archive/2007/08/21/138298.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Tue, 21 Aug 2007 02:44:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2007/08/21/138298.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/138298.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2007/08/21/138298.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/138298.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/138298.html</trackback:ping><description><![CDATA[<p><span><span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除指的是数据库服务器根据查询谓词确定只需要访问表的一部分<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>就可以实现查询的能力。当对分区表运行决策支持查询时，<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除可以提供特定好处。</span></p>
<p><span>分区表使用了数据组织方案，即，表数据根据该表中一个或多个表分区键列中的值分布到多个存储对象（称为<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>或范围）中。根据 CREATE TABLE 语句的 PARTITION BY 子句中指定的内容，给定表的数据被划分到多个存储对象中。这些存储对象可以在不同的表空间中，也可以在相同表空间中。</span></p>
<p><span>以下示例演示了<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除所产生的性能方面的好处。如果发出以下语句：</span></p>
<pre class=xmp><strong>CREATE TABLE</strong> custlist(subsdate DATE, Province CHAR(2), AccountID INT)
<strong>PARTITION BY RANGE(subsdate)</strong>
(<strong>STARTING FROM</strong> '1/1/1990' <strong>IN</strong> ts1,
<strong>STARTING FROM</strong> '1/1/1991' <strong>IN</strong> ts1,
<strong>STARTING FROM</strong> '1/1/1992' <strong>IN</strong> ts1,
<strong>STARTING FROM</strong> '1/1/1993' <strong>IN</strong> ts2,
<strong>STARTING FROM</strong> '1/1/1994' <strong>IN</strong> ts2,
<strong>STARTING FROM</strong> '1/1/1995' <strong>IN</strong> ts2,
<strong>STARTING FROM</strong> '1/1/1996' <strong>IN</strong> ts3,
<strong>STARTING FROM</strong> '1/1/1997' <strong>IN</strong> ts3,
<strong>STARTING FROM</strong> '1/1/1998' <strong>IN</strong> ts3,
<strong>STARTING FROM</strong> '1/1/1999' <strong>IN</strong> ts4,
<strong>STARTING FROM</strong> '1/1/2000' <strong>IN</strong> ts4,
<strong>STARTING FROM</strong> '1/1/2001' <strong>ENDING</strong> '12/31/2001' <strong>IN</strong> ts4);</pre>
<p>假定您对 2000 年的客户信息感兴趣。如果发出以下查询：</p>
<pre class=xmp><strong>SELECT * FROM</strong> custlist <strong>WHERE</strong> subsdate <strong>BETWEEN</strong> '1/1/2000' <strong>AND</strong> '12/31/2000'; </pre>
<p>正如<a href="http://localhost:51000/help/topic/com.ibm.db2.udb.admin.doc/doc/c0021579.htm#datapartelimination"><u><font color=#0000ff>图 101</font></u></a><span>所显示的那样，数据库服务器确定只需要访问表空间 4（ts4）中的一个<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>就可以解决此查询。</span></p>
<a name=datapartelimination></a>
<div class=fignone id=datapartelimination><span class=figcap><span>图 101. 分区表上<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除所产生的性能方面的好处</span></span>
<div class=mmobj><img height=435 alt=数据库服务器确定只需要访问一部分数据分区就可以实现查询。 src="http://www.blogjava.net/images/blogjava_net/anwenhao/00022397.gif" width=723 border=0></div>
</div>
<p>图 <a href="http://localhost:51000/help/topic/com.ibm.db2.udb.admin.doc/doc/c0021579.htm#indexanding"><u><font color=#0000ff>图 102</font></u></a><span> 中显示的另一个<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除示例是索引扫描，它涉及两个索引并根据以下方案进行扫描：</span></p>
<pre class=xmp><strong>CREATE TABLE</strong> multi (sale_date date, region char(2))
<strong>PARTITION BY</strong> (sale_date)
(<strong>STARTING</strong> '01/01/2005' <strong>ENDING</strong> '12/31/2005' <strong>EVERY</strong> 1 MONTH);
<strong>CREATE INDEX</strong> sx <strong>ON</strong> multi(sale_date);
<strong>CREATE INDEX</strong> rx <strong>ON</strong> multi(region);</pre>
<p>如果发出以下查询：</p>
<pre class=xmp><strong>SELECT * FROM</strong> multi <strong>WHERE</strong>
sale_date <strong>BETWEEN</strong> '6/1/2005' <strong>AND</strong> '7/31/2005' <strong>AND</strong> REGION = 'NW';</pre>
<a name=indexanding></a>
<div class=fignone id=indexanding><span class=figcap>图 102. 表分区和索引&#8220;与&#8221;（AND）的优化器决策路径</span>
<div class=mmobj><img height=394 alt=比较不使用表分区（索引&#8220;与&#8221;（AND））和使用表分区（数据分区消除）时的优化器决策路径。 src="http://www.blogjava.net/images/blogjava_net/anwenhao/00022399.gif" width=713 border=0></div>
</div>
<p>在不使用表分区时，一种可能的方案是索引&#8220;与&#8221;（AND）。索引&#8220;与&#8221;（AND）执行下列任务：</p>
<ul>
    <li>读取每个索引中的所有相关索引条目
    <li>保存两组行标识（RID）
    <li>匹配 RID 以确定哪些 RID 同时出现在这两个索引中
    <li>使用 RID 来访存行</li>
</ul>
<p>如<a href="http://localhost:51000/help/topic/com.ibm.db2.udb.admin.doc/doc/c0021579.htm#indexanding"><u><font color=#0000ff>图 102</font></u></a> 中所示，在使用表分区的情况下，读取索引以查找 region 和 sale_date 的匹配项，从而允许快速检索匹配行。</p>
<div><span class=pblktitle>DB2 说明</span>
<p>还可以使用 DB2 说明来确定 DB2 优化器选择的分区消除。<strong>DP Elim Predicates</strong><span> 信息显示扫描了哪些<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>来解决以下查询：</span></p>
<p>&#160;</p>
<pre class=xmp><strong>SELECT * FROM</strong> custlist <strong>WHERE</strong> subsdate
<strong>BETWEEN</strong> '12/31/1999' <strong>AND</strong> '1/1/2001'</pre>
<pre class=xmp>Arguments:
---------
DPESTFLG: (Number of data partitions accessed are Estimated)
FALSE
DPLSTPRT: (List of data partitions accessed)
9-11
DPNUMPRT: (Number of data partitions accessed)
3
DP Elim Predicates:
------------------
Range 1)
Stop  Predicate: (Q1.A &lt;= '01/01/2001')
Start Predicate: ('12/31/1999' &lt;= Q1.A)
Objects Used in Access Plan:
---------------------------
Schema: MRSRINI
Name: 		 CUSTLIST
Type: 		 Data Partitioned Table
Time of creation: 		 	 2005-11-30-14.21.33.857039
Last statistics update: 		 2005-11-30-14.21.34.339392
Number of columns: 		 	 3
Number of rows: 		 	 100000
Width of rows: 		 	 19
Number of buffer pool pages: 		 1200
Number of data partitions: 		 12
Distinct row values: 		 	 No
Tablespace name: 		 	 &lt;VARIOUS&gt;
</pre>
</div>
<div><span class=pblktitle>多列支持</span>
<p><span>在使用多个列作为表分区键的情况下，<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除将起作用。</span></p>
<p>例如，如果发出以下语句：</p>
<pre class=xmp><strong>CREATE TABLE</strong> sales (year INT, month INT)
<strong>PARTITION BY RANGE</strong>(year, month)
<strong>(STARTING FROM</strong> (2001, 1) <strong>ENDING AT</strong>(2001,3) IN ts1,
<strong>ENDING AT</strong>(2001,6) <strong>IN</strong> ts2,
<strong>ENDING AT</strong>(2001,9) <strong>IN</strong> ts3,
<strong>ENDING AT</strong>(2001,12) <strong>IN</strong> ts4,
<strong>ENDING AT</strong>(2002,3) <strong>IN</strong> ts5,
<strong>ENDING AT</strong>(2002,6) <strong>IN</strong> ts6,
<strong>ENDING AT</strong>(2002,9) <strong>IN</strong> ts7,
<strong>ENDING AT</strong>(2002,12) <strong>IN</strong> ts8)</pre>
<p>接着，发出以下查询：</p>
<pre class=xmp>	<strong>SELECT * FROM</strong> sales <strong>WHERE</strong> year = 2001 <strong>AND</strong> month &lt; 8</pre>
<p class=indatacontent><span>查询优化器推断只需要访问 ts1、ts2 和 ts3 中的<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>就可以解决此查询。</span></p>
<a name=wq4029></a>
<div class=notetitle id=wq4029>注:</div>
<div class=notebody><span>在多个列组成表分区键的情况下，只有当拥有组合键的前导列上的谓词时才能实现<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除，因为用于表分区键的非前导列不是独立的。</span></div>
</div>
<p>&#160;</p>
<div><span class=pblktitle>多范围支持</span>
<p><span>可以使用多个范围在<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>上实现<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除（即，一起执行&#8220;或&#8221;（OR）运算）。通过使用上一个示例中创建的表，执行下列查询：</span></p>
<pre class=xmp>	<strong>SELECT * FROM</strong> sales
<strong>WHERE</strong> (year = 2001 <strong>AND</strong> month &lt;= 3) <strong>OR</strong> (year = 2002 and month &gt;= 10)</pre>
<p class=indatacontent>数据库服务器只访问 2001 年的第一季度和 2002 年的最后一个季度的数据。</p>
</div>
<div><span class=pblktitle>生成列</span>
<p>可以将生成列用作表分区键。</p>
<p>例如，可以发出以下语句：</p>
<pre class=xmp><strong>CREATE TABLE</strong> sales(a INT, b INT <strong>GENERATED ALWAYS AS</strong> (a / 5))
<strong>IN</strong> ts1,ts2,ts3,ts4,ts5,ts6,ts7,ts8,ts9,ts10
<strong>PARTITION BY RANGE</strong>(b)
<strong>(STARTING FROM</strong> (0) <strong>ENDING AT</strong>(1000) <strong>EVERY</strong> (50))</pre>
<p><span>在此示例中，将生成列上的谓词用于<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除。此外，当用来生成列的表达式是单调的时，数据库服务器会将源列上的谓词转换为生成列上的谓词，从而在生成列上启用<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除。</span></p>
<p>例如，如果具有以下查询：</p>
<pre class=xmp>	<strong>SELECT * FROM</strong> sales <strong>WHERE</strong> a &gt; 35</pre>
<p class=indatacontent><span>数据库服务器根据（a &gt; 35）在 b（b &gt; 7）上生成额外谓词，从而允许<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除。</span></p>
</div>
<div><span class=pblktitle>连接谓词</span>
<p><span>如果将连接谓词下推到表访问级别，则也可以在<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除中使用连接谓词。连接谓词仅在嵌套循环连接（NLJN）的内部才下推到表访问级别。</span></p>
<p>请考虑下列表：</p>
<pre class=xmp><strong>CREATE TABLE</strong> T1(A INT, B INT)
<strong>PARTITION BY RANGE</strong>(A, B)
(<strong>STARTING FROM</strong> (1, 1)
<strong>ENDING</strong> (1,10) <strong>IN</strong> ts1, <strong>ENDING</strong> (1,20) <strong>IN</strong> ts2,
<strong>ENDING</strong> (2,10) <strong>IN</strong> ts3, <strong>ENDING</strong> (2,20) <strong>IN</strong> ts4,
<strong>ENDING</strong> (3,10) <strong>IN</strong> ts5, <strong>ENDING</strong> (3,20) <strong>IN</strong> ts6,
<strong>ENDING</strong> (4,10) <strong>IN</strong> ts7, <strong>ENDING</strong> (4,20) <strong>IN</strong> ts8)
<strong>CREATE TABLE</strong> T2 (A INT, B INT)</pre>
<p class=indatacontent>使用的谓词有： </p>
<pre class=xmp>P1: T1.A = T2.A
P2: T1.B &gt; 15</pre>
<p><span>在此示例中，由于不知道连接的外值，因此不能确定将在编译时访问的额外<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>。在这种情况下，以及在使用主变量或参数标记的情况下，当绑定必需的值时，就会发生<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除。</span></p>
<p><span>在运行时，当 T1 是 NLJN 的内部表时，会根据 T2.A 的每个外值的谓词自动进行<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除。在运行时，对外值 T2.A = 3 应用谓词 T1.A = 3 和 T1.B &gt; 15，这样就限定了访问的表空间 ts6 和 ts7 中的<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>。</span></p>
<p>考虑表 T1 和 T2 中的列 A 具有下列值：</p>
<a name=wq4033></a>
<table id=wq4033 rules=none width="100%" summary="" border=0 frame=void>
    <thead vAlign=bottom>
        <tr>
            <th id=wq4034 align=middle width="25%">外部表 T2：列 A</th>
            <th id=wq4035 align=middle width="25%">内部表 T1：列 A</th>
            <th id=wq4036 align=middle width="25%">内部表 T1：列 B</th>
            <th id=wq4037 align=middle width="25%"><span>内部表 T1：<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>位置</span></th>
        </tr>
    </thead>
    <tbody vAlign=top>
        <tr>
            <td align=middle headers=wq4034>2</td>
            <td align=middle headers=wq4035>3</td>
            <td align=middle headers=wq4036>20</td>
            <td align=middle headers=wq4037>ts6</td>
        </tr>
        <tr>
            <td align=middle headers=wq4034>3</td>
            <td align=middle headers=wq4035>2</td>
            <td align=middle headers=wq4036>10</td>
            <td align=middle headers=wq4037>ts3</td>
        </tr>
        <tr>
            <td align=middle headers=wq4034>3</td>
            <td align=middle headers=wq4035>2</td>
            <td align=middle headers=wq4036>18</td>
            <td align=middle headers=wq4037>ts4</td>
        </tr>
        <tr>
            <td align=middle headers=wq4034></td>
            <td align=middle headers=wq4035>3</td>
            <td align=middle headers=wq4036>15</td>
            <td align=middle headers=wq4037>ts6</td>
        </tr>
        <tr>
            <td align=middle headers=wq4034></td>
            <td align=middle headers=wq4035>1</td>
            <td align=middle headers=wq4036>40</td>
            <td align=middle headers=wq4037>ts3</td>
        </tr>
    </tbody>
</table>
<p>要执行嵌套循环连接（假定对内部表进行表扫描），数据库管理器执行下列步骤：</p>
<ol type=1>
    <li>读取 T2 中的第一行。A 的值是 2。
    <li>在连接谓词 T1.A = T2.A 中将 T2.A 值（它是 2）绑定到列 T2.A。该谓词就变成 T1.A = 2。
    <li><span>使用谓词 T1.A = 2 和 T1.B &gt; 15 应用<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>消除。这将限定表空间 ts4 和 ts5 中的<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>。 </span>
    <li><span>在应用 T1.A = 2 和 T1.B &gt; 15 之后，扫描表 T1 的表空间 ts4 和 ts5 中的<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>，直到找到一行为止。找到的第一个合格行是 T1 的行 3。 </span>
    <li>连接匹配的行。
    <li><span>扫描表 T1 的表空间 ts4 和 ts5 中的<span style="BACKGROUND: highlight; COLOR: highlighttext">数据分区</span>，直到找到下一个匹配项（T1.A = 2 和 T1.B &gt; 15）为止。再也找不到其他行。 </span>
    <li>对 T2 的下一行（将 A 的值替换为 3）重复步骤 1 至 6，直到用完 T2 中的所有行为止。</li>
</ol>
</div><img src ="http://www.blogjava.net/anwenhao/aggbug/138298.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2007-08-21 10:44 <a href="http://www.blogjava.net/anwenhao/archive/2007/08/21/138298.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DB2 中使用table Partition(原创)</title><link>http://www.blogjava.net/anwenhao/archive/2007/08/21/138291.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Tue, 21 Aug 2007 02:27:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2007/08/21/138291.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/138291.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2007/08/21/138291.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/138291.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/138291.html</trackback:ping><description><![CDATA[&nbsp;
<p>&nbsp;创建DB Partition Group ：<br><br>&nbsp;&nbsp;&nbsp;CREATE DATABASE PARTITION GROUP "PG2" ON DBPARTITIONNUMS (2);<br>&nbsp;&nbsp;&nbsp;COMMENT ON DATABASE PARTITION GROUP "PG2" IS 'PG2';<br><br></p>
<p><span><span>1、&nbsp;</span></span><span>在创建</span><span>table</span><span>时可以选择</span><span>table Partition </span><span>需要先创建对应的表空间。后指定</span><span>table Partition</span><span>的范围：</span></p>
<p><span>CONNECT TO TESTDPF;</span></p>
<p><span>CREATE TABLE WANGDH.TABLEPARTITIONTEST ( ID INTEGER&nbsp;NOT NULL , TEST BIGINT&nbsp;NOT NULL&nbsp;, CONSTRAINT CC1187661638203 PRIMARY KEY ( ID)&nbsp;) PARTITION BY RANGE (ID NULLS LAST) (PARTITION PAR1 STARTING FROM (0) INCLUSIVE ENDING AT (10) INCLUSIVE IN PARTITION1 ) IN PARTITION1 CYCLE ;</span></p>
<p><span>CONNECT RESET;</span></p>
<p>&nbsp;</p>
<p><span><span>2、&nbsp;</span></span><span>追加</span><span>table partition </span><span>时需要先建立</span><span>table space </span><span>。然后再在对应的</span><span>table space </span><span>上建立</span><span>partition</span></p>
<p>&nbsp;</p>
<p><span><span>一、<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>建立</span><span>table space </span><span>：</span></p>
<p><span>create large tablespace par2 pagesize 4K managed by automatic storage extentsize 16 overhead 10.5 prefetchsize 16;</span></p>
<p>&nbsp;</p>
<p><span>Node</span><span>：</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>创建的</span><span>table space </span><span>需要选择类型为：</span><span>large </span><span>（大型）</span></p>
<p><span><span>二、<span>&nbsp;&nbsp;&nbsp; </span></span></span><span>使用</span><span>add table partition </span><span>增加</span><span>table partition:</span></p>
<p><span>alter table tablepartitiontest add partition PAR2 starting from (11) inclusive ending at (20) exclusive in PAR2</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>可选择</span><span>partition</span><span>的范围。</span><span>Inclusive </span><span>：包含</span><span>&nbsp;exclusive</span><span>：不包含</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>通过以上两种方式可在</span><span>table</span><span>层面上建立</span><span>table partition </span><span>从而达到数据库中数据隔离的要求。</span></p><img src ="http://www.blogjava.net/anwenhao/aggbug/138291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2007-08-21 10:27 <a href="http://www.blogjava.net/anwenhao/archive/2007/08/21/138291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>客户端调用BPEL流程的几种方法(转)</title><link>http://www.blogjava.net/anwenhao/archive/2007/06/25/126133.html</link><dc:creator>安文豪</dc:creator><author>安文豪</author><pubDate>Mon, 25 Jun 2007 08:12:00 GMT</pubDate><guid>http://www.blogjava.net/anwenhao/archive/2007/06/25/126133.html</guid><wfw:comment>http://www.blogjava.net/anwenhao/comments/126133.html</wfw:comment><comments>http://www.blogjava.net/anwenhao/archive/2007/06/25/126133.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/anwenhao/comments/commentRss/126133.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/anwenhao/services/trackbacks/126133.html</trackback:ping><description><![CDATA[<p>使用WID开发BPEL业务流程模版后，通常部署到WPS上面以后我们需要能够trgger流程启动和流程运转。否则流程就没有意义了。<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 请参考：<a href="http://www.ibm.com/developerworks/cn/websphere/library/techarticles/0512_fanggw/#N100F6">http://www.ibm.com/developerworks/cn/websphere/library/techarticles/0512_fanggw/#N100F6</a><br><br>这里介绍客户端调用流程的几种方式。通常有三种方式：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、基于服务组件架构（SCA）的调用方式</p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、基于Web服务的调用方式 （WebService调用）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、通过BPC的应用程序接口<br>用到最多的还是第三种通过BPC应用程序接口调用的方式。下面介绍一下通过BPC应用程序调用BPEL的方式：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当我们设计好业务流程。并且部署到WPS下后：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们首先要通过JNDI找到LocalBusinessFlowManagerHome，然后生成相应的LocalBusinessFlowManager。这部分的代码片断如下：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InitialContext ctx = new InitialContext();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocalBusinessFlowManagerHome mgrHome =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(LocalBusinessFlowManagerHome)ctx.lookup("java:comp/env/ejb/LocalBusinessFlowManagerHome");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LocalBusinessFlowManager mgr = mgrHome.create();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>调用流程的代码是通过LocalBusinessFlowManager的call方法。方法的简单说明如下：</p>
<pre>public ClientObjectWrapper call(java.lang.String processTemplateName,
ClientObjectWrapper inputMessage)；</pre>
<p>因此，我们需要构建一个代表输入参数的ClientOjbectWrapper。生成一个代表输入参数的ClientObjectWrapper有多种方式，这里采用先构建一个DataObject，然后调用ClientObjectWrapper构造方法的方式。具体代码实现如下：</p>
<br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>ServiceManager serviceMgr = new ServiceManager();
            BOFactory bofactory = (BOFactory)serviceMgr.locateService("com/ibm/websphere/bo/BOFactory");
            DataObject input = bofactory.createByElement("http://HelloWorld/HelloWorldInterface", "hello");
            input.setString("helloInput", msg);
            ClientObjectWrapper inputWrapper = new ClientObjectWrapper(input);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>BOFactory的createByElement根据流程的WSDL接口生成一个代表参数的一个DataObject。在生成代表输入的ClientObjectWrapper之后，调用流程就变得相对比较简单，具体代码片断如下：</p>
<br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td class=code-outline>
            <pre class=displaycode>ClientObjectWrapper outputWrapper = mgr.call("HelloWorldProcess", inputWrapper);
            DataObject output = (DataObject) outputWrapper.getObject();
            resp = output.getString("helloOutput");
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br><img src ="http://www.blogjava.net/anwenhao/aggbug/126133.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/anwenhao/" target="_blank">安文豪</a> 2007-06-25 16:12 <a href="http://www.blogjava.net/anwenhao/archive/2007/06/25/126133.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>