Hibernate注解版关联关系映射全解析+案例

时间:2022-10-28 12:07:17

HIbernate注解说明

1、@Entity(name="EntityName")
必须,name为可选,对应数据库中一的个表,此处的EntryName要注意,在代码中使用hql进行查询时,需要from Xxx,那么Xxx就是对应的此处的EntryName,所以要注意EntryName的命名,否则会出现映射问题。



2、@Table(name="",catalog="",schema="")
可选,通常和@Entity配合使用,只能标注在实体的class定义处,表示实体对应的数据库表的信息

name:可选,表示表的名称。默认地,表名和实体名称一致,只有在不一致的情况下才需要指定表名
catalog:可选,表示Catalog名称。默认为Catalog("")
schema:可选,表示Schema名称。默认为Schema("")


3、@id
必须

@id定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键。置于getXxxx()前



4、@GeneratedValue(strategy=GenerationType,generator="")
可选

strategy:表示主键生成策略,有AUTO、INDENTITY、SEQUENCE和 TABLE 4种,分别表示让ORM框架自动选择、根据数据库的Identity字段生成、根据数据库表的Sequence字段生成、以及根据一个额外的表生成主键。默认为AUTO

generator:表示主键生成器的名称,这个属性通常和ORM框架相关。例如,Hibernate可以指定uuid等主键生成方式

示例:

@Id

@GeneratedValues(strategy=StrategyType.SEQUENCE)

public int getPk() {

return pk;

}



5、@Basic(fetch=FetchType,optional=true)
可选

@Basic表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的getXxxx()方法。默认即为@Basic

fetch:表示该属性的读取策略,有EAGER和LAZY两种,分别表示主支抓取和延迟加载。默认为EAGER
optional:表示该属性是否允许为null,默认为true
示例:

@Basic(optional=false)

public String getAddress() {

return address;

}



6、@Column
可选

@Column描述了数据库表中该字段的详细定义,这对于根据JPA注解生成数据库表结构的工具非常有作用
name:表示数据库表中该字段的名称。默认情形属性名称一致
nullable:表示该字段是否允许为null。默认为true
unique:表示该字段是否是唯一标识。默认为false
length:表示该字段的大小,仅对String类型的字段有效
insertable:表示在ORM框架执行插入操作时,该字段是否应出现INSETRT语句中。默认为true
updateable:表示在ORM框架执行更新操作时,该字段是否应该出现在UPDATE语句中,默认为true。对于一经创建就不可以更改的字段,该属性非常有用,如对于birthday字段
columnDefinition:表示该字段在数据库中的实际类型。通常ORM框架可以根据属性类型自动判断数据库中字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是DATE、TIME还是TIMESTAMP。此外,String的默认映射类型为VARCHAR,如果要将String类型映射到特定数据库的BLOB或TEXT字段类型,该属性非常有用
示例:

@Column(name="BIRTH",nullable="false",columnDefinition="DATE")

public String getBithday() {

return birthday;

}



7、@Transient
可选

@Transient表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性

如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Basic

示例:

//根据birth计算出age属性

@Transient

public int getAge() {

return getYear(new Date()) -getYear(birth);

}



8、@ManyToOne(fetch=FetchType,cascade=CascadeType)
可选

@ManyToOne表示一个多对一的映射,该注解标注的属性通常是数据库表的外键

optional:是否允许该字段为null,该属性应该根据数据库表的外键约束来确定,默认为true
fetch:表示抓取策略,默认为FetchType.EAGER
cascade:表示默认的级联操作策略,可以指定为ALL、PERSIST、MERGE、REFRESH和REMOVE中的若干组合,默认为无级联操作
targetEntity:表示该属性关联的实体类型,该属性通常不必指定,ORM框架根据属性类型自动判断targetEntity


示例:

//订单Order和用户User是一个ManyToOne的关系

//在Order类中定义

@ManyToOne()

@JoinColumn(name="USER")

public User getUser() {

return user;

}



9、@JoinColumn
可选

@JoinColumn和@Column类似,介量描述的不是一个简单字段,而是一个关联字段,例如,描述一个@ManyToOne的字段.



name:该字段的名称,由于@JoinColumn描述的是一个关联字段,如ManyToOne,则默认的名称由其关联的实体决定.


例如,实体Order有一个user属性来关联实体User,则Order的user属性为一个外键

其默认的名称为实体User的名称+下划线+实体User的主键名称

示例:

见@ManyToOne



10、@OneToMany(fetch=FetchType,cascade=CascadeType)
可选

@OneToMany描述一个一对多的关联,该属性应该为集体类型,在数据库中并没有实际字段



fetch:表示抓取策略,默认为FetchType.LAZY,因为关联的多个对象通常不必从数据库预先读取到内存
cascade:表示级联操作策略,对于OneToMany类型的关联非常重要,通常该实体更新或删除时,其关联的实体也应当被更新或删除


例如:实体User和Order是OneToMany的关系,则实体User被删除时,其关联的实体Order也应该被全部删除

示例:

@OneTyMany(cascade=ALL)

public List getOrders() {

return orders;

}



11、@OneToOne(fetch=FetchType,cascade=CascadeType)
可选

@OneToOne描述一个一对一的关联

fetch:表示抓取策略,默认为FetchType.LAZY

cascade:表示级联操作策略

示例:

@OneToOne(fetch=FetchType.LAZY)

public Blog getBlog() {

return blog;

}



12、@ManyToMany
可选

@ManyToMany描述一个多对多的关联,多对多关联上是两个一对多关联,但是在ManyToMany描述中,中间表是由ORM框架自动处理

targetEntity:表示多对多关联的另一个实体类的全名,例如:package.Book.class

mappedBy:表示多对多关联的另一个实体类的对应集合属性名称



13、@MappedSuperclass
可选

@MappedSuperclass可以将超类的JPA注解传递给子类,使子类能够继承超类的JPA注解

示例:

@MappedSuperclass

public class Employee() {

....

}



@Entity

public class Engineer extends Employee {

.....

}

@Entity

public class Manager extends Employee {

.....

}



14、@Embedded
可选

@Embedded将几个字段组合成一个类,并作为整个Entity的一个属性

例如User包括id、name、city、street、zip属性

我们希望city、street、zip属性映射为Address对象。这样,User对象将具有id、name和address这三个属性.


Address对象必须定义为@Embededable

示例:

@Embeddable

public class Address {city,street,zip}

@Entity

public class User {

@Embedded

public Address getAddress() {

..........

}

}



1、Hibernate注解关系处理关系映射


在hibernate中,通常配置对象关系映射关系有两种,一种是基于xml的方式,另一种是基于annotation的注解方式,熟话说,萝卜青菜,可有所爱,每个人都有自己喜欢的配置方式,我在试了这两种方式以后,发现使用annotation的方式可以更简介,所以这里就简单记录下通过annotation来配置各种映射关系,在hibernate4以后已经将annotation的jar包集成进来了,如果使用hibernate3的版本就需要引入annotation的jar包。

一、单对象操作


@Entity  --->  如果我们当前这个bean要设置成实体对象,就需要加上Entity这个注解
@Table(name="t_user")  ---->  设置数据库的表名
public class User
{
private int id;
private String username;
private String password;
private Date born;
private Date registerDate;

@Column(name="register_date")  --->  Column中的name属性对应了数据库的该字段名字,里面还有其他属性,例如length,nullable等等
public Date getRegisterDate()
{
return registerDate;
}
public void setRegisterDate(Date registerDate)
{
this.registerDate = registerDate;
}

@Id  --->  定义为数据库的主键ID  (建议不要在属性上引入注解,因为属性是private的,如果引入注解会破坏其封装特性,所以建议在getter方法上加入注解)
@GeneratedValue  ---->  ID的生成策略为自动生成  
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
  ............
}

最后只需要在hibernate.cfg.xml文件里面将该实体类加进去即可:

