CASTOR JDO 指南

类别:Java 点击:0 评论:0 推荐:

CASTOR  JDO 指南
    现在,越来越多的企业级开发项目中需要一种在众多关系数据库
上进行对象关系映射的技术。遗憾的是,个体组织内部的解决方案很
难构建,而对其进行长期维护和扩展就更难了。虽然有了EJB技术,
但是我发现在某些情况下使用EJB技术往往过于重量级了,这时候适合
的解决方式应该是轻量级的为好。本文中,我将向您介绍了使用 Cast
or JDO 的基础知识, Castor JDO(Java 数据对象 (Java Data Obje
cts))是一种开放源码的、百分之百 Java 关系对象映射框架,Castor
同许多其它技术结合使用,已经将 Java 对象模型绑定到关系数据库、
XML 文档以及 LDAP 目录上。

    在本文中,您将了解使用 Castor JDO 的基本知识。我们将从配置
    JDO开始;然后是关系数据模型和 Java 对象模型,接下来讨论在
    二者之间进行映射的基础知识;最后我们将讨论 Castor JDO 的一
    些特性。您将了解一些基本内容,如(关系的和面向对象的)继承、
    从属与相关关系、对象查询语言(Object Query Language)实现以
    及短事务和长事务的比较。

第一部分:J DO 配置
数据库配置意味着从数据库服务器中获得一个连接,和在java类和数据
表间映射,以及提供数据库服务与客户间的会话。Castor支持目前所有
主流的数据库产品,需要注意的是,它不支持JDBC-ODBC桥接方式。不同
的数据库服务有着不同的配置语法,通过配置数据库服务器对客户提供服
务。

Castor支持的数据库系统列表如下:

1:oracle Oracle 7 and Oracle 8
2:sybase Sybase 11
3:sql-server Microsoft SQL Server
4:db2 DB/2
5:informix Informix
6:postgresql PostgreSQL 7.1
7:hsql Hypersonic SQL
8:instantdb InstantDB
9:interbase Interbase
10:mysql MySQL
11:sapdb SAP DB

下面给出几种数据库系统的配置方式:

Sybase jConnect  
   <data-source class-name="com.sybase.jdbc2.jdbc.SybDataSource">
   <params user="user" password="secret"  port-number="4100"
   server-name="host" />
   </data-source>
 
Oracle Thin Driver  
<database name="ebiz" engine="oracle">
   <driver class-name="oracle.jdbc.driver.OracleDriver"
          url="jdbc:oracle:thin:@host:post:SID">
    <param name="user" value="scott" />
    <param name="password" value="tiger" />
   </driver>
</database>
 
InstantDB 
     <driver class-name="org.enhydra.instantdb.jdbc.idbDriver"
          url="jdbc:idb:C:\\castor-0.8.8\\db\\test\\test.prp">
     <param name="user" value="" />
     <param name="password" value="" />
    </driver>
 
sql-server

<database name="test" engine="sql-server" >
 <driver class-name="com.microsoft.jdbc.sqlserver.SQLServerDriver"
         url="jdbc:microsoft:sqlserver://localhost:1433">
      <param name="user" value="sa" />
      <param name="password" value="sa"/>
    </driver>
   <mapping href="mapping.xml"/>
</database>


第二部分:第一个例子

在这一部分里我将从一个简单的数据模型开始,并让你初步了解如何使用
Castor。

首先我定义一个简单的数据模型,不包含任何的关系。
 

她的代码如下:
Customer.java

package org.user;

import java.util.*;

public class  Customer{
 private int _id;
 private String _last_name;
 private String _first_name;

  public int getId()
    {
        return _id;
    }
    public void setId( int id )
    {
        _id = id;
    }
  public String  getFname()
    {
        return _first_name;
    }
public void setFname( String  first_name )
    {
        _first_name = first_name;
    }
     public String  getLname()
    {
        return _last_name;
    }
    public void setLname( String  last_name )
    {
        _last_name = last_name;
    }
  
public void toString()
    {
        return  this.getFname()+" "+this.getLname() ","+this.getId();
    }

}

