注解映射必须满足两大条件:Hibernate3.2以上版本和JSEE 5。
@Entity 类注释,所有要持久化的类都要有
Java代码
@Entity
public class Org implements java.io.Serializable{
}
@Entitypublic class Org implements java.io.Serializable {}
@Id 主键
Java代码
@Id
@Id @GeneratedValue private String orgId; private StringorgName;
@Column(name="...") 该属性对应表中的字段是什么,没有name表示一样
@Table 对象与表映射
@UniqueConstraint 唯一约束
@Version 方法和字段级,乐观锁用法,返回数字和timestamp,数字为首选
@Transient 暂态属性,表示不需要处理
@Basic 最基本的注释。有两个属性:fetch是否延迟加载,optional是否允许null
@Enumerated 枚举类型
@Temporal 日期转换。默认转换Timestamp
@Lob 通常与@Basic同时使用,提高访问速度。
@Embeddable 类级,表可嵌入的
@Embedded 方法字段级,表被嵌入的对象和@Embeddable一起使用
@AttributeOverrides 属性重写
@AttributeOverride 属性重写的内容和@AttributeOverrides一起嵌套使用
@SecondaryTables 多个表格映射
@SecondaryTable 定义辅助表格映射和@SecondaryTables一起嵌套使用
@GeneratedValue 标识符生成策略,默认Auto
表与表关系映射
@OneToOne:一对一映射。它包含五个属性:
targetEntity:关联的目标类
Cascade:持久化时的级联操作,默认没有
fetch:获取对象的方式,默认EAGER
Optional:目标对象是否允许为null,默认允许
mappedBy:定义双向关联中的从属类。
单向:
@JoinColumn:定义外键(主表会多一字段,做外键)
@OneToMany:一对多映射;@ManyToOne:多对一映射
单向一对多:
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="book_oid")
单向多对一:
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="author_oid")
关联表格一对多:
@OneToMany(cascade=CascadeType.ALL)
@JoinTable(joinColumn={@JoinColumn(name="BOOK_OBJECT_OID")},inverseJoinColumns={@JoinColumn(name="AUTHER_OBJECT_OID")})
双向一对多或多对一:
不需要多一张表,只是使用mappedBy:使用在One一方,值为One方类名表示Many的从属类。
Java代码
@Entity
public class Org implements java.io.Serializable{
...
...
}
@Entitypublic class Org implements java.io.Serializable { // Fields@Id @GeneratedValue private String orgId; private String orgName;@OneToMany(mappedBy = "org") privateList<Department> departments; //Constructors... // Property accessors...}
Java代码
@Entity
public class Department implements java.io.Serializable{
}
@Entitypublic class Department implements java.io.Serializable { //Fields @Id @GeneratedValue private String id; private String name;@ManyToOne(fetch=FetchType.EAGER) @JoinColumn(name="org_orgId")private Org org; @OneToMany(mappedBy = "department") privateList<Employee> employees; //Constructors public List<Employee>getEmployees() { return employees; } public voidsetEmployees(List<Employee>employees) { this.employees = employees; } public Org getOrg() {return org; } public void setOrg(Org org) { this.org = org; } . . .}
Java代码
@Entity
public class Employee implements java.io.Serializable{
}
@Entitypublic class Employee implements java.io.Serializable { //Fields @Id @GeneratedValue private String employeeId; privateString employeeName; private String passWord; private Integer age;private Integer sex; @ManyToOne(fetch=FetchType.EAGER)@JoinColumn(name="department_id") private Department department;public Department getDepartment() { return department; } publicvoid setDepartment(Department department) { this.department =department; } ... // Property accessors ...}
双向多对多:@ManyToMany.单向多对多这里不在赘述(没有太多实际意义)
这个比较简单,看下代码就明白了:
Java代码
@Entity
public class Book implements java.io.Serializable{
}
@Entitypublic class Book implements java.io.Serializable { @Idprivate int id; private String name; private float money;@ManyToMany(cascade = CascadeType.ALL) privateList<Author> authors; publicList<Author> getAuthors() { returnauthors; } public voidsetAuthors(List<Author> authors) {this.authors = authors; } ...}
Java代码
@Entity
public class Author implements java.io.Serializable{
}
@Entitypublic class Author implements java.io.Serializable { @Idprivate int id; private String name; private int age;@ManyToMany(mappedBy="authors") privateList<Book> books; publicList<Book> getBooks() { return books;} public void setBooks(List<Book>books) { this.books = books; } ...}
需要注意的是:注释最好加在属性上,不要加在get方法上,那样做有时候就会出错。比如:@ManyToMany的时候就会报错!
注意import javax.xx.Entity,而不是org.hibernate.xx.Entity。
Descn属性不存在于数据库中,用@Transient注明
------------------------------------------
1,需要: Hibernate库文件,Hibernate Annotations库,ejb3-persstence.jar(Java持久化API)
sessionFactory=newAnnotationConfiguration().buildSessionFactory();
------------------------------------------
2,<bean id="sessionFactory"class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactory
</bean>
------------------------------------------
1,@Entity
@Table(name ="teacher_info")
@IdClass(UUIDHexGenerator.class)
public class UserMember implementsjava.io.Serializable
2,@entity通过getters/setters方法访问,或直接访问他的成员变量。
@Entity(access =AccessType.PROPERTY)
@Entity(access =AccessType.FIELD)
------------------------------------------
映射标识符
1,@Id
@GeneratedValue(strategy =GenerationType.AUTO)
private String id;
2,@Id(generate=GeneratorType.SEQUENCE,generator='SEQ_STORE')
3,@Id(generate=GeneratorType.IDENTITY)
------------------------------------------
映射属性
1,@Transient
2,@Column(name="PLANE_ID", length=80,nullable=true)
3,@Basic(fetch =FetchType.LAZY)
4,@Serialized凡标识@Serialized的属性将被序列化
public Country getCountry() { ...}
5,@Lob标识了存储对象可能是个CLOB或者BLOB。
@Lob(type=LobType.CLOB)
public String getFullText(){returnfullText;}
@Lob(type = LobType.BLOB)
public byte[] getFullCode() {returnfullCode;}
@Version 定义乐观锁机制使用
------------------------------------------
关联关系:
一、一对一:
1,@OneToOne(mappedBy ="address")
public User getUser(){
}
1、两边都定义了@OneToOne,但都没有定义mappedBy,则user和address表都会生成到对方的外键,双方都是这个关系的拥有者。
2、两边都定义了@OneToOne,如果user定义了mappedBy,则在address表生成到user的外键,address是这个关系的拥有者;如果address定义
了mappedBy,则在user表生成到address的外键,user是这个关系的拥有者。
二、一对多,多对一:
2,@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE})
3,@OneToMany(mappedBy="planeType",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@OrderBy("name")
public List<ModelPlane>getModelPlanes() {
}
其中定义mappedBy的是@OneToMany,也就是说One这一方是关系的拥有者。Many一方的表中生成到关联类的外键。
三、@ManyToMany
private Set authors = newHashSet<Author>();
@ManyToMany
public Set<Author>getAuthors(){
returnauthors;
}
private Set books = newHashSet<Book>();
@ManyToMany(mappedBy="authors")
public Set<Book>getBooks(){
returnbooks;
}
@ManyToMany会生成中间表,具体表名和字段可以通过@AssociationTable来定义,默认的就可以了,同样关系的非拥有者,需要定义mappedBy属性。
------------------------------------------
命名查询
你也可以通过注解,利用@NameQueries和@NameQuery注解,如下:
@NamedQueries(
{
@NamedQuery(name="planeType.findAll",query="select p from PlaneTypep" ),
@NamedQuery(name="planeType.delete",query="delete from PlaneTypewhere id=:id" )
}
)
------------------------------------------
内嵌对象(组件)
@Embedded({
}
@Embeddable(access =AccessType.FIELD)
public class Address implements Serializable{
}
@Embeddable
public class Country implements Serializable{
}
------------------------------------------
自定义的主键生成策略
@javax.persistence.GeneratedIdTable(
table =@Table(name='GENERATOR_TABLE'),
)
@javax.persistence.TableGenerator(
)
@javax.persistence.SequenceGenerator(
)
packageorg.hibernate.test.metadata;
school和userMember是一对多关系
importjavax.persistence.CascadeType;
importjavax.persistence.Column;
importjavax.persistence.Entity;
importjavax.persistence.FetchType;
importjavax.persistence.GeneratedValue;
importjavax.persistence.Id;
importjavax.persistence.OneToMany;
importjavax.persistence.Table;
importjavax.persistence.Temporal;
importjavax.persistence.TemporalType;
importorg.hibernate.annotations.Formula;
importorg.hibernate.annotations.GenericGenerator;
@Entity
@Table(name ="school_info")
public class SchoolInfo implements java.io.Serializable{
}
@GeneratedValue(strategy=GenerationType.AUTO)我们常用的自增长机制,我这里采用的是hibernate的uuid生成机制.
需要注意的是import javax.xx.Entity ,而不是org.hibernate.xx.Entity。
郁闷的是我上面用到@Formula,生成的sql竟然是'select COUNT(*) from school_info asformula0_ from school_info schoolinfo0_,当然不能执行了,寻求正解中~!!!!!!!!!
UserMember.java(前面引入的包已经贴过了,下面就不贴了)
@Entity
@Table(name ="teacher_info")//实体类和数据库表名不一致时,才用这个
public class UserMember implements java.io.Serializable{
}
最近在项目中使用 Spring 和 Hibernate 进行开发,有感于 Criteria 比较好用,在查询方法设计上可以灵活的根据 Criteria 的特点来方便地进行查询条件的组装。现在对 Hibernate的Criteria的用法进行总结:
Criteria 和 DetachedCriteria 的主要区别在于创建的形式不一样, Criteria 是在线的,所以它是由Hibernate Session 进行创建的;而 DetachedCriteria 是离线的,创建时无需Session,DetachedCriteria 提供了 2 个静态方法 forClass(Class) 或forEntityName(Name) 进行DetachedCriteria 实例的创建。
Spring 的框架提供了getHibernateTemplate().findByCriteria(detachedCriteria) 方法可以很方便地根据DetachedCriteria来返回查询结果。
Criteria 和 DetachedCriteria 均可使用 Criterion 和 Projection 设置查询条件。可以设置 FetchMode( 联合查询抓取的模式 ) ,设置排序方式。对于 Criteria 还可以设置 FlushModel (冲刷Session 的方式)和 LockMode (数据库锁模式)。下面对 Criterion 和 Projection进行详细说明。
Criterion 是 Criteria 的查询条件。Criteria 提供了 add(Criterion criterion)方法来添加查询条件。
Example exampleUser =Example.create(u) .ignoreCase() // 忽略大小写
.enableLike(MatchMode.ANYWHERE); // 对 String 类型的属性,无论在那里值在那里都匹配。相当于%value%
Project 主要是让 Criteria 能够进行报表查询,并可以实现分组。 Project 主要有SimpleProjection 、 ProjectionList 和 Property 三个实现。其中SimpleProjection 和 ProjectionList 的实例化是由内建的 Projections 来完成,如提供的avg 、 count 、 max 、 min 、 sum可以让开发者很容易对某个字段进行统计查询。
Property 是对某个字段进行查询条件的设置,如通过Porperty.forName(“color”).in (newString[]{“black”,”red”,”write”}); 则可以创建一个 Project 实例。通过 criteria 的add(Project)方法加入到查询条件中去。
1. 创建一个Criteria 实例 org.hibernate.Criteria接口表示特定持久类的一个查询。Session是Criteria实例的工厂。
Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();
2. 限制结果集内容一个单独的查询条件是org.hibernate.criterion.Criterion 接口的一个实例。org.hibernate.criterion.Restrictions类定义了获得某些内置Criterion类型的工厂方法。
List cats = sess.createCriteria(Cat.class) .add(Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) ).list();
约束可以按逻辑分组。
List cats = sess.createCriteria(Cat.class) .add(Restrictions.like("name", "Fritz%") )
.add( Restrictions.or( Restrictions.eq( "age", new Integer(0) ),Restrictions.isNull("age")
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk"} ) )
.add( Restrictions.disjunction() .add( Restrictions.isNull("age"))
.add( Restrictions.eq("age", new Integer(0) ) )
.add( Restrictions.eq("age", new Integer(1) ))
.add( Restrictions.eq("age", new Integer(2) ) ) ))
.list();
Hibernate提供了相当多的内置criterion类型(Restrictions 子类), 但是尤其有用的是可以允许你直接使用SQL。
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.sql("lower({alias}.name) like lower(?)","Fritz%", Hibernate.STRING) )
{alias}占位符应当被替换为被查询实体的列别名。Property实例是获得一个条件的另外一种途径。你可以通过调用Property.forName() 创建一个Property。
List cats =sess.createCriteria(Cat.class)
.add(Restrictions.disjunction()
.add( age.isNull())
.add( age.eq( new Integer(0) ))
.add( age.eq( new Integer(1) ))
.add( age.eq( new Integer(2) ))
.add( Property.forName("name").in( new String[] { "Fritz", "Izi","Pk" } ))
.list();
3.结果集排序你可以使用org.hibernate.criterion.Order来为查询结果排序。
.add( Restrictions.like("name","F%")
.addOrder( Order.asc("name"))
.addOrder( Order.desc("age"))
.setMaxResults(50)
.list();
.add( Property.forName("name").like("F%"))
.addOrder( Property.forName("name").asc())
.addOrder( Property.forName("age").desc())
.setMaxResults(50)
.list();
4. 关联你可以使用createCriteria()非常容易的在互相关联的实体间建立约束。
List cats =sess.createCriteria(Cat.class)
.add( Restrictions.like("name","F%")
.createCriteria("kittens")
.add( Restrictions.like("name","F%")
.list();
注意第二个 createCriteria()返回一个新的 Criteria实例,该实例引用kittens 集合中的元素。接下来,替换形态在某些情况下也是很有用的。
List cats =sess.createCriteria(Cat.class)
.createAlias("mate","mt")
.add( Restrictions.eqProperty("kt.name", "mt.name"))
.list();
List cats =sess.createCriteria(Cat.class)
.createCriteria("kittens","kt")
.add( Restrictions.eq("name", "F%"))
.returnMaps()
.list();
Iterator iter = cats.iterator(); while ( iter.hasNext() ) {
}
5.动态关联抓取你可以使用setFetchMode()在运行时定义动态关联抓取的语义。
.add( Restrictions.like("name", "Fritz%"))
.setFetchMode("mate",FetchMode.EAGER)
.setFetchMode("kittens",FetchMode.EAGER)
.list();
这个查询可以通过外连接抓取mate和kittens。
6. 查询示例 org.hibernate.criterion.Example类允许你通过一个给定实例构建一个条件查询。
Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results =session.createCriteria(Cat.class)
.add( Example.create(cat))
.list();
版本属性、标识符和关联被忽略。默认情况下值为null的属性将被排除。可以自行调整Example使之更实用。
.excludeZeroes()
.excludeProperty("color")
.ignoreCase()
.enableLike();
List results =session.createCriteria(Cat.class)
.add(example)
.list();
甚至可以使用examples在关联对象上放置条件。
List results =session.createCriteria(Cat.class)
.add( Example.create(cat))
.add( Example.create( cat.getMate() ))
7. 投影(Projections)、聚合(aggregation)和分组(grouping)org.hibernate.criterion.Projections是 Projection 的实例工厂。我们通过调用setProjection()应用投影到一个查询。
List results =session.createCriteria(Cat.class)
.setProjection( Projections.rowCount())
.add( Restrictions.eq("color", Color.BLACK))
.list();
List results =session.createCriteria(Cat.class)
.setProjection(Projections.projectionList()
.add( Projections.rowCount())
.add( Projections.avg("weight"))
.add( Projections.max("weight"))
.add( Projections.groupProperty("color"))
.list();
在一个条件查询中没有必要显式的使用 "group by" 。某些投影类型就是被定义为 分组投影,他 们也出现在SQL的groupby子句中。 可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的实现方式:
.setProjection( Projections.alias(Projections.groupProperty("color"), "colr" ))
.list();
List results =session.createCriteria(Cat.class)
.setProjection( Projections.groupProperty("color").as("colr"))
.addOrder( Order.asc("colr"))
.list();
alias()和as()方法简便的将一个投影实例包装到另外一个 别名的Projection实例中。简而言之,当你添加一个投影到一个投影列表中时 你可以为它指定一个别名:
.setProjection(Projections.projectionList()
.add( Projections.rowCount(), "catCountByColor")
.add( Projections.avg("weight"), "avgWeight")
.add( Projections.max("weight"), "maxWeight")
.add( Projections.groupProperty("color"), "color")
.addOrder( Order.desc("catCountByColor"))
.addOrder( Order.desc("avgWeight"))
.list();
.createAlias("kittens","kit")
.setProjection(Projections.projectionList()
.add( Projections.property("cat.name"), "catName")
.add( Projections.property("kit.name"), "kitName")
.addOrder( Order.asc("catName"))
.addOrder( Order.asc("kitName"))
.list();
也可以使用Property.forName()来表示投影:
List results =session.createCriteria(Cat.class)
.setProjection( Property.forName("name"))
.add( Property.forName("color").eq(Color.BLACK))
.list();
.setProjection(Projections.projectionList()
.add( Projections.rowCount().as("catCountByColor"))
.add( Property.forName("weight").avg().as("avgWeight"))
.add( Property.forName("weight").max().as("maxWeight"))
.add( Property.forName("color").group().as("color")
.addOrder( Order.desc("catCountByColor"))
.addOrder( Order.desc("avgWeight"))
.list();
DetachedCriteria query =DetachedCriteria.forClass(Cat.class)
.add(Property.forName("sex").eq('F'));
//创建一个Session
Session session = .;
Transaction txn = session.beginTransaction();
List results =query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();
DetachedCriteria也可以用以表示子查询。条件实例包含子查询可以通过 Subqueries或者Property获得。
DetachedCriteria avgWeight =DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight").avg() );
session.createCriteria(Cat.class)
.add( Property.forName("weight).gt(avgWeight))
session.createCriteria(Cat.class)
相互关联的子查询也是有可能的:
DetachedCriteria avgWeightForSex =DetachedCriteria.forClass(Cat.class,"cat2")
session.createCriteria(Cat.class, "cat")
Hibernate3 提供了一种创新的方式来处理具有“显性(visibility)”规则的数据,那就是使用Hibernatefilter。
Hibernate3新增了对某个类或者集合使用预先定义的过滤器条件(filter criteria)的功能。过滤器条件相当于定义一个非常类似于类和各种集合上的“where”属性的约束子句,但是过滤器条件可以带参数。应用程序可以在运行时决定是否启用给定的过滤器,以及使用什么样的参数值。过滤器的用法很像数据库视图,只不过是在应用程序中确定使用什么样的参数的。
要使用过滤器,必须首先在相应的映射节点中定义。而定义一个过滤器,要用到位于<hibernate-mapping/>节点之内的<filter-def/>节点:
<filter-def name="myFilter"><filter-param name="myFilterParam"type="string"/></filter-def>定义好之后,就可以在某个类中使用这个过滤器:
<class name="myClass" ...> ...<filter name="myFilter" condition=":myFilterParam =MY_FILTERED_COLUMN"/></class>也可以在某个集合使用它:
<set ...> <filtername="myFilter" condition=":myFilterParam =MY_FILTERED_COLUMN"/></set>可以在多个类或集合中使用某个过滤器;某个类或者集合中也可以使用多个过滤器。
Session对象中会用到的方法有:enableFilter(String filterName),getEnabledFilter(String filterName), 和 disableFilter(StringfilterName). Session中默认是不启用过滤器的,必须通过Session.enabledFilter()方法显式的启用。该方法返回被启用的Filter的实例。以上文定义的过滤器为例:
session.enableFilter("myFilter").setParameter("myFilterParam","some-value");注意,org.hibernate.Filter的方法允许链式方法调用。(类似上面例子中启用Filter之后设定Filter参数这个“方法链”)Hibernate的其他部分也大多有这个特性。
下面是一个比较完整的例子,使用了记录生效日期模式过滤有时效的数据:
<filter-def name="effectiveDate"><filter-param name="asOfDate"type="date"/></filter-def> <classname="Employee" ...> ... <many-to-onename="department" column="dept_id"class="Department"/> <propertyname="effectiveStartDate" type="date"column="eff_start_dt"/> <propertyname="effectiveEndDate" type="date"column="eff_end_dt"/> ... <!-- Notethat this assumes non-terminal records have an eff_end_dt set to amax db date for simplicity-sake注意,为了简单起见,此处假设雇用关系生效期尚未结束的记录的eff_end_dt字段的值等于数据库最大的日期--> <filter name="effectiveDate"condition=":asOfDate BETWEEN eff_start_dt andeff_end_dt"/> </class><class name="Department" ...> ...<set name="employees" lazy="true"><key column="dept_id"/><one-to-many class="Employee"/><filter name="effectiveDate" condition=":asOfDateBETWEEN eff_start_dt and eff_end_dt"/></set></class>定义好后,如果想要保证取回的都是目前处于生效期的记录,只需在获取雇员数据的操作之前先开启过滤器即可:
Session session = ...;session.enabledFilter("effectiveDate").setParameter("asOfDate", newDate()); List results = session.createQuery("from Employee as ewhere e.salary > :targetSalary").setLong("targetSalary", new Long(1000000)) .list();在上面的HQL中,虽然我们仅仅显式的使用了一个薪水条件,但因为启用了过滤器,查询将仅返回那些目前雇用关系处于生效期的,并且薪水高于一百万美刀的雇员的数据。
注意:如果你打算在使用外连接(或者通过HQL或load fetching)的同时使用过滤器,要注意条件表达式的方向(左还是右)。最安全的方式是使用左外连接(left outer joining)。并且通常来说,先写参数,然后是操作符,最后写数据库字段名。
在Filter定义之后,它可能被附加到多个实体和/或集合类,每个都有自己的条件。假若这些条件都是一样的,每次都要定义就显得很繁琐。因此,<filter-def/>被用来定义一个默认条件,它可能作为属性或者CDATA出现:
<filter-def name="myFilter" condition="abc>xyz">...</filter-def><filter-defname="myOtherFilter">abc=xyz</filter-def>当这个filter被附加到任何目的地,而又没有指明条件时,这个条件就会被使用。注意,换句话说,你可以通过给filter附加特别的条件来重载默认条件