当前位置:支点网 >> 资讯
滚动新闻:

利用Hibernate优势加快 SCA 模块实现

作者:张俊青  来源:developerWorks 中国  时间:2008-7-3 11:26:52
SCA(Service Component Architecture)作为服务组件体系结构,将所有的集成构件都描述为具有定义明确的接口的服务组件。SCA 还引入了模块的概念,它将服务组件集中到一起,并提供服务的进一步说明和封装。

 

  StockHolder存放股东信息,该表中的主键id的值由一个用户定义的sequence产生,为了让Hibernate能够自动调用这个sequence的 nextval获取下一个值,我们必须指定id元素的generator的class为sequence,并且在param中指定sequence的名称,如清单-10所示:

  清单-10:StockHolder表定义

  CREATE TABLE StockHolder(
  id                INTEGER NOT NULL,
  name              VARCHAR(40),
  gender            CHAR(2),    
  idCardNum         VARCHAR(18),
  email             VARCHAR(50),
  address           VARCHAR(100),
  CONSTRAINT pk_stockHolder PRIMARY KEY (id)
  );
  CREATE SEQUENCE stockHolder_seq
  START WITH 1005
  INCREMENT BY 1
  NOMAXVALUE
  NOCYCLE
  CACHE 24 ;

  清单-11:StockHolder类定义

  public class StockHolder implements Serializable {
  private String id;
  private String name;
  private String gender;
  private String idCardNum;
  private String email;
  private String address;
  //Getters and setters
  ……
  }

  清单-12:StockHolder.hbm.xml定义

  <?xml version="1.0"?>
  <!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  <hibernate-mapping package="module.stock.implementation">
  <class name="StockHolder" table="StockHolder"
  lazy="true">
  <comment>Stock Holder table</comment>      
  <id name="id">
  <generator class="sequence">
  <param name="sequence">stockHolder_seq</param>
  </generator>
  </id>      
  <property name="name"/>
  <property name="gender"/>
  <property name="idCardNum"/>
  <property name="email"/>
  <property name="address"/>
  </class>   
  </hibernate-mapping>

  StockMemo.hbm.xml – 使用identity

  StockMemo表存放每个交易日的证券价格信息,StockMemo表的主键id在数据库中是一个identity的自增字段类型,因此在做Hibernate映射时,必须使用<generator class="native" />来对id的generator算法进行定义, native将使得Hibernate在插入数据时,使用数据库内置的identity属性来生成唯一的id值。

  清单-13:stockMemo表定义

  CREATE TABLE stockMemo(
  id                INTEGER NOT NULL
  GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
  stockId           VARCHAR(10) NOT NULL,
  currentPrice      DECIMAL(17,3),
  highestPrice      DECIMAL(17,3),
  lowestPrice       DECIMAL(17,3),
  tradeDate         VARCHAR(10) default char(current date),
  FOREIGN KEY fk_stockMemeo (stockId)
  REFERENCES Stock ON DELETE NO ACTION
  );

  清单-14:StockMemo类定义

  public class StockMemo implements Serializable {
  private String id;
  private String stockId;
  private String currentPrice;
  private String highestPrice;
  private String tradeDate;
  private Stock stock;
  //Getters and setters
  ……
  }

  StockMemo类还有一个stock属性,类型为Stock,很明显对应于stockId,StockMemo与Stock之间是多对一的关系,因此,我们使用 many-to-one元素来定义stock属性。如清单-13所示:

  清单-15:StockMemo.hbm.xml定义

  <?xml version="1.0"?>
  <!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  <hibernate-mapping package="module.stock.implementation">
  <class name="StockMemo" table="StockMemo"
  lazy="true">
  <comment>Stock memo table</comment>    
  <id name="id">
  <generator class="native" />
  </id>
  <property name="stockId"/>
  <property name="currentPrice"/>
  <property name="highestPrice"/>
  <property name="lowestPrice"/>
  <property name="tradeDate"/>
  <many-to-one name="stock" class="Stock"
  insert="false" update="false">
  <column name="stockId"/>
  </many-to-one>
  </class>   
  </hibernate-mapping>

  StockAccount.hbm.xml – 使用compose-id和多个many-to-one映射

  StockAccount类比较复杂,对应的Accout表存放的是股东拥有证券的情况,除了要对stockHolderId, stockId, balance, profit等四个一般属性进行映射外,还必须为三个复杂数据类型的属性进行映射。

  在定义映射关系之前,需要明确StockAccount与StockHolder,Stock以及StockMemo之间的对应关系:

  一个股东可以买卖多个证券,因此StockAccount与StockHolder之间是多对一关系
  一个证券可以被多个股东所买卖,因此StockAccount与Stock之间是多对一关系
  一个证券在不同的交易日有不同的价格,因此StockMemo与Stock之间是多对一关系
  值得注意的是通过StockAccount,我们实际上定义了StockHolder与Stock之间的多对多关系。

  清单-16:Account表定义

  CREATE TABLE account(
  stockHolderId INTEGER NOT NULL,
  stockId           VARCHAR(10) NOT NULL,
  balance           INT,
  profit            DECIMAL(17,3),
  FOREIGN KEY fk_account1 (stockHolderId)
  REFERENCES StockHolder ON DELETE NO ACTION,
  FOREIGN KEY fk_account2 (stockId)
  REFERENCES stock ON DELETE NO ACTION
  );

  对于Account表,stockHolderId和stockId组合可以被视为该表的主键,这一点将使用composite-id元素在Hibernate映射文件中进行表达。

  清单-17:StockAccount类定义

  public class StockAccount implements Serializable {
  private String stockHolderId;
  private String stockId;
  private int balance;
  private float profit;
  private StockHolder stockHolder;
  private Stock stock;
  private StockMemo stockMemo;
  //Getters and setters
  ......
  public boolean equals(StockAccount sa){
  boolean isEquals=false;
  if(sa!=null){
  if(stockHolder.getId().equals(sa.getStockHolder().getId()) &&
  stockHolder.getIdCardNum().equals(
  sa.getStockHolder().getIdCardNum()) &&
  stock.getId().equals(sa.getStock().getId()) &&
  stock.getStkName().equals(sa.getStock().getStkName())      
  )
  isEquals = true;
  }
  return isEquals;
  }
  public int hashCode() {
  int h=0;
  h = stockHolder.hashCode()+19*stock.hashCode();
  return h;
  }
  }

  清单-18:StockAccount.hbm.xml定义

  <a name="<?xml version="1.0"?>
  <!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  <hibernate-mapping package="module.stock.implementation">
  <class name="StockAccount" table="Account" lazy="true">
  <comment>Stock Account table</comment> 
  <composite-id >
  <key-property name="stockHolderId"/>
  <key-property name="stockId"/>
  </composite-id> 
  <many-to-one name="stockHolder" class="StockHolder"
  insert="false" update="false">
  <column name="stockHolderId"/>
  </many-to-one>
  <many-to-one name="stock" class="Stock"
  insert="false" update="false">
  <column name="stockId"/>
  </many-to-one> 
  <many-to-one name="stockMemo" class="StockMemo"
  insert="false" update="false">
  <column name="stockId"/>
  </many-to-one> 
  <property name="balance"/>
  <property name="profit"/>
  </class>
  </hibernate-mapping>
  "></a>

  -composite-id定义了一个由stockHolderId和stockId组成的组合主键。和一般id不同,在包含composite-id的持久类中,必须重载equals()和hashCode()这两个方法。如上面的清单-15所示。

  -三个many-to-one元素,把stockHolder, stock和stockMemo分别映射到StockHolder类,Stock类和StockMemo类上。

  6.实现StockService模块

  StockServiceImp是StockService模块的实现类,我们使用Hibernate充当数据访问服务层,通过JavaBean可以很方便的实现底层数据与SDO之间的交换。

  图-18 SDO,JavaBean与数据库的交互过程

 

  首先,我们需要创建一个叫做HibernateUtil的类,如清单-17所示,它以Singleton的模式实例化一个SessionFactory,为Hibernate API调用提供基础。在实例化SessionFactory时,指定hibernate.xfg.xml配置文件(见清单-3)。

  清单-19: HibernateUtil.java

  public class HibernateUtil {
  private static final SessionFactory sessionFactory;
  static {
  try {
  // Create the SessionFactory from hibernate.cfg.xml
  sessionFactory = new Configuration()
  .configure("/gen/src/module/stock/implementation/hibernate.cfg.xml")
  .buildSessionFactory();
  } catch (Throwable ex) {
  System.err.println("Initial SessionFactory creation failed." + ex);
  throw new ExceptionInInitializerError(ex);
  }
  }
  public static SessionFactory getSessionFactory() {
  return sessionFactory;
  }
  }

  然后,实现addStock, addStockType,getStockTypeList等一系列方法。限于篇幅,本文只介绍两个典型的方法 addStockAccount和getStockList的实现,这两个方法的实现包括了实现其他几个方法会涉及到的问题。

  1) addStockAccount方法:

  该方法的功能是:将StockHolder SDO和Stock SDO以及stock的数量qty等数据存储到account表中,业务上表现为股东StockHolder买进数量为qty的Stock类证券。

  输入参数有三个:

  DataObject stockHolder, 股东信息
  DataObject stock,证券信息
  Integer qty,买入的证券数量
  我们的方法是把DataObject中的数据转换到JavaBean中,然后再利用Hibernate,把数据持久化到DB中,代码如清单-18所示:

  清单-20:addStockAccount的实现代码

  public String addStockAccount(DataObject stockHolder, DataObject stock,Integer qty) {
  String message = null;
  if (stockHolder != null && stock != null) {
  try {//得到SessionFactory的实例
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  //这一句是必需的,表明Transaction的开始
  session.beginTransaction();
  //将输入参数DataObject分别转换为JavaBean
  StockHolder sh = convertToStockHolder(stockHolder);
  Stock st = convertToStock(stock);
  //新建一个StockAccount Bean对象
  StockAccount sa = new StockAccount();
  //把入参都set进去
  sa.setStock(st);
  sa.setStockHolder(sh);
  sa.setStockHolderId(sh.getId());
  sa.setStockId(st.getId());
  sa.setBalance(qty.intValue());
  sa.setProfit(0); //初始化为0
  //调用session.persist()方法,指定StockAccount将被持久化
  session.persist("StockAccount", sa);
  //调用session.flush()方法将memory中的数据保存到数据库中
  session.flush();
  //关闭session
  session.close();
  message = "StockAccount saved successfully!";
  } catch (Exception e) {
  e.printStackTrace();
  message = "Faile to save StockAccount to database: "+ e.getMessage();
  }
  }
  return message;
  }

  下面对上述代码进行简要说明:

  首先,我们把输入参数中的两个DataObject转换为JavaBean:sh(StockHolder)和st(Stock)
  对于StockHolder,我们定义以下方法来完成DataObject向JavaBean转化:

  清单-21:convertToStockHolder(DataObject stockHolderBO)方法

  private StockHolder convertToStockHolder(DataObject stockHolderBO) {
  StockHolder stockHolder = null;
  if (stockHolderBO != null) {
  try {
  stockHolder = new StockHolder();
  stockHolder.setId(stockHolderBO.getString("id"));
  stockHolder.setName(stockHolderBO.getString("name"));
  stockHolder.setGender(stockHolderBO.getString("gender"));
  stockHolder.setIdCardNum(stockHolderBO.getString("idCardNum"));
  stockHolder.setEmail(stockHolderBO.getString("email"));
  stockHolder.setAddress(stockHolderBO.getString("address"));
  } catch (Exception e) {
  e.printStackTrace();
  stockHolder = null;
  }
  }
  return stockHolder;
  }

  同样,为Stock定义一个方法实现DataObject与JavaBean之间的相互转化,这里从略。

  然后创建一个StockAccount的实例,并把StockHolder的实例sh和Stock的实例st 放到StockAccount类中。

  最后调用Hibernate的Session.persiste等方法将StockAccount数据存储到数据库中。

 

[1] [2] [3] [4] [5
责任编辑:李伟
【字体: 】【打印此文】【关闭窗口】【论坛
相关信息
相关评论