<!-- 基于annotation的配置 -->
<mapping class="com.xiaoluo.bean.User"/>
<!-- 基于hbm.xml配置文件 -->
<mapping resource="com/xiaoluo/bean/User.hbm.xml"/>
这样我们就可以写测试类来进行我们的CRUD操作了。

二、一对多的映射(one-to-many)

这里我们定义了两个实体类,一个是ClassRoom,一个是Student,这两者是一对多的关联关系。

ClassRoom类:


@Entity
@Table(name="t_classroom")
public class ClassRoom
{
private int id;
private String className;
private Set<Student> students;

public ClassRoom()
{
students = new HashSet<Student>();
}

public void addStudent(Student student)
{
students.add(student);
}

@Id
@GeneratedValue
public int getId()
{
return id;
}

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

public String getClassName()
{
return className;
}

public void setClassName(String className)
{
this.className = className;
}

@OneToMany(mappedBy="room")  --->  OneToMany指定了一对多的关系,mappedBy="room"指定了由多的那一方来维护关联关系,mappedBy指的是多的一方对1的这一方的依赖的属性,(注意:如果没有指定由谁来维护关联关系,则系统会给我们创建一张中间表)
@LazyCollection(LazyCollectionOption.EXTRA)  --->  LazyCollection属性设置成EXTRA指定了当如果查询数据的个数时候,只会发出一条 count(*)的语句,提高性能
public Set<Student> getStudents()
{
return students;
}

public void setStudents(Set<Student> students)
{
this.students = students;
}

}

Student类:


@Entity
@Table(name="t_student")
public class Student
{
private int id;
private String name;
private int age;
private ClassRoom room;

@ManyToOne(fetch=FetchType.LAZY)  ---> ManyToOne指定了多对一的关系,fetch=FetchType.LAZY属性表示在多的那一方通过延迟加载的方式加载对象(默认不是延迟加载)
@JoinColumn(name="rid")  --->  通过 JoinColumn 的name属性指定了外键的名称 rid (注意:如果我们不通过JoinColum来指定外键的名称,系统会给我们声明一个名称)
public ClassRoom getRoom()
{
return room;
}
public void setRoom(ClassRoom room)
{
this.room = room;
}
@Id
@GeneratedValue
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}

}

三、一对一映射(One-to-One)

一对一关系这里定义了一个Person对象以及一个IDCard对象

Person类:


@Entity
@Table(name="t_person")
public class Person
{
private int id;
private String name;
private IDCard card;

@OneToOne(mappedBy="person")  --->  指定了OneToOne的关联关系,mappedBy同样指定由对方来进行维护关联关系
public IDCard getCard()
{
return card;
}
public void setCard(IDCard card)
{
this.card = card;
}
@Id
@GeneratedValue
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}

}

IDCard类:


@Entity
@Table(name="t_id_card")
public class IDCard
{
private int id;
private String no;
private Person person;

@Id
@GeneratedValue
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getNo()
{
return no;
}
public void setNo(String no)
{
this.no = no;
}
@OneToOne  --->  OnetoOne指定了一对一的关联关系,一对一中随便指定一方来维护映射关系,这里选择IDCard来进行维护
@JoinColumn(name="pid")  --->  指定外键的名字 pid
public Person getPerson()
{
return person;
}
public void setPerson(Person person)
{
this.person = person;
}
}

注意:在判断到底是谁维护关联关系时,可以通过查看外键,哪个实体类定义了外键,哪个类就负责维护关联关系。

四、Many-to-Many映射(多对多映射关系)

多对多这里通常有两种处理方式,一种是通过建立一张中间表,然后由任一一个多的一方来维护关联关系,另一种就是将多对多拆分成两个一对多的关联关系

1.通过中间表由任一一个多的一方来维护关联关系

Teacher类:


@Entity
@Table(name="t_teacher")
public class Teacher
{
private int id;
private String name;
private Set<Course> courses;

public Teacher()
{
courses = new HashSet<Course>();
}
public void addCourse(Course course)
{
courses.add(course);
}

@Id
@GeneratedValue
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@ManyToMany(mappedBy="teachers")  --->  表示由Course那一方来进行维护
public Set<Course> getCourses()
{
return courses;
}
public void setCourses(Set<Course> courses)
{
this.courses = courses;
}

}

Course类:


@Entity
@Table(name="t_course")
public class Course
{
private int id;
private String name;
private Set<Teacher> teachers;

public Course()
{
teachers = new HashSet<Teacher>();
}
public void addTeacher(Teacher teacher)
{
teachers.add(teacher);
}
@ManyToMany   ---> ManyToMany指定多对多的关联关系
@JoinTable(name="t_teacher_course", joinColumns={ @JoinColumn(name="cid")},
inverseJoinColumns={ @JoinColumn(name = "tid") })  --->  因为多对多之间会通过一张中间表来维护两表直接的关系,所以通过 JoinTable 这个注解来声明,name就是指定了中间表的名字,JoinColumns是一个 @JoinColumn类型的数组,表示的是我这方在对方中的外键名称,我方是Course,所以在对方外键的名称就是 rid,inverseJoinColumns也是一个 @JoinColumn类型的数组,表示的是对方在我这放中的外键名称,对方是Teacher,所以在我方外键的名称就是 tid
public Set<Teacher> getTeachers()
{
return teachers;
}

public void setTeachers(Set<Teacher> teachers)
{
this.teachers = teachers;
}

@Id
@GeneratedValue
public int getId()
{
return id;
}

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

public String getName()
{
return name;
}

public void setName(String name)
{
this.name = name;
}

}

2.将Many-to-Many拆分成两个One-to-Many的映射(Admin、Role、AdminRole)

Admin类:


@Entity
@Table(name="t_admin")
public class Admin
{
private int id;
private String name;
private Set<AdminRole> ars;
public Admin()
{
ars = new HashSet<AdminRole>();
}
public void add(AdminRole ar)
{
ars.add(ar);
}
@Id
@GeneratedValue
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@OneToMany(mappedBy="admin")  --->  OneToMany关联到了AdminRole这个类,由AdminRole这个类来维护多对一的关系,mappedBy="admin"
@LazyCollection(LazyCollectionOption.EXTRA)  
public Set<AdminRole> getArs()
{
return ars;
}
public void setArs(Set<AdminRole> ars)
{
this.ars = ars;
}
}

Role类:


@Entity
@Table(name="t_role")
public class Role
{
private int id;
private String name;
private Set<AdminRole> ars;
public Role()
{
ars = new HashSet<AdminRole>();
}
public void add(AdminRole ar)
{
ars.add(ar);
}
@Id
@GeneratedValue
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@OneToMany(mappedBy="role")  --->  OneToMany指定了由AdminRole这个类来维护多对一的关联关系,mappedBy="role"
@LazyCollection(LazyCollectionOption.EXTRA)
public Set<AdminRole> getArs()
{
return ars;
}
public void setArs(Set<AdminRole> ars)
{
this.ars = ars;
}
}

AdminRole类:


@Entity
@Table(name="t_admin_role")
public class AdminRole
{
private int id;
private String name;
private Admin admin;
private Role role;
@Id
@GeneratedValue
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@ManyToOne  --->  ManyToOne关联到Admin
@JoinColumn(name="aid")  
public Admin getAdmin()
{
return admin;
}
public void setAdmin(Admin admin)
{
this.admin = admin;
}
@ManyToOne  --->  
@JoinColumn(name="rid")
public Role getRole()
{
return role;
}
public void setRole(Role role)
{
this.role = role;
}
}

小技巧:通过hibernate来进行插入操作的时候,不管是一对多、一对一还是多对多,都只需要记住一点,在哪个实体类声明了外键,就由哪个类来维护关系,在保存数据时,总是先保存的是没有维护关联关系的那一方的数据,后保存维护了关联关系的那一方的数据,如:


       Person p = new Person();
p.setName("xiaoluo");
session.save(p);

IDCard card = new IDCard();
card.setNo("1111111111");
card.setPerson(p);
session.save(card);



