颠覆软件

关注 : 架构与设计,敏捷,快速开发,项目管理,执行力,SSH,RoR

Archive for the ‘hibernate’ Category

简单就是美 — 简化hibernate,简化dao

May 13, 2007

key word : hibernate,dao

一。简化hibernate
首先hibernate是一个优秀的ORM工具(此话鉴定为废话:))
其次,按照20/80的规律,有80%的问题不需要那20%学习起来比较麻烦的东西。

很多人在用hibernate的时候一定把关系作为精华来学习,比如一对多,多对一,以及多对多,认为只有熟练运用这个才是对hibernate的真正掌握。
说实话,这个想法从技术的角度讲有点道理,问题是很多人对这些始终是一头雾水,反正不要好看,我现在仍然是一头雾水,今天我终于给自己
解放了出来,我回头去看自己的项目,发现N多的时候100%的不要关系(在 hibernate中)也不会出人命,而且效果很好。

现在,每个mapping文件中没有了set,list,map,我相信一定有N多人说我这个不符合OO什么的,不过大家反过来想,在我的项目组中会有一个明显
的好处就是我将问题简化了,
大家都会做,比如Org与User的关系,1:N的关系,我不用考虑这个,直接手工去维护,dao.save(org);user.setOrgId(“11″);dao.save(user);

有一段时间我依次问各个项目组,你们的hibernate中用到了关联操作了么,回答清一色的“NO”,看来大家都在无意识的回避这个陷阱,呵呵,
很合吾意。

二.简化dao

可能是受到appfuse的影响,一个service就有一个dao,现在从实际的角度来看仍然觉得没有太大的必要,当然,如果你是类似测试驱动的想法
那么可能另当别论。现在我更喜欢一个通用的dao全部搞定,确实舒服。

service中的操作全部调用通用dao(getObjects(),saveObject(),updateObject(),removeObject())

public BeanValue saveItem(RequestMap rMap) {
        BeanValue value 
= null;
        
try {
            log.info(
=====begin to save alexItem object);
            value 
= new BeanValue();
            AlexItem alexItem 
= (AlexItem) BeanUtil.convertObject(AlexItem.class, rMap.getMap());
            dao.saveObject(alexItem);
            log.info(
=====end to save alexItem object);
            value.addRequestMap(
admin,alexItem);
            value.setForword(
success);
        }
 catch (BaseException e) {
           value.addErrorMap(
errorName,e);
           value.setForword(
error);
        }

        
return value;
    }

愿意听听各位在项目中的做法。

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

[zt] Hibernate+Spring 对DAO的处理实列!

January 25, 2007

key words : hibernate spring dao

come from : http://lpacec.javaeye.com/blog/46220

   1.  package infoweb.dao;
   
2.
   
3import java.util.List;
   
4import java.util.Iterator;
   
5.
   
6import infoweb.pojo.Info;
   
7.
   
8import net.sf.hibernate.HibernateException;
   
9import net.sf.hibernate.Query;
  
10import net.sf.hibernate.Session;
  
11.
  
12import org.springframework.orm.hibernate.HibernateCallback;
  
13import org.springframework.orm.hibernate.support.HibernateDaoSupport;
  
14.
  
15/**
  16.  *

      Title:

  17.  *

      Description:

  18.  *

      Copyright: Copyright (c) 2004

  19.  *

      Company:

  20.  * 
@author 段洪杰
  21.  * 
@version 1.0
  22.  
*/

  
23.
  