正如你所看到的,它可以是一个普通类,当然你也可以实现org.exolab.castor.jdo.
Persistent接口,从而在持久化之前做预处理。

现在让我们来看映射配置文件

mapping.xml

<!DOCTYPE databases PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
                           "http://castor.exolab.org/mapping.dtd">
<mapping>
<class name="org.user.Customer"  identity="id">
<description>     
        Customer
 </description>
 <map-to table="CUSTOMERS"/>
  
   <field name="id" type="integer">
   <sql name="ID" type="integer"/>
   </field>
   
   <field name="fname" type="string">
   <sql name="FIRST_NAME" type="char"/>
   </field>
  
   <field name="lname" type="string">
   <sql name="LAST_NAME" type="char"/>
   </field>
</class>
 </mapping>


正如你所看到的,映射文件很简单。<class> 元素支持一些重要的属性和元素。例如,
Customer映射使用 identify 属性来指示对象的哪个特性充当对象标识符。<class>
 元素还支持 <map-to> 元素, 该元素告诉 Castor 每个对象映射到什么关系表上。
 <field> 元素也支持一些属性。请注意,所有 <field> 和 <sql> 元素的映射都包
 含 type 属性。类型属性向 Castor指示:该在内部使用什么 类型转换器来在对象
 和关系数据类型之间进行转换。

现在让我们来写一个测试文件:

test.java

import org.user.*;


public class Mytest{  
    public static final String DatabaseFile = "database.xml";
    public static final String MappingFile = "mapping.xml";
    public static final String Usage = "Usage: example jdo";
   
    private Mapping  _mapping;
    private JDO      _jdo;

     public static void main( String[] args )
    {
     
      try
        {
            Test test = new Ttest();
            test.run();
        }
        catch ( Exception except )
        {           
            except.printStackTrace();
        }
    }
   
    public Test()
        throws Exception
    {
        // 装载实体关系映射文件
        _mapping = new Mapping( getClass().getClassLoader() );
        _mapping.loadMapping( getClass().getResource( MappingFile ) );
        //装载数据库连接映射文件
        _jdo = new JDO();
        _jdo.setConfiguration( getClass().getResource( DatabaseFile ).
        toString() );
        _jdo.setDatabaseName( "test" );
       
    }


    public void run()
        throws Exception
    {
        Database      db;      
        Customer customer;     
        OQLQuery      customerOql;
        QueryResults  results;

        db = _jdo.getDatabase();
        //注意在持久化对对象包含关系引用时,必须打开这个选项才能够自动持久
        化关系对象。
db.setAutoStore(true);

        db.begin();
 
        customer = new Customer();
        customer.setId(1);
        customer.setFname("rain");
        customer.setLname("wk");
       
        //持久化数据
        db.makePersistent(customer);


//通过装载也可加载数据
// customer = (Customer)db.load(Customer.class,new Integer("1"));
//System.out.println( "select customer: " + customer); 

//通过OQL语言查询持久化数据。
        customerOql = db.getOQLQuery("SELECT p FROM org.user.Customer  p
         WHERE p.id =$1");
        productOql.bind(1);

        results = customerOql.execute();
        while ( results.hasMore())
        {
            customer = (Customer) results.next();
            System.out.println( "select customer: " + customer);           
        }
        db.commit();
}

}

 

结果:

   select customer:rain wk ,1

   在体验完第一个例子后,想必你对Castor 有了一定的认识,是不是看上去很简单,
Castor帮你是现实过去需要EJB才能实现的实体持久化。这正是我们想要的,一个
轻量级的可以在大多数场合替代EJB的有效技术。我将在接下来的文章中详细讲解
Castor JDO 技术。

 


第四部分:JDO 关系
    上一章我讲解了JDO的持久化,本章将讲解JDO中关于关系的问题。同样的]我将通