2、Hibernate基于注解的双向one-to-many映射关系的实现


项目中用到了一对多的实体类关系映射,之前接触的都是基于配置文件的映射实现,但是公司的大部分都是基于注解的,因此自己参考之前的代码捣鼓了基于注解的一对多的映射关系实现。


背景:

一的一端:QingAoCenterInfo:青奥场所信息,

多的一端:QingAoPlaceInfo:青奥场馆信息,

其中一个青奥场所下可以包含多个青奥场馆


one端:QingAoCenterInfo,持有QingAoPlaceInfo的List引用,

通过注解@OneToMany(mappedBy="qingAoCenterInfo",cascade= CascadeType.ALL)


mappedBy定义类之间的双向关系。如果类之间是单向关系,不需要提供定义,如果类和类之间形成双向关系,我们就需要使用这个属性进行定义, 否则可能引起数据一致性的问题。要由One的一方指向Many的一方,并且,这个属性应该等于Many的一方中含有One类的属性的属性名,否则会出错啦

cascadeCascadeType[]类型。该属性定义类和类之间的级联关系

定义的级联关系将被容器视为对当前类对象及其关联类对象采取相同的操作,而且这种关系是递归调用的。

举个例子:Order 和OrderItem有级联关系,那么删除QingAoCenterInfo时将同时删除它所对应的QingAoPlaceInfo对象。而如果QingAoPlaceInfo还和其他的对象之间有级联关系,那么这样的操作会一直递归执行下去。

cascade的值只能从CascadeType.PERSIST(级联新建)、CascadeType.REMOVE(级联删除)、CascadeType.REFRESH(级联刷新)、CascadeType.MERGE(级联更新)中选择一个或多个。还有一个选择是使用CascadeType.ALL,表示选择全部四项。 