24public class InfoDAOImpl extends HibernateDaoSupport implements IInfoDAO {
  
25.   /**
  26.    * 构造函数
  27.    
*/

  
28.   public InfoDAOImpl() {
  
29.     super();
  
30.   }

  
31.
  
32.   /**
  33.    * 增加记录
  34.    * 
@param info Info
  35.    
*/

  
36.   public void setInfo(Info info) throws Exception {
  
37.     getHibernateTemplate().save(info);
  
38.   }

  
39.
  
40.   /**
  41.    * 通过ID取得记录
  42.    * 
@param id String
  43.    * 
@return Info
  44.    
*/

  
45.   public Info getInfoById(String id) throws Exception {
  
46.     Info info = (Info) getHibernateTemplate().load(Info.class, id);
  
47.     return info;
  
48.   }

  
49.
  
50.   /**
  51.    * 修改记录
  52.    * 
@param Info info
  53.    
*/

  
54.   public void modifyInfo(Info info) throws Exception {
  
55.     getHibernateTemplate().update(info);
  
56.   }

  
57.
  
58.   /**
  59.    * 删除记录
  60.    * 
@param Info info
  61.    
*/

  
62.   public void removeInfo(Info info) throws Exception {
  
63.     getHibernateTemplate().delete(info);
  
64.   }

  
65.
  
66.   ////////////////////////////////////////////////////////      
  67.   /////                                                ///      
  68.   /////以下部份不带审核功能                              ///      
  69.   /////                                                ///      
  70.   ////////////////////////////////////////////////////////      
  71.
  
72.   /**
  73.    * 取记录总数
  74.    * 
@return int
  75.    
*/

  
76.   public int getInfosCount() throws Exception {
  
77.     int count = 0;
  
78.     String queryString = select count(*) from Info;
  
79.     count = ((Integer) getHibernateTemplate().iterate(queryString).next()).
  
80.             intValue();
  
81.     return count;
  
82.   }

  
83.
  
84.   /**
  85.    * 取所有记录集合
  86.    * 
@return Iterator
  87.    
*/

  
88.   public Iterator getAllInfos() throws Exception {
  
89.     Iterator iterator = null;
  
90.     String queryString =  select info from Info as info order by info.id desc;
  
91.     List list = getHibernateTemplate().find(queryString);
  
92.     iterator = list.iterator();
  
93.     return iterator;
  
94.   }

  
95.
  
96.   /**
  97.    * 取记录集合
  98.    * 
@return Iterator
  99.    * 
@param int position, int length
 100.    
*/

 
101.   public Iterator getInfos(int position, int length) throws Exception {
 
102.     Iterator iterator = null;
 
103.     String queryString =  select info from Info as info order by info.id desc;
 
104.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
105.     //设置游标的起始点      
 106.     query.setFirstResult(position);
 
107.     //设置游标的长度      
 108.     query.setMaxResults(length);
 
109.     //记录生成      
 110.     List list = query.list();
 
111.     //把查询到的结果放入迭代器      
 112.     iterator = list.iterator();
 
113.     return iterator;
 
114.   }

 
115.
 
116.   /**
 117.    * 取第一条记录
 118.    * 
@throws Exception
 119.    * 
@return Station
 120.    
*/

 
121.   public Info getFirstInfo() throws Exception {
 
122.     Iterator iterator = null;
 
123.     Info info = null;
 
124.     String queryString = select info from Info as info order by info.id desc;
 
125.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
126.     //记录生成      
 127.     List list = query.list();
 
128.     //把查询到的结果放入迭代器      
 129.     iterator = list.iterator();
 
130.     if (iterator.hasNext()) {
 
131.       info = (Info) iterator.next();
 
132.     }

 
133.     return info;
 
134.   }

 
135.
 
136.   /**
 137.    * 取最后一条记录
 138.    * 
@throws Exception
 139.    * 
@return Station
 140.    
*/

 
141.   public Info getLastInfo() throws Exception {
 
142.     Iterator iterator = null;
 
143.     Info info = null;
 
144.     String queryString = select info from Info as info order by info.id asc;
 
145.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
146.     //记录生成      
 147.     List list = query.list();
 
148.     //把查询到的结果放入迭代器      
 149.     iterator = list.iterator();
 
150.     if (iterator.hasNext()) {
 
151.       info = (Info) iterator.next();
 
152.     }

 
153.     return info;
 
154.
 
155.   }

 
156.
 
157.   ////////////////////////////////////////////////////////      
 158.   /////                                                ///      
 159.   ///// 以下部份表中要有特定字段才能正确运行   个人和企业     ///      
 160.   /////                                                ///      
 161.   ////////////////////////////////////////////////////////      
 162.
 
163.   /**
 164.    * 取符合条件记录总数, [表中要有 isperson 字段]
 165.    * 
@return int
 166.    * 
@param int isPerson
 167.    
*/

 
168.
 
169.   public int getInfosCountByIsperson(int isPerson) throws Exception {
 
170.     int count = 0;
 
171.     String queryString =
 
172.         select count(*) from Info as info where info.isperson = + isPerson;
 
173.     count = ((Integer) getHibernateTemplate().iterate(queryString).next()).
 
174.             intValue();
 
175.     return count;
 
176.   }

 
177.
 
178.   /**
 179.    * 取所有符合条件记录集合, 模糊查询条件.[表中要有 isperson 字段]
 180.    * 
@return Iterator
 181.    * 
@param int isPerson
 182.    
*/

 
183.
 
184.   public Iterator getAllInfosByIsperson(int isPerson) throws Exception {
 
185.     Iterator iterator = null;
 
186.     String queryString =  select info from Info as info where info.isperson = +
 
187.                          isPerson +  order by info.id desc;
 
188.     List list = getHibernateTemplate().find(queryString);
 
189.     //把查询到的结果放入迭代器      
 190.     iterator = list.iterator();
 
191.     return iterator;
 
192.   }

 
193.
 
194.   /**
 195.    * 取符合条件记录集合, 模糊查询条件.[表中要有 isperson 字段]
 196.    * 
@return Iterator
 197.    * 
@param int isPerson,int position, int length
 198.    
*/

 
199.
 
200.   public Iterator getInfosByIsperson(int isPerson, int position, int length) throws
 
201.       Exception {
 
202.     Iterator iterator = null;
 
203.     String queryString =  select info from Info as info where info.isperson = +
 
204.                          isPerson +  order by info.id desc;
 
205.     //创建查询      
 206.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
207.     //设置游标的起始点      
 208.     query.setFirstResult(position);
 
209.     //设置游标的长度      
 210.     query.setMaxResults(length);
 
211.     //记录生成      
 212.     List list = query.list();
 
213.     //把查询到的结果放入迭代器      
 214.     iterator = list.iterator();
 
215.     return iterator;
 
216.   }

 
217.
 
218.   ////////////////////////////////////////////////////////      
 219.   /////                                                ///      
 220.   ///// 以下部份表中要有特定字段才能正确运行   查询部份      ///      
 221.   /////                                                ///      
 222.   ///////////////////////////////////////////////////////      
 223.   /**
 224.    * 取符合条件记录总数, 模糊查询条件.[表中要有 title 字段]
 225.    * 
@return int
 226.    * 
@param String text
 227.    
*/

 
228.   public int getInfosCount(String text) throws Exception {
 
229.     int count = 0;
 
230.     count = ((Integer) getHibernateTemplate().iterate(
 
231.         select count(*) from Info as info where info.title like ’% + text +
 
232.         %’).next()).intValue();
 
233.     return count;
 
234.   }

 
235.
 
236.   /**
 237.    * 取所有符合条件记录集合, 模糊查询条件.[表中要有 title 字段]
 238.    * 
@return Iterator
 239.    * 
@param String text
 240.    
*/

 
241.
 
242.   public Iterator getAllInfos(String text) throws Exception {
 
243.     Iterator iterator = null;
 
244.     String queryString =
 
245.          select info from Info as info where info.title like ’% + text +
 
246.         %’ order by info.id desc;
 
247.     //创建查询      
 248.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
249.     //记录生成      
 250.     List list = query.list();
 
251.     //把查询到的结果放入迭代器      
 252.     iterator = list.iterator();
 
253.     return iterator;
 
254.   }

 
255.
 
256.   /**
 257.    * 取符合条件记录集合, 模糊查询条件.[表中要有 title 字段]
 258.    * 
@return Iterator
 259.    * 
@param String text,int position, int length
 260.    
*/

 
261.   public Iterator getInfos(String text, int position, int length) throws
 
262.       Exception {
 
263.     Iterator iterator = null;
 
264.     String queryString =
 
265.          select info from Info as info where info.title like ’% + text +
 
266.         %’ order by info.id desc;
 
267.
 
268.     //创建查询      
 269.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
270.     //设置游标的起始点      
 271.     query.setFirstResult(position);
 
272.     //设置游标的长度      
 273.     query.setMaxResults(length);
 
274.     //记录生成      
 275.     List list = query.list();
 
276.     //把查询到的结果放入迭代器      
 277.     iterator = list.iterator();
 
278.     return iterator;
 
279.   }

 
280.
 
281.   ////////////////////////////////////////////////////////      
 282.   /////                                                ///      
 283.   ///// 以下部份表中要有特定字段才能正确运行   注册相关      ///      
 284.   /////                                                ///      
 285.   ////////////////////////////////////////////////////////      
 286.
 
287.   /**
 288.    * 取符合条件记录总数.[ 表中要有 registername 字段]
 289.    * 
@return int
 290.    * 
@param String text
 291.    
*/

 
292.   public int getInfosCountByRegisterName(String registerName) throws Exception {
 
293.     int count = 0;
 
294.     count = ((Integer) getHibernateTemplate().iterate(
 
295.         select count(*) from Info as info where info.registername = ’ +
 
296.         registerName + ).next()).intValue();
 
297.     return count;
 
298.   }

 
299.
 
300.   /**
 301.    * 通过注册名取得一条记录,如有多条,只取第一条.[表中要有 registername字段]
 302.    * 
@param registername String
 303.    * 
@return Info
 304.    
*/

 
305.   public Info getInfoByRegisterName(String registerName) throws Exception {
 
306.     Iterator iterator = null;
 
307.     Info info = null;
 
308.     String queryString =
 
309.          select info from Info as info where info.registername=’ +
 
310.         registerName + ‘ order by info.id desc;
 
311.     //创建查询      
 312.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
313.     //记录生成      
 314.     List list = query.list();
 
315.     //把查询到的结果放入迭代器      
 316.     iterator = list.iterator();
 
317.     if (iterator.hasNext()) {
 
318.       info = (Info) iterator.next();
 
319.     }

 
320.     return info;
 
321.   }

 
322.
 
323.   /**
 324.    * 通过注册名取得所有记录集合.[表中要有 registername字段]
 325.    * 
@param registername String
 326.    * 
@return Iterator
 327.    
*/

 
328.   public Iterator getAllInfosByRegisterName(String registerName) throws
 
329.       Exception {
 
330.     Iterator iterator = null;
 
331.     String queryString =
 
332.          select info from Info as info where info.registername=’ +
 
333.         registerName + ‘ order by info.id desc;
 
334.     //创建查询      
 335.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
336.     //记录生成      
 337.     List list = query.list();
 
338.     //把查询到的结果放入迭代器      
 339.     iterator = list.iterator();
 
340.     return iterator;
 
341.   }

 
342.
 
343.   /**
 344.    * 通过注册名取得记录列表.[表中要有 registername字段]
 345.    * 
@param registername String
 346.    * 
@return Iterator
 347.    
*/

 
348.   public Iterator getInfosByRegisterName(String registerName, int position,
 
349.                                          int length) throws Exception {
 
350.     Iterator iterator = null;
 
351.     String queryString =
 
352.          select info from Info as info where info.registername=’ +
 
353.         registerName + ‘ order by info.id desc;
 
354.     //创建查询      
 355.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
356.     //设置游标的起始点      
 357.     query.setFirstResult(position);
 
358.     //设置游标的长度      
 359.     query.setMaxResults(length);
 
360.     //记录生成      
 361.     List list = query.list();
 
362.     //把查询到的结果放入迭代器      
 363.     iterator = list.iterator();
 
364.     return iterator;
 
365.   }

 
366.
 
367.   ////////////////////////////////////////////////////////      
 368.   /////                                                ///      
 369.   ///// 以下部份表中要有特定字段才能正确运行     树型版块     ///      
 370.   /////                                                ///      
 371.   ////////////////////////////////////////////////////////      
 372.
 
373.   /**
 374.    * 取记录总数.[ 表中要有 board_id 字段]
 375.    * 
@return int
 376.    * 
@param String boardId
 377.    
*/

 
378.   public int getInfosCountByBoard(String boardId) throws Exception {
 
379.     int count = 0;
 
380.
 
381.     count = ((Integer) getHibernateTemplate().iterate(
 
382.         select count(*) from Info as info where info.boardId = ’ + boardId +
 
383.         ).next()).intValue();
 
384.
 
385.     return count;
 
386.   }

 
387.
 
388.   /**
 389.    * 通过版块名取得所有记录集合.[表中要有 board_id字段]
 390.    * 
@param BoardId String
 391.    * 
@return Iterator
 392.    
*/

 
393.   public Iterator getAllInfosByBoard(String boardId) throws Exception {
 
394.     Iterator iterator = null;
 
395.     String queryString =  select info from Info as info where info.boardId=’ +
 
396.                          boardId + ‘ order by info.id desc;
 
397.     //创建查询      
 398.     Query query = getHibernateTemplate().createQuery(getSession(), queryString);
 
399.     //记录生成      
 400.     List list = query.list();
 
401.     //把查询到的结果放入迭代器      
 402.     iterator = list.iterator();
 
403.     return iterator;

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

MiddleGen中配置hibernate的many to many属性

December 7, 2006

key words: MiddleGen,hibernate,many to many,多对多 如果你有如下表结构 user(user_id,user_name) role(role_id,role_name) user_role(id,user_id,role_id) 那么默认MiddleGen生成的是两个一对多,但我们更多的情况是用many to many 需要修改middlegen的build.xml文件

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

Hibernate的Fetch

December 1, 2006

越来越发现其实掌握 hibernate并不容易,Spring用起来其实简单多了,但是在用hibernate的时候真的是需要一定的时间积累,对一个项目组来说如果采用hibernate最好有一个对hibernate比较清楚的人否则碰到问题就会成为项目的风险。
我想告诉各位的是,掌握hibernate可能比你预期的难多了,当你轻松的告诉我,hibernate很简单的时候该是你自己多反省了. (只有一种情况例外,你是一个牛人)

好了,一个引子废话那么多,其实今天只是想先说一说hibernate里的Fetch的作用.

大家都知道,在hibernate里为了性能考虑,引进了lazy的概念,这里我们以Parent和Child为模型来说明,

public class Parent implements Serializable {

/** identifier field */
private Long id;

/** persistent field */
private List childs;

//skip all getter/setter method

}

public class Child implements Serializable {

/** identifier field */
private Long id;

/** persistent field */
private net.foxlog.model.Parent parent;

//skip all getter/setter method

}
在我们查询Parent对象的时候,默认只有Parent的内容,并不包含childs的信息,如果在Parent.hbm.xml里设置lazy=”false”的话才同时取出关联的所有childs内容.

问题是我既想要hibernate默认的性能又想要临时的灵活性该怎么办?  这就是fetch的功能。我们可以把fetch与lazy=”true”的关系类比为事务当中的编程式事务与声明式事务,不太准确,但是大概是这个意思。

总值,fetch就是在代码这一层给你一个主动抓取得机会.

Parent parent = (Parent)hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
Query q 
= session.createQuery(
from Parent as parent +
 left outer join fetch parent.childs  +
 where parent.id = :id
);
q.setParameter(
id,new Long(15));
return (Parent)q.uniqueResult();
}

});