过几个例子来详细介绍他的有关特性。
    为了处理真实世界的模型,jdo必须能够管理数据模型彼此复杂的关系,在jdo中,
不同种类的关系被归为5种类型:一对多单向,一对多双向,多对一单向,多对一双向,多对多。
在开始之前,我们先定义一个管理接口的适配器,以方便编码。

abstract  class  PersistentCapable implements Persistent{
private Database     _db;
    public void jdoPersistent( Database db )
    {
        _db = db;
    }
    public void jdoTransient()
    {
        _db = null;
    }
    public Class jdoLoad(short accessMode)
    {
        return null;
    }
    public void jdoBeforeCreate( Database db )
    {
    }
    public void jdoAfterCreate()
    {
    }
    public void jdoStore(boolean modified)
    {
    }
    public void jdoBeforeRemove()
    {
    }
    public void jdoAfterRemove()
    {
    }
    public void jdoUpdate()
    {
    }
}

一对多
在一对多的关系下,数据模型中从表有一个指向主表的引用,模型图如下所示
,Oder 和Orderitem 构成了主从表关系,order_id=id 为其关系。一对多关
系是典型的数据库应用。但是从Castor中存储的时候却必须以主(Oder)对象
来持久化,从(Orderitem)做为他的从属对象来对待。
 

首先让我们来看一下order类。需要注意的是:第一,实现Persistent接口。
第二,建立与OrderItem的引用。
package org.user;

import java.util.*;

public  class Order  extend  PersistentCapable {

 private int _id;
 private String _name;
 private Vector _orderItems = new Vector();

 public void setId(int id){
  _id = id;
 }
 public int getId(){
  return _id;
 }
 
 public void setName(String name){
  _name = name;
 }
 public String getName(){
  return _name;
 }

 public void addOrderItem(OrderItem orderItem){
  _orderItems.add(orderItem);
   orderItem.setOrder(this);  
 }

 public Vector getOrderItems(){
  return _orderItems;
 }
}

同样的OrderItem也保持一个Order的引用。
 package org.user;

import java.util.*;

public  class OrderItem{
 private int _id;
 private String _name;
 private float _price;
 
 private Order _order;
 
 public void setId(int id){
  _id = id;
 }
 public int getId(){
  return _id;
 }
 public void setName(String name){
  _name = name;
 }
 public String getName(){
  return _name;
 }
 public void setPrice(float price){
  _price = price;
 }
 public float getPrice(){
  return _price;
 }
 public void setOrder(Order order){
  _order = order;
 }
 public Order getOrder(){
  return _order;
 }
}

接下来让我们看一看配置文件的内容。

<class name="org.user.Order" identity="id">
<description>     
        Order
 </description>
 <map-to table="ORDERS"/>
    <field name="id" type="integer">
    <sql name="ID" type="integer"/>
    </field>
    <field name="name" type="string">
     <sql name="NAME" type="char"/>
</field>

     <field name="orderItems" type="org.user.OrderItem"  required="true"
     collection="vector">
     <sql many-key="ORDER_ID"/>
     </field>
    
</class>

<class name="org.user.OrderItem" identity="id">
<description>     
        OrderItem
 </description>
<map-to table="ORDERITEM"/>
   <field name="id" type="integer">
    <sql name="ID" type="integer"/>
   </field>
    <field name="name" type="string">
     <sql name="NAME" type="char"/>
    </field>
    <field name="price" type="float">
    <sql name="PRICE" type="float"/>
    </field>
    <field name="order" type="org.user.Order">
      <sql name="ORDER_ID"/>     
    </field>
 </class>


需要注意的是如下的配置代码:

Order引用了一个外部类型OrderItem,外部字段名称是ORDER_ID ,orderItems属
性返回一个collection结构的对象集合。
<field name="orderItems" type="org.user.OrderItem"  required="true"
collection="vector">
<sql many-key="ORDER_ID"/>