[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. package com.yuqiaotech.nttelcom.model;  
  2.   
  3. import java.util.Date;  
  4. import java.util.List;  
  5.   
  6. import javax.persistence.CascadeType;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.GeneratedValue;  
  9. import javax.persistence.GenerationType;  
  10. import javax.persistence.Id;  
  11. import javax.persistence.OneToMany;  
  12. import javax.persistence.Table;  
  13.   
  14. /** 
  15.  * 青奥重点场所信息表。 
  16.  *  
  17.  */  
  18. @Entity(name="QING_AO_CENTER_INFO")  
  19. @Table(name="QING_AO_CENTER_INFO")  
  20. public class QingAoCenterInfo {  
  21.     private Long id;  
  22.     private String centerName;  //重点场所名称  
  23.     private Long alarmNum;      //告警数  
  24.     private String note;        //备注  
  25.     private String iconName;    //图标名称  
  26.     private String cityName;    //所在城市  
  27.     private String type;        //重点场所、活动保障  
  28.     private Date createTime;  
  29.     private List<QingAoPlaceInfo> qingAoPlaceInfo; //场所拥有的场馆  
  30.     @Id  
  31.     @GeneratedValue(strategy=GenerationType.AUTO)  
  32.     public Long getId() {  
  33.         return id;  
  34.     }  
  35.     public void setId(Long id) {  
  36.         this.id = id;  
  37.     }  
  38.     /** 
  39.      * @searchItem 
  40.      * displayType="text" 
  41.      *  
  42.      * 重点场所名称 
  43.      * @return 
  44.      */  
  45.     public String getCenterName() {  
  46.         return centerName;  
  47.     }  
  48.     public void setCenterName(String centerName) {  
  49.         this.centerName = centerName;  
  50.     }  
  51.     /** 
  52.      * 告警数 
  53.      * @return 
  54.      */  
  55.     public Long getAlarmNum() {  
  56.         return alarmNum;  
  57.     }  
  58.     public void setAlarmNum(Long alarmNum) {  
  59.         this.alarmNum = alarmNum;  
  60.     }  
  61.     /** 
  62.      * 备注 
  63.      * @return 
  64.      */  
  65.     public String getNote() {  
  66.         return note;  
  67.     }  
  68.     public void setNote(String note) {  
  69.         this.note = note;  
  70.     }  
  71.     /** 
  72.      * 图标名称 
  73.      * @return 
  74.      */  
  75.     public String getIconName() {  
  76.         return iconName;  
  77.     }  
  78.     public void setIconName(String iconName) {  
  79.         this.iconName = iconName;  
  80.     }  
  81.   
  82.     public String getCityName() {  
  83.         return cityName;  
  84.     }  
  85.   
  86.     public void setCityName(String cityName) {  
  87.         this.cityName = cityName;  
  88.     }  
  89.     public String getType() {  
  90.         return type;  
  91.     }  
  92.     public void setType(String type) {  
  93.         this.type = type;  
  94.     }  
  95.     public Date getCreateTime() {  
  96.         return createTime;  
  97.     }  
  98.     public void setCreateTime(Date createTime) {  
  99.         this.createTime = createTime;  
  100.     }  
  101.     @OneToMany(mappedBy="qingAoCenterInfo",cascade= CascadeType.ALL)  
  102.     public List<QingAoPlaceInfo> getQingAoPlaceInfo() {  
  103.         return qingAoPlaceInfo;  
  104.     }  
  105.     public void setQingAoPlaceInfo(List<QingAoPlaceInfo> qingAoPlaceInfo) {  
  106.         this.qingAoPlaceInfo = qingAoPlaceInfo;  
  107.     }  
  108. }  


many端:QingAoPlaceInfo,持有QingAoCenterInfo的引用

通过@ManyToOne(fetch=FetchType.LAZY )    @JoinColumn(name="f_center_id")设置关联关系

 @ManyToOne指明QingAoPlaceInfo和QingAoCenterInfo之间为多对一关系,多个QingAoPlaceInfo实例关联的都是同一个QingAoCenterInfo对象

    fetch和lazy是用来定义级联查询的方式:

    fetch:官方文档里对fetch有如下描述,Hibernate3 定义了如下几种抓取策略:


[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. package com.yuqiaotech.nttelcom.model;  
  2.   
  3. import java.util.Date;  
  4. import java.util.List;  
  5.   
  6. import javax.persistence.CascadeType;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.FetchType;  
  9. import javax.persistence.GeneratedValue;  
  10. import javax.persistence.GenerationType;  
  11. import javax.persistence.Id;  
  12. import javax.persistence.JoinColumn;  
  13. import javax.persistence.ManyToOne;  
  14. import javax.persistence.OneToMany;  
  15. import javax.persistence.Table;  
  16.   
  17. /** 
  18.  * 场馆信息。 
  19.  *  
  20.  */  
  21. @Entity(name="QING_AO_PLACE_INFO")  
  22. @Table(name="QING_AO_PLACE_INFO")  
  23. public class QingAoPlaceInfo {  
  24.     private Long id;  
  25.     private QingAoCenterInfo qingAoCenterInfo;// 重点场所id  
  26.     private String placeName;// 场馆名称  
  27.     private String note;// 备注  
  28.     private String openStat;// 开通状态  
  29.     private Long displayOrder;  
  30.     private String cityName;  
  31.     private Date createTime;  
  32.     private List<QingAoPlaceCdmaSector> qingAoPlaceCdmaSector;//拥有的cdma  
  33.     private List<QingAoPlaceLteSector> qingAoPlaceLteSector;//拥有的Lte  
  34.     private List<QingAoAp> qingAoAp;                          //拥有的Ap  
  35.       
  36.   
  37.     @Id  
  38.     @GeneratedValue(strategy = GenerationType.AUTO)  
  39.     public Long getId() {  
  40.         return id;  
  41.     }  
  42.   
  43.     public void setId(Long id) {  
  44.         this.id = id;  
  45.     }  
  46.   
  47.     @ManyToOne(fetch=FetchType.LAZY )  
  48.     @JoinColumn(name="f_center_id")  
  49.     public QingAoCenterInfo getQingAoCenterInfo() {  
  50.         return qingAoCenterInfo;  
  51.     }  
  52.       
  53.     public void setQingAoCenterInfo(QingAoCenterInfo qingAoCenterInfo) {  
  54.         this.qingAoCenterInfo = qingAoCenterInfo;  
  55.     }  
  56.     /** 
  57.      * @searchItem 
  58.      * displayType="text" 
  59.      * 场所名称 
  60.      * @return 
  61.      */  
  62.     public String getPlaceName() {  
  63.         return placeName;  
  64.     }  
  65.     public void setPlaceName(String placeName) {  
  66.         this.placeName = placeName;  
  67.     }  
  68.   
  69.     public String getNote() {  
  70.         return note;  
  71.     }  
  72.   
  73.     public void setNote(String note) {  
  74.         this.note = note;  
  75.     }  
  76.   
  77.     public String getOpenStat() {  
  78.         return openStat;  
  79.     }  
  80.   
  81.     public void setOpenStat(String openStat) {  
  82.         this.openStat = openStat;  
  83.     }  
  84.   
  85.     public Long getDisplayOrder() {  
  86.         return displayOrder;  
  87.     }  
  88.   
  89.     public void setDisplayOrder(Long displayOrder) {  
  90.         this.displayOrder = displayOrder;  
  91.     }  
  92.   
  93.     public String getCityName() {  
  94.         return cityName;  
  95.     }  
  96.   
  97.     public void setCityName(String cityName) {  
  98.         this.cityName = cityName;  
  99.     }  
  100.     public Date getCreateTime() {  
  101.         return createTime;  
  102.     }  
  103.     public void setCreateTime(Date createTime) {  
  104.         this.createTime = createTime;  
  105.     }  
  106.     @OneToMany(mappedBy="qingAoPlaceInfo",cascade= CascadeType.ALL)  
  107.     public List<QingAoPlaceCdmaSector> getQingAoPlaceCdmaSector() {  
  108.         return qingAoPlaceCdmaSector;  
  109.     }  
  110.   
  111.     public void setQingAoPlaceCdmaSector(  
  112.             List<QingAoPlaceCdmaSector> qingAoPlaceCdmaSector) {  
  113.         this.qingAoPlaceCdmaSector = qingAoPlaceCdmaSector;  
  114.     }  
  115.     @OneToMany(mappedBy="qingAoPlaceInfo",cascade= CascadeType.ALL)  
  116.     public List<QingAoPlaceLteSector> getQingAoPlaceLteSector() {  
  117.         return qingAoPlaceLteSector;  
  118.     }  
  119.   
  120.     public void setQingAoPlaceLteSector(  
  121.             List<QingAoPlaceLteSector> qingAoPlaceLteSector) {  
  122.         this.qingAoPlaceLteSector = qingAoPlaceLteSector;  
  123.     }  
  124.     @OneToMany(mappedBy="qingAoPlaceInfo",cascade= CascadeType.ALL)  
  125.     public List<QingAoAp> getQingAoAp() {  
  126.         return qingAoAp;  
  127.     }  
  128.   
  129.     public void setQingAoAp(List<QingAoAp> qingAoAp) {  
  130.         this.qingAoAp = qingAoAp;  
  131.     }  
  132. }  


3、Hibernate4 注解版关系案例

一对多和多对一

公司用的maven 所以我也是建的maven工程,导入hibernate4的jar包

[html]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1.    <dependency>   
  2. <groupId>org.hibernate</groupId>   
  3. <artifactId>hibernate-core</artifactId>   
  4. <version>4.1.6.Final</version>   
  5.    </dependency>   

但是oracle的驱动包,好像要自己手动加。不知道有没有用maven直接从网上加的方法。

hibernate.cfg.xml  文件

[html]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. <!DOCTYPE hibernate-configuration PUBLIC  
  2.     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"  
  3.     "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">  
  4.   
  5. <hibernate-configuration>  
  6. <session-factory>  
  7.   
  8.     <!-- 数据库信息 -->  
  9.     <property name="dialect">  
  10.         org.hibernate.dialect.Oracle10gDialect  
  11.     </property>  
  12.     <property name="connection.url">jdbc:oracle:thin:@192.168.15.102:1521:ora11g</property>  
  13.     <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>  
  14.     <property name="connection.username">iris_ecnu_dev</property>  
  15.     <property name="connection.password">iris_ecnu_dev</property>  
  16.           
  17.     <!-- 其他配置 -->  
  18.     <property name="show_sql">true</property>  
  19.     <property name="hbm2ddl.auto">update</property>  
  20.     <property name="format_sql">true</property>  
  21.       
  22.     <!-- 导入映射配置  -->  
  23.     <mapping class="cn.lzg.Order" />  
  24.     <mapping class="cn.lzg.Person" />  
  25. </session-factory>  
  26. </hibernate-configuration>  

Order.java 文件 

[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. package cn.lzg;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import javax.persistence.Column;  
  6. import javax.persistence.Entity;  
  7. import javax.persistence.FetchType;  
  8. import javax.persistence.GeneratedValue;  
  9. import javax.persistence.GenerationType;  
  10. import javax.persistence.Id;  
  11. import javax.persistence.JoinColumn;  
  12. import javax.persistence.ManyToOne;  
  13. import javax.persistence.SequenceGenerator;  
  14. import javax.persistence.Table;  
  15.   
  16. @Entity  
  17. @Table(name = "order_lzg")  
  18. public class Order {  
  19.   
  20.     @Id  
  21.     @SequenceGenerator(name = "order_lzg", sequenceName = "o_seq", allocationSize = 1)  
  22.     @GeneratedValue(generator = "order_lzg", strategy = GenerationType.SEQUENCE)  
  23.     private Long order_id;  
  24.   
  25.     @Column(name = "submit_time")  
  26.     private Date submit_time;  
  27.   
  28.     @ManyToOne(fetch = FetchType.LAZY)  
  29.     @JoinColumn(name = "p_id")  
  30.     // order_lzg表 里面 放person_lzg ID的列  
  31.     private Person person_lzg;  
  32.   
  33.     public Order() {  
  34.     }  
  35.   
  36.     public Long getOrder_id() {  
  37.         return order_id;  
  38.     }  
  39.   
  40.     public void setOrder_id(Long order_id) {  
  41.         this.order_id = order_id;  
  42.     }  
  43.   
  44.     public Date getSubmit_time() {  
  45.         return submit_time;  
  46.     }  
  47.   
  48.     public void setSubmit_time(Date submit_time) {  
  49.         this.submit_time = submit_time;  
  50.     }  
  51.   
  52.     public Person getPerson_lzg() {  
  53.         return person_lzg;  
  54.     }  
  55.   
  56.     public void setPerson_lzg(Person person_lzg) {  
  57.         this.person_lzg = person_lzg;  
  58.     }  
  59.   
  60. }  

Person.java 文件

[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. package cn.lzg;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. import javax.persistence.CascadeType;  
  7. import javax.persistence.Column;  
  8. import javax.persistence.Entity;  
  9. import javax.persistence.FetchType;  
  10. import javax.persistence.GeneratedValue;  
  11. import javax.persistence.GenerationType;  
  12. import javax.persistence.Id;  
  13. import javax.persistence.OneToMany;  
  14. import javax.persistence.SequenceGenerator;  
  15. import javax.persistence.Table;  
  16.   
  17. @Entity  
  18. @Table(name = "person_lzg")  
  19. public class Person {  
  20.   
  21.     @Id  
  22.     @SequenceGenerator(name = "person_lzg", sequenceName = "p_seq", allocationSize = 1)  
  23.     @GeneratedValue(generator = "person_lzg", strategy = GenerationType.SEQUENCE)  
  24.     private Long p_id;  
  25.   
  26.     @Column(name = "name")  
  27.     private String name;  
  28.   
  29.     @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person_lzg")  
  30.     // mappedBy的值,是Order对象里面存Person对象的属性的值  
  31.     private Set<Order> orderSet = new HashSet<Order>();  
  32.   
  33.     public Long getp_id() {  
  34.         return p_id;  
  35.     }  
  36.   
  37.     public void setp_id(Long p_id) {  
  38.         this.p_id = p_id;  
  39.     }  
  40.   
  41.     public String getName() {  
  42.         return name;  
  43.     }  
  44.   
  45.     public void setName(String name) {  
  46.         this.name = name;  
  47.     }  
  48.   
  49.     public Set<Order> getOrderSet() {  
  50.         return orderSet;  
  51.     }  
  52.   
  53.     public void setOrderSet(Set<Order> orderSet) {  
  54.         this.orderSet = orderSet;  
  55.     }  
  56.   
  57. }  


多对多

其实它的和 一对多 差不多,但是按照网上写法出现了一个问题,使得 双向的关系变成了单向的。

Person类

[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. package cn.lzg;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import javax.persistence.Column;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.FetchType;  
  9. import javax.persistence.GeneratedValue;  
  10. import javax.persistence.GenerationType;  
  11. import javax.persistence.Id;  
  12. import javax.persistence.JoinColumn;  
  13. import javax.persistence.JoinTable;  
  14. import javax.persistence.ManyToMany;  
  15. import javax.persistence.SequenceGenerator;  
  16. import javax.persistence.Table;  
  17.   
  18. @Entity  
  19. @Table(name = "person_lzg")  
  20. public class Person {  
  21.   
  22.     @Id  
  23.     @SequenceGenerator(name = "person_lzg", sequenceName = "p_seq", allocationSize = 1)  
  24.     @GeneratedValue(generator = "person_lzg", strategy = GenerationType.SEQUENCE)  
  25.     private Long p_id;  
  26.   
  27.     @Column(name = "name")  
  28.     private String name;  
  29.   
  30.     @ManyToMany(targetEntity = cn.lzg.Book.class, fetch = FetchType.LAZY)  
  31.     @JoinTable(name = "lzgp_lzgb", joinColumns = { @JoinColumn(name = "p_id") }, inverseJoinColumns = { @JoinColumn(name = "b_id") })  
  32.     // name中间表的名字,第一个自己的主键,第二个关联的主键  
  33.     private List<Book> books = new ArrayList<Book>();  
  34.   
  35.     public Long getP_id() {  
  36.         return p_id;  
  37.     }  
  38.   
  39.     public void setP_id(Long p_id) {  
  40.         this.p_id = p_id;  
  41.     }  
  42.   
  43.     public String getName() {  
  44.         return name;  
  45.     }  
  46.   
  47.     public void setName(String name) {  
  48.         this.name = name;  
  49.     }  
  50.   
  51.     public List<Book> getBooks() {  
  52.         return books;  
  53.     }  
  54.   
  55.     public void setBooks(List<Book> books) {  
  56.         this.books = books;  
  57.     }  
  58.   
  59. }  
Book类

[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. package cn.lzg;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import javax.persistence.Column;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.FetchType;  
  9. import javax.persistence.GeneratedValue;  
  10. import javax.persistence.GenerationType;  
  11. import javax.persistence.Id;  
  12. import javax.persistence.JoinColumn;  
  13. import javax.persistence.JoinTable;  
  14. import javax.persistence.ManyToMany;  
  15. import javax.persistence.SequenceGenerator;  
  16. import javax.persistence.Table;  
  17.   
  18. @Entity  
  19. @Table(name = "book_lzg")  
  20. public class Book {  
  21.     @Id  
  22.     @SequenceGenerator(name = "book_lzg", sequenceName = "b_seq", allocationSize = 1)  
  23.     @GeneratedValue(generator = "book_lzg", strategy = GenerationType.SEQUENCE)  
  24.     private Long b_id;  
  25.   
  26.     @Column(name = "name")  
  27.     private String name;  
  28.   
  29.     @ManyToMany(targetEntity = cn.lzg.Person.class, fetch = FetchType.LAZY)  
  30.     <span style="color:#FF0000;">// 如果在上面使用mappedBy后,就成单向的了.也就是mappedBy出现的位置所在的类,这个类是被维护端,它只能被别人级联,不能去保存别人.  
  31.     // 这个问题搞了好久才发现,开始一直是单向的.</span>  
  32.     @JoinTable(name = "lzgp_lzgb", joinColumns = { @JoinColumn(name = "b_id") }, inverseJoinColumns = { @JoinColumn(name = "p_id") })  
  33.     private List<Person> persons = new ArrayList<Person>();  
  34.   
  35.     public Long getB_id() {  
  36.         return b_id;  
  37.     }  
  38.   
  39.     public void setB_id(Long b_id) {  
  40.         this.b_id = b_id;  
  41.     }  
  42.   
  43.     public String getName() {  
  44.         return name;  
  45.     }  
  46.   
  47.     public void setName(String name) {  
  48.         this.name = name;  
  49.     }  
  50.   
  51.     public List<Person> getPersons() {  
  52.         return persons;  
  53.     }  
  54.   
  55.     public void setPersons(List<Person> persons) {  
  56.         this.persons = persons;  
  57.     }  
  58.   
  59. }  
注意

[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. <span style="color:#FF0000;">如果在上面ManyToMany注解中使用mappedBy,就成单向的了.因为mappedBy出现的位置所在的类,这个类是被维护端,它只能被别人级联,不能去保存别人  
  2.   
  3. <span style="color:#330033;">测试类  
  4. </span></span><pre name="code" class="java">package cn.lzg;  
  5.   
  6. import java.util.ArrayList;  
  7. import java.util.Date;  
  8. import java.util.List;  
  9.   
  10. import org.hibernate.Session;  
  11. import org.hibernate.SessionFactory;  
  12. import org.hibernate.Transaction;  
  13. import org.hibernate.cfg.Configuration;  
  14. import org.hibernate.service.ServiceRegistry;  
  15. import org.hibernate.service.ServiceRegistryBuilder;  
  16. import org.junit.Test;  
  17.   
  18. public class TestHibernate {  
  19.     private static Configuration configuration = null;  
  20.     private static SessionFactory sessionFactory = null;  
  21.     private static ServiceRegistry serviceRegistry = null;  
  22.     private static Session session = null;  
  23.   
  24.     static {  
  25.         /** 
  26.          * hibernate 4 貌失要这样获得sessionFactory 以前的configuration.buildSessionFactory();方法 过时了 
  27.          */  
  28.         configuration = new Configuration().configure();  
  29.   
  30.         serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())  
  31.                 .buildServiceRegistry();  
  32.   
  33.         sessionFactory = configuration.buildSessionFactory(serviceRegistry);  
  34.         session = sessionFactory.openSession();  
  35.     }  
  36.   
  37.   
  38.   
  39.     @Test  
  40.     // 测试manytomany  
  41.     public void testM2M() {  
  42.         Person p1 = new Person();  
  43.         p1.setName("张三");  
  44.         Person p2 = new Person();  
  45.         p2.setName("李四");  
  46.         Person p3 = new Person();  
  47.         p3.setName("王五");  
  48.         List<Person> persons = new ArrayList<Person>();  
  49.         persons.add(p1);  
  50.         persons.add(p2);  
  51.         persons.add(p3);  
  52.   
  53.         Book b1 = new Book();  
  54.         b1.setName("书本1");  
  55.         Book b2 = new Book();  
  56.         b2.setName("书本2");  
  57.         Book b3 = new Book();  
  58.         b3.setName("书本3");  
  59.         List<Book> books = new ArrayList<Book>();  
  60.         books.add(b1);  
  61.         books.add(b2);  
  62.         books.add(b3);  
  63.   
  64.         p1.setBooks(books);  
  65.         b3.setPersons(persons);  
  66.   
  67.         Transaction tx = session.beginTransaction();  
  68.         session.save(p1);  
  69.         session.save(p2);  
  70.         session.save(p3);  
  71.         session.save(b1);  
  72.         session.save(b2);  
  73.         session.save(b3);  
  74.         tx.commit();  
  75.         session.close();  
  76.     }  
  77. }  


 
 结果生成了中间表 
 
[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. lzgp_lzgb 里面的关系p1 有三本书, p1,p2,p3都有b3  

HIbernate注解多对多关系要点总结

最近在公司做一个小项目,框架的持久层我选用的是Hibernate annotation,用户和他收藏的网站的关系是多对多的关系,一个用户可以收藏多个他喜爱的网站;反过来,一个网站也可以被多个用户收藏。
因此在设计类的时候,我设计了一个Sysuser(用户)类和一个Website(网站)类。

在配置注解的时候,由于在用户和网站之前,用户是主控方,网站是被控方。所以我在Sysuser类的getWebsite()方法上加了下面一段内容进行注解。

[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. @ManyToMany(fetch=FetchType.EAGER,cascade={CascadeType.PERSIST,CascadeType.MERGE})  
  2.     @JoinTable(name="user_web",joinColumns=@JoinColumn(name="userid"),  
  3.             inverseJoinColumns=@JoinColumn(name="webid"))  
  4.     public Set<Website> getWebsite() {  
  5.         return website;  
  6.     }  
  7.     public void setWebsite(Set<Website> website) {  
  8.         this.website = website;  
  9.     }  

其中@ManyToMany就不用说了,指明用户和网站之前是多对多的关系。这里需要说的是,在主控方的get那个set集合的方法上面需要再加上@JoinTable进行注解,其中name="user_web"就是指在数据库中体现多对多关系的中间表是user_web,指定之后在首次运行项目的时候会在数据库中自动生成这个中间表,而且这个中间表不需要写个类去对应,可以通过这两个有多对多关系的类去维护第三章表的数据。joinColumns=@JoinColumn(name="userid")这句话的意思是是定义中间表与Sysuser这个类外键关系,中间表是通过userid这一列产生外键关联的,而inverseJoinColumns是中间表参考另一张的表的主键生成的列。

在Website类的getSysuser()方法上加了下面一段内容进行注解

[java]  view plain copy Hibernate注解版关联关系映射全解析+案例 Hibernate注解版关联关系映射全解析+案例
  1. @ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST},mappedBy="website")  
  2.     public Set<Sysuser> getSysuser() {  
  3.         return sysuser;  
  4.     }  
  5.     public void setSysuser(Set<Sysuser> sysuser) {  
  6.         this.sysuser = sysuser;  
  7.     }  

其中的@ManyToMany也不用说了,指明网站与用户之间是多对多的关系。需要说明的是在被控方,需要加上mappedBy,例如这里的mappedBy="website"是产生关系的属性。

总结一下需要注意的几点:

1、只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性,ManyToOne不存在该属性;

2、mappedBy标签一定是定义在the owned side(被控方,或者叫被拥有方),他指向the owning side(主控方,或者叫做拥有方);

3、mappedBy跟JoinColumn/JoinTable总是处于互斥的一方,可以理解为正是由于拥有方的关联被拥有方的字段存在,拥有方才拥有了被拥有方。mappedBy这方定义的JoinColumn/JoinTable总是失效的,不会建立对应的字段或者表。

Hibernate Annotation关系映射的几种类型映射用法及使用方法

Hibernate Annotation关系映射的几种类型映射用法及使用方法(说明:以前实例的实体是user和role,主键分别是userid和roleid)

1)一对一外键关联映射(单向)
@OneToOne(cascade=CascadeType.ALL) //一对一外键关联,使用@OneToOne,并设置了级联操作
@JoinColumn(name="userid",unique=true) //@JoinColum设置了外键的名称为userid(数据库字段名),如果不设置,则默认为另一类的属性名+ _id。外键的值是唯一的(unique),不可重复,与另一类的主键一直

2)一对一外键关联映射(双向)
@OneToOne(mappedBy=" role",cascade=CascadeType.ALL) //一对一双向关联关系,使用@OneToOne。注意:需要加上mappedBy="role",如果不加上的话, role 也会生成一个外键(user_id),mappedby="role"需要指向与他关联对象的一个属性,说明双向关联关系中,有且仅有一端是作为主体(owner)端存在的,主体端负责维护联接列,对于不需要维护这种关系的从表则通过mappedBy属性进行声明,mappedBy的值指向主体的关联属性
//规律:只有是双向关联关系,都加上mappedby,cascade=CascadeType.ALL级联

3)一对一主键关联映射(不重要)
在实际中很少用,使用注解@PrimaryKeyJoinColumn,意思是说,我的主键去参考另外一张表中的主键,作为我的主键,但是在我测试使用注解一对一主键关联映射,在生成表的时候,数据库中并没有生成关联,使用XML映射可以生成。Annotation注解一对一主键关联映,有些bug。不过没空去研究它。因为在实际开发中一对一很少用。在实际开发中我机会没有用过,主键关联就更少了

4)多对一关联映射
多端配置
@ManyToOne(targetEntity=role.class) //多对一注解@ManyToOne;targetEntity指定了关联对象
@JoinColumn(name="userid") //@JoinColumn(name="userid")指定生产的外键的字段名,默认是org_id

5)一对多关联映射(单向)
@OneToMany //一对多注解@OneToMany(单向),如果只写@OneToMany的话,hibernate会建一张中间表来维护他们之间的关系
@JoinColumn(name="roleid") //加上@JoinColumn(name="roleid"),则不会建中间表,他会在多的一端加上外键roleid,来维护他们之间的关系

6)一对多关联映射(双向)
一端配置
@OneToMany(mappedBy="role") //一对多双向,在一的一端中设置mappedBy,说明多的一端为主导
@JoinColumn(name="roleid") //如果指定了外键字段名称,则多的一端也需要指定相同的字段名称