Assert.assertTrue(parent.getChilds().size() > 0);

你可以在lazy=”true”的情况下把fetch去掉,就会报异常. 当然,如果lazy=”false”就不需要fetch了

有一个问题,使用Fetch会有重复记录的现象发生,我们可以理解为Fetch实际上不是为Parent服务的,而是为Child服务的.所以直接取Parent会有不匹配的问题.

参考一下下面的这篇文章
Hibernate集合初始化

======================================================================

update:以上有些结论错误,实际上在hibernate3.2.1版本下测试,可以不出现重复记录,

public void testNPlusOne() throws Exception{
List list 
= (List)hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
Query q 
= session.createQuery(
select distinct p from net.foxlog.model.Parent p inner join fetch p.childs
);
return q.list();
}

});

//((Parent)(list.get(0))).getChilds();
        System.out.println(list size =  + list.size());
for(int i=0;i<list.size();i++){
Parent p 
= (Parent)list.get(i);
System.out.println(
===parent =  + p);
System.out.println(
===parent’s child’s length =  + p.getChilds().size());
}

}

打印结果如下:

Hibernate: select distinct parent0_.id as id2_0_, childs1_.id as id0_1_, childs1_.parent_id as parent2_0_1_, childs1_.parent_id as parent2_0__, childs1_.id as id0__ from parent parent0_ inner join child childs1_ on parent0_.id=childs1_.parent_id
list size 
= 3
===parent = net.foxlog.model.Parent@1401d28[id=14]
===parents childs length = 1
===parent = net.foxlog.model.Parent@14e0e90[id=15]
===parents childs length = 2
===parent = net.foxlog.model.Parent@62610b[id=17]
===parents childs length = 3