同样的OrderItem引用了一个Order类型的关系,字段名称是ORDER_ID。
<field name="order" type="org.user.Order">
      <sql name="ORDER_ID"/>     
    </field>

上面的关系是双向的,他们可以互相观察对方,你可以通过任何一方来导航,但也
可以是单向的,即通过主导航到从,你需要修改部分代码,这里我就不讲了,不过
我建议你使用双向导航。
多对一

在多对一的关系下,数据模型中主表有一个指向从表的引用,模型图如下所示,
Customer 和Address 构成了表关系,多对一关系是典型的数据库应用。是Castor
中存储的时候却必须以主(Customer)对象来持久化,从(Address)做为他的从
属对象来对待。

 

代码如下.
package org.user;

import java.util.*;

public class  Customer  extend  PersistentCapable {
 private int _id;
 private String _last_name;
 private String _first_name;
 private Vector _address =new Vector();
 
 private Address _address;
  public int getId()
    {
        return _id;
    }
    public void setId( int id )
    {
        _id = id;
    }
public String  getFname()
    {
        return _first_name;
    }
public void setFname( String  first_name )
    {
        _first_name = first_name;
    }
     public String  getLname()
    {
        return _last_name;
    }
    public void setLname( String  last_name )
    {
        _last_name = last_name;
    }
     public Address getAddress()
    {
        return _address;
    }
    public void addAddress( Address address )
    {
        _address.add( address );
        address.setCustomer(this);
    }
     public void setAddress(Address address)
    {
        _address = address;
    }

}

package org.user;

public class Address{
 
 private int _id;
 private String _street;
 private String _city;
 private String _state;
 private String _zip;
 private Customer _customer;
 
    public int getId()
    {
        return _id;
    }
    public void setId( int id )
    {
        _id = id;
    }
    public String  getStreet()
    {
        return _street;
    }
    public void setStreet( String street )
    {
        _street = street;
    }
    public String  getCity()
    {
        return _city;
    }
    public void setCity( String city )
    {
        _city = city;
    }
   
    public String  getState()
    {
        return _state;
    }
    public void setState( String state )
    {
        _state = state;
    }
    public String  getZip()
    {
        return _zip;
    }
    public void setZip( String zip )
    {
        _zip = zip;
    }
    public Customer  getCustomer()
    {
        return _customer;
    }
    public void setCustomer( Customer customer )
    {
        _customer = customer;
    }
}


<class name="org.user.Customer"  identity="id">
<description>     
        Customer
 </description>
 <map-to table="CUSTOMER"/>
   <field name="id" type="integer">
   <sql name="ID" type="integer"/>
   </field>
   <field name="fname" type="string">
   <sql name="FIRST_NAME" type="char"/>
   </field>
   <field name="lname" type="string">
   <sql name="LAST_NAME" type="char"/>
   </field>
    <field name="address" type="org.user.Address">
      <sql name="ADDRESS_ID"/>    
    </field>  
</class>

<class name="org.user.Address"  identity="id">
<description>     
        Address
 </description>
 <map-to table="ADDRESS"/>
   <field name="id" type="integer">
   <sql name="ID" type="integer"/>
   </field>
   <field name="street" type="string">
   <sql name="STREET" type="char"/>
   </field>
   <field name="state" type="string">
   <sql name="STATE" type="char"/>
   </field>
   <field name="zip" type="string">
   <sql name="ZIP" type="char"/>
   </field>
   <field name="city" type="string">
   <sql name="CITY" type="char"/>
   </field>
</class>

Customer引用了一个外部类型Address,字段名称是ADDRESS_ID。
<field name="address" type="org.user.Address">
      <sql name="ADDRESS_ID"/>    
 </field>  


多对多


在多对多的关系下,数据模型中表A,表B都有一个指向中间表的引用,模型图如下
所示category 和category_prod构成了表关系,prod和category_prod构成了表关,
这样category和prod构成多对多得关系,这是典型的数据库应用。
 

代码如下:

package jdo;

import java.util.Vector;
import java.util.Enumeration;

public class Category
{
    private int      _id;
    private Vector   _products = new Vector();
private String   _name;

    public int getId()
    {
        return _id;
    }
    public void setId( int id )
    {
        _id = id;
    }
    public String getName()
    {
        return _name;
    }
    public void setName( String name )
    {
        _name = name;
    }
    //public Enumeration getProducts()
    public Vector getProducts()
    {
        return _products;
        // return _products.elements();
    }
    public void addProduct( Product product )
    {
        if ( ! _products.contains( product ) ) {
            System.out.println( "Adding product " + product + "
            to category " + this );
            _products.addElement( product );
            product.addCategories( this );
        }
    }
    public String toString()
    {
        return "<id: " + _id + " name: " + _name + ">";
    }
}

package jdo;

import java.util.Vector;
import java.util.Enumeration;
import org.exolab.castor.jdo.Database;
import org.exolab.castor.jdo.Persistent;


public class Product //implements Persistent
{
    private int          _id;
    private String       _name;
    private float        _price;
    private Database     _db;
    private Vector       _categories = new Vector();
    public int getId()
    {
        return _id;
    }
    public void setId( int id )
    {
        _id = id;
    }
    public String getName()
    {
        return _name;
    }
    public void setName( String name )
    {
        _name = name;
    }
    public float getPrice()
    {
        return _price;
    }
    public void setPrice( float price )
    {
        _price = price;
    }
    public Vector getCategories()
    {
        return _categories;
    }
    public void addCategories( Category category )
    {
        if ( ! _categories.contains( category ) ) {
            _categories.addElement( category );
            category.addProduct( this );
        }
    }
    public String toString()
    {
        return "<id: " + _id + " name: " + _name + ">";
    }
}


<!--  Mapping for Product  -->
  <class name="jdo.Product" identity="id">
    <description>Product definition</description>
    <map-to table="prod" xml="product" />
    <field name="id" type="integer">
      <sql name="id" type="integer" />
    </field>
    <field name="name" type="string">
      <sql name="name" type="char" />
    </field>
    <field name="price" type="float">
      <sql name="price" type="numeric" />
    </field>

    <!-- Product has reference to Category with
         many-many relationship -->
    <field name="categories" type="jdo.Category" required="true"
           collection="vector">
      <sql name="category_id"
           many-table="category_prod" many-key="prod_id" />
    </field>
  </class>

<class name="jdo.Category" identity="id">
    <description>
        A product category, any number of products can belong to
        the same category, a product can belong to any number of
        categories
    </description>
    <map-to table="category" xml="category" />
    <field name="id" type="integer">
      <sql name="id" type="integer"/>
    </field>
    <field name="name" type="string">
      <sql name="name" type="char"/>
    </field>
    <field name="products" type="jdo.Product" required="true"
           collection="vector">
      <sql name="prod_id"
           many-table="category_prod" many-key="category_id" />
    </field>
  </class>


Product含有一个 Category引用,附加一个中间表category_prod,字段名称为
category_id;同样 Category也有一个 Product引用,附加一个中间表categor
y_prod,字段名称为prod_id。

<field name="categories" type="jdo.Category" required="true"
           collection="vector">
      <sql name="category_id"
           many-table="category_prod" many-key="prod_id" />
    </field>

<field name="products" type="jdo.Product" required="true"
           collection="vector">
      <sql name="prod_id"
           many-table="category_prod" many-key="category_id" />
      </field>

 

在本文中,我们讨论了使用 Castor 将关系数据模型映射到 Java 对象模型的基
础知识。同过这些简单的示例肯定不能涵盖 Castor 的全部能力。实际上,Cast
or 支持许多其它特性,包括键生成、延迟装入、LRU 高速缓存、不同的锁定/访
问方式以及更多。我将在下一部分介绍更多的知识。


参考资料

 

本文地址:http://com.8s8s.com/it/it17821.htm