多端配置
@ManyToOne //一对多双向
@JoinColumn(name=" roleid ") //需要指定外键与一的一端给的外键名称一致,@JoinColumn(name=" roleid "),也可以不指定,如果在多的一端不指定,则一的一端也不能指定,否则为生成两个外键

7)多对多关联映射(单向)
@ManyToMany //多对多映射:注解@ManyToMany(单向),默认情况下,hibernate会自动的创建一张中间表来维护多对多关系

默认中间表的名称 :user_role中间表,字段的名称user_id role_id,如果想更换表名和字段名称,注解如下:
@JoinTable(name="t_u_r",joinColumns={@JoinColumn(name="u_id")},inverseJoinColumns={@JoinColumn(name="r_id")})

8)多对多关联映射(双向)
user端
@ManyToMany //多对多映射:注解@ManyToMany(单向);默认情况下,hibernate会自动的创建一张中间表,来维护多对多关系;默认中间表的名称 :user_role中间表,字段的名称user_id role_id
如果想更换表名和字段名称,注解如下:
@JoinTable(name="t_u_r",joinColumns={@JoinColumn(name="u_id")},inverseJoinColumns={@JoinColumn(name="r_id")}) //@JoinTable(name="t_u_r"),指定中间表的表名;joinColumns={@JoinColumn(name="u_id")},指定当前对象的外键;inverseJoinColumns={@JoinColumn(name="r_id")},指定关联对象的外键