另外,如果用open session in view模式的话一般不用fetch,但首先推荐fetch,如果非用的话因为有N+1的现象,所以可以结合batch模式来改善下性能.

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

[zt]hibernate复合主键

November 9, 2006

key words:hibernate,复合主键,composite-id

基于业务需求,您会需要使用两个字段来作复合主键,例如在User数据表中,您也许会使用“name”“phone”两个字段来定义复合主键。

假设您这么建立User表格:

CREATE TABLE user (

name VARCHAR(100NOT NULL,

phone VARCHAR(50NOT NULL,

age INT,

PRIMARY KEY(name, phone)

);

在表格中,“name”“age”被定义为复合主键,在映像时,您可以让User类别直接带有“name”“age”这两个属性,而Hibernate要求复合主键类别要实作Serializable接口,并定义equals()hashCode()方法:

User.java

package onlyfun.caterpillar;

import java.io.Serializable;

import org.apache.commons.lang.builder.EqualsBuilder;

import org.apache.commons.lang.builder.HashCodeBuilder;

// 复合主键类的对应类别必须实作Serializable接口

public class User implements Serializable {

private String name;

private String phone;

private Integer age;

public User() {

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getPhone() {

return phone;

}

public void setPhone(String phone) {

this.phone = phone;

}

// 必须重新定义equals()与hashCode()

public boolean equals(Object obj) {

if(obj == this) {

return true;

}

if(!(obj instanceof User)) {

return false;

}

User user = (User) obj;

return new EqualsBuilder()

.append(this.name, user.getName())

.append(this.phone, user.getPhone())

.isEquals();

}

public int hashCode() {

return new HashCodeBuilder()

.append(this.name)

.append(this.phone)

.toHashCode();

}

}

equals()hashCode()方法被用作两笔不同数据的识别依据;接着您可以使用<composite-id>在映射文件中定义复合主键与对象的属性对应:

User.hbm.xml

<?xml version=”1.0″ encoding=”utf-8″?>

<!DOCTYPE hibernate-mapping

PUBLIC ”-//Hibernate/Hibernate Mapping DTD 3.0//EN”

“http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd”>

<hibernate-mapping>

<class name=”onlyfun.caterpillar.User” table=”user”>

<composite-id>

<key-property name=”name”

column=”name”

type=”java.lang.String”/>

<key-property name=”phone”

column=”phone”

type=”java.lang.String”/>

</composite-id>

<property name=”age” column=”age” type=”java.lang.Integer”/>

</class>

</hibernate-mapping>

在储存数据方面,复合主键的储存没什么区别,现在的问题在于如何依据复合主键来查询数据,例如使用load()方法,您可以创建一个User实例,并设定复合主键对应的属性,接着再透过load()查询对应的数据,例如:

User user = new User();

user.setName(bush);

user.setPhone(0970123456);

Session session = sessionFactory.openSession();

// 以实例设定复合主键并加载对应的数据

user 
= (User) session.load(User.class, user);

System.out.println(user.getAge() + \t +

user.getName() + \t +

user.getPhone());

session.close();

 

可以将主键的信息独立为一个类别,例如:

UserPK.java

package onlyfun.caterpillar;

import java.io.Serializable;

import org.apache.commons.lang.builder.EqualsBuilder;

import org.apache.commons.lang.builder.HashCodeBuilder;

public class UserPK implements Serializable {

private String name;

private String phone;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getPhone() {

return phone;

}

public void setPhone(String phone) {

this.phone = phone;

}

public boolean equals(Object obj) {

if(obj == this) {

return true;

}

if(!(obj instanceof User)) {

return false;

}

UserPK pk = (UserPK) obj;

return new EqualsBuilder()

.append(this.name, pk.getName())

.append(this.phone, pk.getPhone())

.isEquals();

}

public int hashCode() {

return new HashCodeBuilder()

.append(this.name)

.append(this.phone)

.toHashCode();

}

}

现在User类别的主键信息被分离出来了,例如:

User.java

package onlyfun.caterpillar;

import java.io.Serializable;

public class User implements Serializable {

private UserPK userPK; // 主键

private Integer age;

public User() {

}

public UserPK getUserPK() {

return userPK;

}

public void setUserPK(UserPK userPK) {

this.userPK = userPK;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

}

在映像文件方面,需要指定主键类的信息,例如:

User.hbm.xml

<?xml version=”1.0″ encoding=”utf-8″?>

<!DOCTYPE hibernate-mapping

PUBLIC ”-//Hibernate/Hibernate Mapping DTD 3.0//EN”

“http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd”>

<hibernate-mapping>

<class name=”onlyfun.caterpillar.User” table=”user”>

<composite-id name=”userPK”

class=”onlyfun.caterpillar.UserPK”

unsaved-value=”any”>

<key-property name=”name”

column=”name”

type=”java.lang.String”/>

<key-property name=”phone”

column=”phone”

type=”java.lang.String”/>

</composite-id>

<property name=”age” column=”age” type=”java.lang.Integer”/>

</class>

</hibernate-mapping>

在查询数据时,必须指定主键信息,例如:

UserPK pk = new UserPK();

pk.setName(bush);

pk.setPhone(0970123456);

Session session = sessionFactory.openSession();

// 以主键类实例设定复合主键并加载对应的数据

User user 
= (User) session.load(User.class, pk);

System.out.println(user.getAge() + \t +

user.getUserPK().getName() + \t +

user.getUserPK().getPhone());

session.close();

=================================================
再参考robbin的一篇文章
一个简单的复合主键的做关联类的例子

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

用通配符解决mappingResources的繁琐配置

November 9, 2006

key words:mappingResources,通配符,mappingDirectoryLocations

平时写mapping的文件需要一个一个的放到配置文件里,比如

   1. <property name=”mappingResources”>
2.             
<list>
3.                 
<value>net/foxlog/model/Classes.hbm.xml</value>
4.                 
<value>net/foxlog/model/Parent.hbm.xml</value>
5.                 
<value>net/foxlog/model/Child.hbm.xml</value>
6.                 
<value>net/foxlog/model/User.hbm.xml</value>
7.             
</list>
8.         
</property>  

可以用更一步到位的方法:

   1. <property name=”mappingDirectoryLocations”>
2.             
<list>
3.                 
<value>classpath*:/org/springside/bookstore/commons/model/hbm</value>
4.             
</list>
5.         
</property>  

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

Hibernate的load错误,你碰到过这样的问题么?

November 7, 2006

key words:hibernate,load,session.get,session.load()

public class Parent implements Serializable {

/** identifier field */
private Long id;

/** persistent field */
private List childs;

/** full constructor */
public Parent(Long id, List childs) {
this.id = id;
this.childs = childs;
}

/** default constructor */
public Parent() {
}

/**
*            @hibernate.id
*             generator-class=”assigned”
*             type=”java.lang.Long”
*             column=”id”
*
*/
public Long getId() {
return this.id;
}

public void setId(Long id) {
this.id = id;
}

/**
*            @hibernate.set
*             lazy=”true”
*             inverse=”true”
*             cascade=”none”
*            @hibernate.collection-key
*             column=”parent_id”
*            @hibernate.collection-one-to-many
*             class=”net.foxlog.model.Child”
*
*/
public List getChilds() {
return this.childs;
}

public void setChilds(List childs) {
this.childs = childs;
}

public String toString() {
return new ToStringBuilder(this)
.append(
id, getId())
.toString();
}

public boolean equals(Object other) {
if ( !(other instanceof Parent) ) return false;
Parent castOther 
= (Parent) other;
return new EqualsBuilder()
.append(
this.getId(), castOther.getId())
.isEquals();
}

public int hashCode() {
return new HashCodeBuilder()
.append(getId())
.toHashCode();
}

}

Parent parent = (Parent)session.load(Parent.class,new Integer(7));
运行提示出错,”can’t get Entity..”

知道是什么低级错误么?  其实很弱智的东西,但是不注意还就会出现,呵呵,答案如下:


Parent parent = (Parent)session.load(Parent.class,new Long(7))

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

[zt]hibernate二级缓存攻略

October 23, 2006

转自 javaEye
很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了。
我的经验主要来自hibernate2.1版本,基本原理和3.0、3.1是一样的,请原谅我的顽固不化。

hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。

二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查询缓存,加上
hibernate.cache.use_query_cache=true

缓存可以简单的看成一个Map,通过key在缓存里面找value。

Class的缓存
对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是 iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。假设是读写缓存,需要设置:
<cache usage=”read-write”/>
如果你使用的二级缓存实现是ehcache的话,需要配置ehcache.xml
<cache name=”com.xxx.pojo.Foo” maxElementsInMemory=”500″ eternal=”false” timeToLiveSeconds=”7200″ timeToIdleSeconds=”3600″ overflowToDisk=”true” />
其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO)的超时时间,如果eternal=”false”,超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put 的元素超过500个时,如果overflowToDisk=”true”,就会把缓存中的部分数据保存在硬盘上的临时文件里面。
每个需要缓存的class都要这样配置。如果你没有配置,hibernate会在启动的时候警告你,然后使用defaultCache的配置,这样多个class会共享一个配置。
当某个ID通过hibernate修改时,hibernate会知道,于是移除缓存。
这样大家可能会想,同样的查询条件,第一次先list,第二次再iterate,就可以使用到缓存了。实际上这是很难的,因为你无法判断什么时候是第一次,而且每次查询的条件通常是不一样的,假如数据库里面有100条记录,id从1到100,第一次list的时候出了前50个id,第二次 iterate的时候却查询到30至70号id,那么30-50是从缓存里面取的,51到70是从数据库取的,共发送1+20条sql。所以我一直认为 iterate没有什么用,总是会有1+N的问题。
(题外话:有说法说大型查询用list会把整个结果集装入内存,很慢,而iterate只select id比较好,但是大型查询总是要分页查的,谁也不会真的把整个结果集装进来,假如一页20条的话,iterate共需要执行21条语句,list虽然选择若干字段,比iterate第一条select id语句慢一些,但只有一条语句,不装入整个结果集hibernate还会根据数据库方言做优化,比如使用mysql的limit,整体看来应该还是 list快。)
如果想要对list或者iterate查询的结果缓存,就要用到查询缓存了

查询缓存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
<cache name=”net.sf.hibernate.cache.StandardQueryCache”
maxElementsInMemory=”50″ eternal=”false” timeToIdleSeconds=”3600″
timeToLiveSeconds=”7200″ overflowToDisk=”true”/>
<cache name=”net.sf.hibernate.cache.UpdateTimestampsCache”
maxElementsInMemory=”5000″ eternal=”true” overflowToDisk=”true”/>
然后
query.setCacheable(true);//激活查询缓存
query.setCacheRegion(“myCacheRegion”);//指定要使用的cacheRegion,可选
第二行指定要使用的cacheRegion是myCacheRegion,即你可以给每个查询缓存做一个单独的配置,使用setCacheRegion来做这个指定,需要在ehcache.xml里面配置它:
<cache name=”myCacheRegion” maxElementsInMemory=”10″ eternal=”false” timeToIdleSeconds=”3600″ timeToLiveSeconds=”7200″ overflowToDisk=”true” />
如果省略第二行,不设置cacheRegion的话,那么会使用上面提到的标准查询缓存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

对于查询缓存来说,缓存的key是根据hql生成的sql,再加上参数,分页等信息(可以通过日志输出看到,不过它的输出不是很可读,最好改一下它的代码)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
参数是”tiger%”,那么查询缓存的key*大约*是这样的字符串(我是凭记忆写的,并不精确,不过看了也该明白了):
select * from cat c where c.name like ? , parameter:tiger%
这样,保证了同样的查询、同样的参数等条件下具有一样的key。
现在说说缓存的value,如果是list方式的话,value在这里并不是整个结果集,而是查询出来的这一串ID。也就是说,不管是list方法还是iterate方法,第一次查询的时候,它们的查询方式很它们平时的方式是一样的,list执行一条sql,iterate执行1+N条,多出来的行为是它们填充了缓存。但是到同样条件第二次查询的时候,就都和iterate的行为一样了,根据缓存的key去缓存里面查到了value,value是一串id,然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。
可以看出来,查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候,都是既填充查询缓存又填充class缓存的。
这里还有一个很容易被忽视的重要问题,即打开查询缓存以后,即使是list方法也可能遇到1+N的问题!相同条件第一次list的时候,因为查询缓存中找不到,不管class缓存是否存在数据,总是发送一条sql语句到数据库获取全部数据,然后填充查询缓存和class缓存。但是第二次执行的时候,问题就来了,如果你的class缓存的超时时间比较短,现在class缓存都超时了,但是查询缓存还在,那么list方法在获取id串以后,将会一个一个去数据库load!因此,class缓存的超时时间一定不能短于查询缓存设置的超时时间!如果还设置了发呆时间的话,保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况,比如class缓存被程序强制evict了,这种情况就请自己注意了。

另外,如果hql查询包含select字句,那么查询缓存里面的value就是整个结果集了。

当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢?
hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。
当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。
可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。

Collection缓存
需要在hbm的collection里面设置
<cache usage=”read-write”/>
假如class是Cat,collection叫children,那么ehcache里面配置
<cache name=”com.xxx.pojo.Cat.children”
maxElementsInMemory=”20″ eternal=”false” timeToIdleSeconds=”3600″ timeToLiveSeconds=”7200″
overflowToDisk=”true” />
Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。
这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新。

缓存策略
只读缓存(read-only):没有什么好说的
读/写缓存(read-write):程序可能要的更新数据
不严格的读/写缓存(nonstrict-read-write):需要更新数据,但是两个事务更新同一条记录的可能性很小,性能比读写缓存好
事务缓存(transactional):缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境,这个我没有怎么研究过

读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁,其他事务如果去取相应的缓存数据,发现被锁住了,然后就直接取数据库查询。
在hibernate2.1的ehcache实现中,如果锁住部分缓存的事务发生了异常,那么缓存会一直被锁住,直到60秒后超时。
不严格读写缓存不锁定缓存中的数据。

使用二级缓存的前置条件
你的hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。你操作数据库必需直接通过 hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。hibernate3.0的大批量更新和删除是不更新二级缓存的,但是据说3.1已经解决了这个问题。
这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧。
SessionFactory也提供了移除缓存的方法,你一定要自己写一些JDBC的话,可以调用这些方法移除缓存,这些方法是:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
不过我不建议这样做,因为这样很难维护。比如你现在用JDBC批量更新了某个表,有3个查询缓存会用到这个表,用evictQueries (String cacheRegion)移除了3个查询缓存,然后用evict(Class persistentClass)移除了class缓存,看上去好像完整了。不过哪天你添加了一个相关查询缓存,可能会忘记更新这里的移除代码。如果你的 jdbc代码到处都是,在你添加一个查询缓存的时候,还知道其他什么地方也要做相应的改动吗?

—————————————————-

总结:
不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据。
如果受不了hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧。
在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。

终于写完了,好累……

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

MiddleGen怪问题,生成的hbm.xml文件的数据类型和数据库类型不一致

February 24, 2006

keyword:MySql字段,Hibernate session,MiddleGen

一.MySql字段敏感

这几天怪问题真是不少,这不刚建的一个数据库的表用MiddleGen批量生成hbm.xml文件居然和数据库的数据类型不一致.
MySql建表语句如下:

drop table if exists book;

/*==============================================================*/
/* Table: book                                                  */
/*==============================================================*/
create table book
(
id                             
int                            not null,
name                           
varchar(100),
author                         
varchar(100),
date                           date,
price                          
int,
primary key (id)
)
comment
=“Book table”
type 
= InnoDB;
生成的hbm.xml文件如下:

<?xml version=”1.0″?>
<!DOCTYPE hibernate-mapping PUBLIC
“-//Hibernate/Hibernate Mapping DTD 2.0//EN”
“http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd” 
>

<hibernate-mapping>
<!–
Created by the Middlegen Hibernate plugin 2.1

http://boss.bekk.no/boss/middlegen/

http://www.hibernate.org/

–>

<class
name=”net.foxlog.prj.Book”
table
=”book”
>
<meta attribute=”class-description” inherit=”false”>
@hibernate.class
table=”book”
</meta>

<id
name=”id”
type
=”java.lang.Long”
column
=”id”
>
<meta attribute=”field-description”>
@hibernate.id
generator-class=”assigned”
type=”java.lang.Long”
column=”id”

</meta>
<generator class=”assigned” />
</id>

<property
name=”name”
type
=”java.lang.String”
column
=”name”
length
=”100″
>
<meta attribute=”field-description”>
@hibernate.property
column=”name”
length=”100″
</meta>
</property>
<property
name=”author”
type
=”java.lang.String”
column
=”author”
length
=”100″
>
<meta attribute=”field-description”>
@hibernate.property
column=”author”
length=”100″
</meta>
</property>
<property
name=”date”
type
=”java.sql.Date”
column
=”date”
length
=”10″
>
<meta attribute=”field-description”>
@hibernate.property
column=”date”
length=”10″
</meta>
</property>
<property
name=”price”
type
=”java.lang.String”
column
=”price”
length
=”10″
>
<meta attribute=”field-description”>
@hibernate.property
column=”price”
length=”10″
</meta>
</property>

<!– Associations –>

</class>
</hibernate-mapping>

注意到没有,id的类型变成了Long型了,而price居然变成了String了,晕啊.

各位碰到过这个问题么?

最后还是找到问题所在了,实际上是建表有问题,问题就出在字段的名称上,把id改为ID,price改为PRICE就没问题了!  MySql对id和price敏感? 不得而知,目前看来好像是这样.只是提醒我以后建表养成一个习惯,都用大写的就没问题了.
没想到一次测试中随便建的一个表发现了这么个有趣的事情  :)

二.Hibernate的session关闭问题
用hibernate的工具类获得session有没有碰到过session is closed的错误提示? 我又幸运的碰到这个问题了,呵呵,我怎么有那么多问题啊,晕了,我看来是问题先生了,我的一个同事上次也跟我说过这个事情,后来他没有正面解决这个,绕过去了,他用Spring去替自己解决了,呵呵,也够狠的.不过问题实际上是获得session的时候需要增加一个判断. 即 session.isOpen() == false;

DBUtil.java代码如下:

/**
* 返回一个可用的数据库Session连接
@return Hibernate中对数据库的Session连接
@throws HibernateException
*/
public static Session currentSession() throws HibernateException
{
Session s 
= (Session) session.get();
// Open a new Session, if this Thread has none yet
        if (null==|| s.isOpen()==false)//注意这里
{
= sessionFactory.openSession();
session.set(s);
}
return s;
}

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)

奇怪,hibernate-extensions生成的POJO没有equals和hashCode方法

February 17, 2006

到网上搜索了半天都说什么要在hbm.xml文件里写什么implements equals,但是心想如果都在这个里面手工写那还有什么方便之处啊.

原因终于找到,原来是高版本不行,我用的是2.1.2,而2.0.2则没问题,确切的说把hibernate-tools.jar换为2.0.2的即可

附配置说明:
不需要记复杂的命令,只要一次配置好Middlegen-Hibernate-r5目录下的build.xml文件即可,以后则需要运行
ant

ant hbm2java即可
注:前者生成数据库对应的所有hbm.xml文件,后者生成hbm.xml对应的所有POJO

build.xml配置如下:

<?xml version=”1.0″?>

<!–
This is a testing platform for the middlegen hibernate plugin. It is a stripped
down version of the samples application. At the moment it is only concerned
with the generation of the mapping documents so that various tests etc can be
done on the generated package.

David Channon

The DOCTYPE declaration declares the location of product-specific parts of the
Ant build file. You can change the values of these declarations to point to
other available files. This gives you an opportunity to choose what database.

Note that this syntax has nothing to do with Ant or Middlegen. This
is the standard way defined by w3c to dynamically include external
files in an XML document. Any decent XML parser will do the include
transparently. Try to open this file in Internet Explorer and see
for yourself.
–>

<!DOCTYPE project [
<!ENTITY database SYSTEM "file:./config/database/mysql.xml"
>
]>

<project name=”Middlegen Hibernate” default=”all” basedir=”.”>

<!– project name=”Middlegen Hibernate” default=”all” basedir=”.” –>

<property file=”${basedir}/build.properties”/>
<property name=”name” value=”bona”/>

<property name=”myPackage” value=”cn.com.chinagc.cpms.model.po”/>

<!– This was added because we were several people (in a course) deploying to same app server>
<property environment=”env”/>
<property name=”unique.name”                    value=”${name}.${env.COMPUTERNAME}”/
–>

<property name=”gui”                            value=”false”/>

<property name=”unique.name”                    value=”${name}”/>

<property name=”appxml.src.file”                value=”${basedir}/src/application.xml”/>
<property name=”lib.dir”                        value=”${basedir}/lib”/>
<property name=”src.dir”                        value=”${basedir}/src”/>
<property name=”java.src.dir”                   value=”${src.dir}/java”/>
<property name=”web.src.dir”                    value=”${src.dir}/web”/>

<property name=”build.dir”                      value=”${basedir}/build”/>
<property name=”build.java.dir”                 value=”${build.dir}/java”/>
<property name=”build.gen-src.dir”              value=”${build.dir}/gen-src”/>
<property name=”build.classes.dir”              value=”${build.dir}/classes”/>

&database;

<!– define the datasource.jndi.name in case the imported ejb file doesn’t –>
<property name=”datasource.jndi.name”           value=”${name}/datasource”/>

<path id=”lib.class.path”>
<pathelement path=”${database.driver.classpath}”/>
<fileset dir=”${lib.dir}”>
<include name=”*.jar”/>
</fileset>
<!– The middlegen jars –>
<!–fileset dir=”${basedir}/..”–>
<fileset dir=”${basedir}/middlegen-lib”>
<include name=”*.jar”/>
</fileset>
</path>

<target name=”init”>
<available property=”xdoclet1.2+” classname=”xdoclet.modules.hibernate.HibernateDocletTask” classpathref=”lib.class.path”/>
</target>

<!– =================================================================== –>
<!– Fails if XDoclet 1.2.x is not on classpath                          –>
<!– =================================================================== –>
<target name=”fail-if-no-xdoclet-1.2″ unless=”xdoclet1.2+”>
<fail>
You must download several jar files before you can build Middlegen.
</fail>
</target>

<!– =================================================================== –>
<!– Create tables                                                       –>
<!– =================================================================== –>
<target
name=”create-tables”
depends
=”init,fail-if-no-xdoclet-1.2,check-driver-present,panic-if-driver-not-present”
description
=”Create tables”
>
<echo>Creating tables using URL ${database.url}</echo>
<sql
classpath=”${database.driver.classpath}”
driver
=”${database.driver}”
url
=”${database.url}”
userid
=”${database.userid}”
password
=”${database.password}”
src
=”${database.script.file}”
print
=”true”
output
=”result.txt”
/>
</target>
<target name=”check-driver-present”>
<available file=”${database.driver.file}” type=”file” property=”driver.present”/>
</target>
<target name=”panic-if-driver-not-present” unless=”driver.present”>
<fail>
The JDBC driver you have specified by including one of the files in ${basedir}/config/database
doesn’t exist. You have to download this driver separately and put it in ${database.driver.file}
Please make sure you’re using a version that is equal or superior to the one we looked for.
If you name the driver jar file differently, please update the database.driver.file property
in the ${basedir}/config/database/xxx.xml file accordingly.
</fail>
</target>

<!– =================================================================== –>
<!– Run Middlegen                                                       –>
<!– =================================================================== –>
<target
name=”middlegen”
description
=”Run Middlegen”
unless
=”middlegen.skip”
depends
=”init,fail-if-no-xdoclet-1.2,check-driver-present,panic-if-driver-not-present”
>
<mkdir dir=”${build.gen-src.dir}”/>

<echo message=”Class path = ${basedir}”/>
<taskdef
name=”middlegen”
classname
=”middlegen.MiddlegenTask”
classpathref
=”lib.class.path”
/>

<middlegen
appname=”${name}”
prefsdir
=”${src.dir}”
gui
=”${gui}”
databaseurl
=”${database.url}”
initialContextFactory
=”${java.naming.factory.initial}”
providerURL
=”${java.naming.provider.url}”
datasourceJNDIName
=”${datasource.jndi.name}”
driver
=”${database.driver}”
username
=”${database.userid}”
password
=”${database.password}”
schema
=”${database.schema}”
catalog
=”${database.catalog}”
>

<!–
We can specify what tables we want Data generated for.
If none are specified, Data will be generated for all tables.
Comment out the <table> elements if you want to generate for all tables.
Also note that table names are CASE SENSITIVE for certain databases,
so on e.g. Oracle you should specify table names in upper case.
–>
<!–table generate=”true” name=”flights” pktable=”flights_pk”/>
<table name=”reservations”/
–>

<!–
If you want m:n relations, they must be specified like this.
Note that tables declare in multiple locations must all have
the same value of the generate attribute.
–>
<!–many2many>
<tablea generate=”true” name=”persons”/>
<jointable name=”reservations” generate=”false”/>
<tableb generate=”true” name=”flights”/>
</many2many
–>

<!– Plugins - Only Hibernate Plugin has been included with this special distribution  –>

<!–
If you want to generate XDoclet markup for hbm2java to include in the POJOs then
set genXDocletTags to true. Also, composite keys are generated as external classes which is
recommended. If you wish to keep them internal then set genIntergratedCompositeKeys to true.
Since r4 the ability to customise the selection of JavaTypes is now provided. The is a
recommended type mapper provided as shown. It is optional - if not provided then Middlegen
itself will select the Java mapping (as it did previously).
These settings are optional thus if they are not define here values default to false.
–>
<hibernate
destination=”${build.gen-src.dir}”
package
=”${myPackage}”
genXDocletTags
=”true”
genIntergratedCompositeKeys
=”false”
javaTypeMapper
=”middlegen.plugins.hibernate.HibernateJavaTypeMapper”
/>

</middlegen>

<mkdir dir=”${build.classes.dir}”/>
</target>

<!– =================================================================== –>
<!– Compile business logic (hibernate)                                        –>
<!– =================================================================== –>
<target name=”compile-hibernate” depends=”middlegen” description=”Compile hibernate Business Domain Model”>
<javac
srcdir=”${build.gen-src.dir}”
destdir
=”${build.classes.dir}”
classpathref
=”lib.class.path”
>
<include name=”**/hibernate/**/*”/>
</javac>
</target>

<!– =================================================================== –>
<!– Run hbm2java    depends=”middlegen”                                 –>
<!– =================================================================== –>
<target name=”hbm2java” description=”Generate .java from .hbm files.”>
<taskdef
name=”hbm2java”
classname
=”net.sf.hibernate.tool.hbm2java.Hbm2JavaTask”
classpathref
=”lib.class.path”
/>

<hbm2java output=”${build.gen-src.dir}”>
<fileset dir=”${build.gen-src.dir}”>
<include name=”**/*.hbm.xml”/>
</fileset>
</hbm2java>
</target>

<!– =================================================================== –>
<!– Build everything                                                    –>
<!– =================================================================== –>
<target name=”all” description=”Build everything” depends=”compile-hibernate”/>

<!– =================================================================== –>
<!– Clean everything                                                    –>
<!– =================================================================== –>
<target name=”clean” description=”Clean all generated stuff”>
<delete dir=”${build.dir}”/>
</target>

<!– =================================================================== –>
<!– Brings up the hsqldb admin tool                                     –>
<!– =================================================================== –>
<target name=”hsqldb-gui” description=”Brings up the hsqldb admin tool”>
<property name=”database.urlparams” value=”?user=${database.userid}&amp;password=${database.password}”/>
<java
classname=”org.hsqldb.util.DatabaseManager”
fork
=”yes”
classpath
=”${lib.dir}/hsqldb-1.7.1.jar;${database.driver.classpath}”
failonerror
=”true”
>
<arg value=”-url”/>
<arg value=”${database.url}${database.urlparams}”/>
<arg value=”-driver”/>
<arg value=”${database.driver}”/>
</java>
</target>

<!– ==================================================================== –>
<!– Validate the generated xml mapping documents                         –>
<!– ==================================================================== –>
<target name=”validate”>
<xmlvalidate failonerror=”no” lenient=”no” warn=”yes”>
<fileset dir=”${build.gen-src.dir}/airline/hibernate” includes=”*.xml” />
</xmlvalidate>
</target>

</project>

记得把2.0.2下面的hibernate-tools.jar文件拷贝到Middlegen-Hibernate-r5\lib下
,当然config下面的数据库配置文件也要设置为你自己的环境

如果你不想用ant来自动化做也可以通过dos命令行的方式来执行,命令如下:
hbm2java c:\sample\org\hibernate\sample\*.xml –output=c:\sample\
,前提是要设置下hibernate-extensions-2.1.2\tools\bin下的setenv.dat文件

VN:F [1.6.3_896]
Rating: 0.0/10 (0 votes cast)
VN:F [1.6.3_896]
Rating: 0 (from 0 votes)