role端
@ManyToMany(mappedBy="role") //多对多,双向关联映射



Hibernate Annotation笔记


在过去几年里,Hibernate不断发展,几乎成为Java数据库持久性的事实标准。它非常强大、灵活,而且具备了优异的性能。在本文中,我们将了解如何使用Java 5 注释来简化Hibernate代码,并使持久层的编码过程变得更为轻松。
  传统上,Hibernate的配置依赖于外部 XML 文件:数据库映射被定义为一组 XML 映射文件,并且在启动时进行加载。
    在最近发布的几个Hibernate版本中,出现了一种基于 Java 5 注释的更为巧妙的新方法。借助新的 Hibernate Annotation 库,即可一次性地分配所有旧映射文件——一切都会按照您的想法来定义——注释直接嵌入到您的Java 类中,并提供一种强大及灵活的方法来声明持久性映射。
即利用hibernate注解后,可不用定义持久化类对应的*.hbm.xml文件,直接以注解方式写入在持久化类中来实现。
Hibernate annotation使用了ejb JPA的注解,所以,下面安装配置hibernate annotation环境时,需要导入ejb的包。许多网上的资料都是jpa hibernate annotation方面的资料。
(2)
安装 Hibernate Annotation
第一步,
环境与jar包:
  要使用 Hibernate Annotation,您至少需要具备 Hibernate 3.2和Java 5。可以从 Hibernate 站点下载 Hibernate 3.2 和 Hibernate Annotation库。除了标准的 Hibernate JAR 和依赖项之外,您还需要 Hibernate Annotations .jar 文件(hibernate-annotations.jar)、Java 持久性 API (lib/ejb3-persistence.jar)。
添加hibernate3.2.jar,hibernate-annotations-3.3.0.jar,hibernate-commons-annotations.jar和ejb3-persistence.jar 。这样就可以使用hibernate的annotation了。

如果您正在使用 Maven,只需要向 POM 文件添加相应的依赖项即可,如下所示:
    ...
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate</artifactId>
      <version>3.2.1.ga</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-annotations</artifactId>
      <version>3.2.0.ga</version>
    </dependency>
    <dependency>
      <groupId>javax.persistence</groupId>
      <artifactId>persistence-api</artifactId>
      <version>1.0</version>
    </dependency>
第二步,
获取 Hibernate 会话工厂。尽管无需惊天的修改,但这一工作与使用 Hibernate Annotations有所不同。您需要使用 AnnotationConfiguration 类来建立会话工厂:
sessionFactory = new AnnotationConfiguration().buildSessionFactory(); 
第三步,
尽管通常使用 <mapping> 元素来声明持久性类,您还是需要在 Hibernate 配置文件(通常是 hibernate.cfg.xml)中声明持久性类:
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    " http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
        <hibernate-configuration>
          <session-factory>
            <mapping class="com.onjava.modelplanes.domain.PlaneType"/>
            <mapping class="com.onjava.modelplanes.domain.ModelPlane"/>
          </session-factory>
        </hibernate-configuration>
  近期的许多 Java 项目都使用了轻量级的应用框架,例如 Spring。如果您正在使用 Spring 框架,可以使用
AnnotationSessionFactoryBean 类轻松建立一个基于注释的 Hibernate 会话工厂,如下所示:
<!-- Hibernate session factory -->
  <bean id="sessionFactory"
       class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
   <property name="dataSource">
     <ref bean="dataSource"/>
   </property>
   <property name="hibernateProperties">
     <props>
       <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
       <prop key="hibernate.hbm2ddl.auto">create</prop>
       ...
     </props>
   </property>
   <property name="annotatedClasses">
     <list>
       <value>com.onjava.modelplanes.domain.PlaneType</value>
       <value>com.onjava.modelplanes.domain.ModelPlane</value>

       ...
     </list>
   </property>
</bean>
(3)
hibernate Annotation标签的使用:
[1]
1.带注释的持久性类也是普通 POJO,它们只是具备了持久性注释的普通 POJO 。
2.事实上,您既可以保持字段的持久性(注释写在成员变量之上),也可以保持属性(注释写在getter方法之上)的持久性。
3.常用的hibernate annotation标签如下:
@Entity              --注释声明该类为持久类。将一个Javabean类声明为一个实体的数据库表映射类,最好实现序列化.此时,默认情况下,所有的类属性都为映射到数据表的持久性字段.若在类中,添加另外属性,而非映射来数据库的,要用下面的Transient来注解.

@Table(name= "promotion_info")      --持久性映射的表(表名="promotion_info).@Table是类一级的注解,定义在@Entity下,为实体bean映射表,目录和schema的名字, 默认为实体bean的类名,不带包名.

@Id--注释可以表明哪种属性是该类中的独特标识符(即相当于数据表的主键)。 
@GeneratedValue   --定义自动增长的主键的生成策略. 
@Transient             --将忽略这些字段和属性,不用持久化到数据库.适用于,在当前的持久类中,某些属性不是用于映射到数据表,而是用于其它的业务逻辑需要,这时,须将这些属性进行transient的注解.否则系统会因映射不到数据表相应字段而出错. 
@Temporal(TemporalType.TIMESTAMP)--声明时间格式 
@Enumerated         --声明枚举 
@Version                --声明添加对乐观锁定的支持 
@OneToOne            --可以建立实体bean之间的一对一的关联 
@OneToMany          --可以建立实体bean之间的一对多的关联 
@ManyToOne          --可以建立实体bean之间的多对一的关联 
@ManyToMany        --可以建立实体bean之间的多对多的关联 
@Formula               --一个SQL表达式,这种属性是只读的,不在数据库生成属性(可以使用sum、average、max等) 
@OrderBy               --Many端某个字段排序(List)
 
1.2
Hibernate 能够出色地自动生成主键。Hibernate/EBJ 3 注释也可以为主键的自动生成提供丰富的支持,允许实现各种策略。
其生成规则由@GeneratedValue设定的.这里的@id和@GeneratedValue都是JPA的标准用法, JPA提供四种标准用法,由@GeneratedValue的源代码可以明显看出. 
JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO. 
TABLE:使用一个特定的数据库表格来保存主键。 
SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。 
IDENTITY:主键由数据库自动生成(主要是自动增长型) 
AUTO:主键由程序控制。 
在指定主键时,如果不指定主键生成策略,默认为AUTO。 
@Id
相当于
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
 
identity:
使用SQL Server 和 MySQL 的自增字段,这个方法不能放到 Oracle 中,Oracle 不支持自增字段,要设定sequence(MySQL 和 SQL Server 中很常用)。
Oracle就要采用sequence了.
 
同时,也可采用uuid,native等其它策略.(相关用法,上网查询)
[2]
第一个持久性类 
@Entity 
@Table(name= "T_MODEL_PLANE"
public  class ModelPlane     implements Serializable { 
        @Id 
        @Column(name= "PLANE_ID")    
        @GeneratedValue(strategy=GenerationType.AUTO)  //注解于属性中 
/* 
对于oracle想使用各自的Sequence,设置如下:        
@GeneratedValue(strategy = GenerationType.AUTO,generator="PROMOTION_SEQ")        
@SequenceGenerator(name="PROMOTION_SEQ",sequenceName="PROMOTION_SEQ")    
 
另外:
对于自动增长后,在数据表中的相应字段,要设置字段为auto_increment.
*/
 
         private Long id; 

         private String name; //注解写于getter方法之上.请见下. 

      //DATE            - java.sql.Date        
      //TIME            - java.sql.Time        
      //TIMESTAMP - java.sql.Timestamp        
     @Temporal(TemporalType.TIMESTAMP)        
     @Column(name= "start_time")        
      private Date startTime;     

      //显示0 隐藏1        
      public  static  enum DisplayType {显示,隐藏}        
     @Enumerated(value = EnumType.ORDINAL) //ORDINAL序数        
      private DisplayType displayType = DisplayType.显示;    

         //1.sql语句中的字段和表名都应该和数据库相应,而不是类中的字段,        
      //若带有参数如la.id= id,这个=id才是类中属性        
      //2.操作字段一定要用别名        
     @Formula(select COUNT(la.id) from largess la)        
      private  int count;    

         //注解于方法中 
        @Column(name= "PLANE_ID", length=80, nullable= true//较详细定义 
         public String getName() { 
                 return name; 
        } 
         public  void setName(String name) { 
                 this.name = name; 
        } 
其它的setter,getter省略...... 
}

该内容将映射到下表中: 
CREATE TABLE T_MODEL_PLANE 

        PLANE_ID  long
        PLANE_NAME varchar 
        其它字段省略... 
)    
默认情况下,Hibernate 会将持久类以匹配的名称映射到表和字段中。例如,下例中,若不用注解,则会映射到如下一表中:
CREATE TABLE MODELPLANE
(
    ID long,
    NAME varchar
    其它字段省略...
)
[3]
一对多注解:
1.
在一对多注解中,会用到:
"一"方:
@OneToMany --> mappedBy:"多"方的关联属性 (被控方)
"多"方:
@ManyToOne --> @JoinColumn,"多"方定义的外键字段.
如数据表定义外键如下:
FOREIGN KEY (classid) REFERENCES classes(id)
则:
@JoinColumn(name= "classid"
2.
在双向关联中,有且仅有一端作为主体(owner)端存在:主体端负责维护联接列(即更新),对于不需要维护这种关系的从表则通过mappedNy属性进行声明。mappedBy的值指向另一主体的关联属性。例子中,mappedBy的值为classes。
附加说明:
mappedBy相当于过去的inverse="true".
inverse=false的side(side其实是指inverse=false所位于的class元素)端有责任维护关系,而inverse=true端无须维护这些关系。
3.
cascade与fetch使用说明:
Cascade
CascadeType.PERSIST (级联新建) 
CascadeType.REMOVE  (级联删除) 
CascadeType.REFRESH (级联刷新) 
CascadeType.MERGE   (级联更新)中选择一个或多个。 
CascadeType.ALL
 fetch属性:
关联关系获取方式,即是否采用延时加载。
 LAZY(默认值)采用延时加载,查询数据时,不一起查询关联对象的数据。而是当访问关联对象时(如:getStudnets()时)才触发相应的查询操作,获取关联对象数据。
EAGER:是在查询数据时,也直接一起获取关联对象的数据。
package oneToMany; 
import java.util.Set; 
import javax.persistence.*; 
/* 
注意导入时,是导入:import javax.persistence.*;    
非导入org.hibernate的相关类:import org.hibernate.annotations.Entity; 
*/
 
@Entity 
@Table(name= "classes"
public  class Classes  implements Serializable { 
  @Id 
  @GeneratedValue(strategy=GenerationType.AUTO) 
   private  int id; 
   private String name; 
    
  @OneToMany(cascade=CascadeType.ALL,mappedBy= "classes")    
   private Set<Student> students; 
//getter,setter省略 



package oneToMany; 
import javax.persistence.*; 
@Entity 
@Table(name= "student"
public  class Student  implements Serializable  { 
  @Id 
  @GeneratedValue(strategy=GenerationType.AUTO) 
   private  int sid; 
    
   private String sname; 
    
   //若有多个cascade,可以是:{CascadeType.PERSIST,CascadeType.MERGE} 
  @ManyToOne(cascade={CascadeType.ALL})         
  @JoinColumn(name= "classid")      //student类中对应外键的属性:classid 
   private Classes classes; 
//getter,setter省略 



public  class TestOneToMany { 
/* 
CREATE TABLE    student (    --要定义外键!!!!!!! 
    `sid` double NOT NULL auto_increment, 
    `classid` double NULL, 
    `sname` varchar(255) NOT NULL, 
    PRIMARY KEY    (sid), 
    INDEX par_ind (classid), 
    FOREIGN KEY (classid) REFERENCES classes(id) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB 
*/
    
   public  static  void main(String[] args)  throws SQLException    
  { 
     try 
    { 
      SessionFactory sf =  new AnnotationConfiguration().configure().buildSessionFactory(); 
      Session session=sf.openSession(); 
      Transaction tx=session.beginTransaction();         
/*
因为mappedBy是定义在classes中,即classes类不负责维护级联关系.即维护者是student.所以,
1.要将clsses的数据,赋给student,即用student的setClasses()方法去捆定class数据;
2.在进行数据插入/更新session.save()/session.update()时,最后操作的是student.
*/
      Classes classes= new Classes(); 
      classes.setName( "access"); 
        
      Student st1= new Student(); 
      st1.setSname( "jason"); 
      st1.setClasses(classes); 
      session.save(st1); 
        
      Student st2= new Student(); 
      st2.setSname( "hwj"); 
      st2.setClasses(classes); 
      session.save(st2); 
      tx.commit();
/* 
输出如下:
Hibernate: insert into classes (name) values (?)
Hibernate: insert into student (classid, sname) values (?, ?)
Hibernate: insert into student (classid, sname) values (?, ?)
*/
/*
因为一端维护关系另一端不维护关系的原因,我们必须注意避免在应用中用不维护关系的类(class)建立关系,因为这样建立的关系是不会在数据库中存储的。
如上的代码倒过来,则插入时,student的外键值为空.如下:
*/
//      Student st1=new Student(); 
//      st1.setSname("jason"); 

//      session.save(st1); 
//        
//      Student st2=new Student(); 
//      st2.setSname("hwj"); 
//      session.save(st2); 
//        
//      Set<Student> students=new HashSet<Student>(); 
//      students.add(st1); 
//      students.add(st2); 
//        
//      Classes classes=new Classes(); 
//      classes.setName("access"); 
//      classes.setStudents(students); 
//      session.save(classes); 
/*
输出如下:
Hibernate: insert into student (classid, sname) values (?, ?)
Hibernate: insert into student (classid, sname) values (?, ?)
Hibernate: insert into classes (name) values (?)
*/
    } 
     catch(HibernateException e) 
    { 
      e.printStackTrace();        
    } 
  } 
}
 
 
[4]
多对多注解: 
在多对多注解中,双方都采用@ManyToMany.
其中被控方,像一对多注解中设置一样,也要设置mappedBy.
其中主控方,不像一对多注解那样,采用@joinColumn,而是采用@joinTable.如下:
@JoinTable(name="j_student_course" ,joinColumns={@JoinColumn(name="sid")},inverseJoinColumns={@JoinColumn(name="cid")})
其中,
如上所说,mappedBy,相当于inverse="true".所以,在@joinTable中的inverseJoinColumns中定义的字段为mappedBy所在类的主键.
joinColumns定义的字段,就是当前类的主键.
@Entity 
@Table(name= "jcourse"
public  class Jcourse { 
  @Id 
  @GeneratedValue(strategy=GenerationType.AUTO) 
   private  int cid; 
   private String cname; 
    
  @ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE},fetch=FetchType.LAZY ,mappedBy= "courses"
   private Set<Jstudent> students; 
//setter,getter省略....    



@Entity 
@Table(name= "jstudent"
public  class Jstudent { 
  @Id 
  @GeneratedValue(strategy=GenerationType.AUTO) 
   private  int sid; 
    
   private String sname; 
    
  @ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE},fetch=FetchType.EAGER) 
   //inverseJoinColumns中对应的id为以下属性course的对应id. 
  @JoinTable(name= "j_student_course" ,joinColumns={@JoinColumn(name= "sid")},inverseJoinColumns={@JoinColumn(name= "cid")}) 
   private Set<Jcourse> courses; 
//setter,getter省略....    



public  class Test { 
   public  static  void main(String[] args) { 
     try 
    { 
      SessionFactory sf =  new AnnotationConfiguration().configure().buildSessionFactory(); 
      Session session=sf.openSession(); 
      Transaction tx=session.beginTransaction(); 
        
      Jcourse course= new Jcourse(); 
      course.setCname( "jason-english"); 
      session.save(course);  //先各自保存. 
        
      Jcourse course2= new Jcourse(); 
      course2.setCname( "herry-english"); 
      session.save(course2); 
        
      Set<Jcourse> courses= new HashSet<Jcourse>(); 
      courses.add(course); 
      courses.add(course2); 
        
      Jstudent student= new Jstudent(); 
      student.setSname( "jason"); 
      student.setCourses(courses); 
        
      session.save(student); // 要用非mapby定义的类(studet)来作为主者(会控制级联关系),一对多,多对一也一样道理. 
       //可以尝试反过来. 
      tx.commit(); 
    } 
     catch(HibernateException e) 
    { 
      e.printStackTrace();        
    } 
  } 
}