Hibernate
什么是ORM
ORM(Object/Rlationship Mapping) :对象、关系映射
利用面向对象思想编写的数据库应用程序最终都是把对象信息保存在关系数据库中,于是要编写很多和底层数据库相关的SQL语句。(这个和我们的面向对象思想是不符的)
在代码中写SQL语句有什么不好?
1. 不同的数据库使用SQL语法不同。比如:PL/SQL(Oracle)与T/SQL(SQL servler),所以代码中的sql语句不能保证在所有的数据库上都可以正常运行。
2. 同样的功能在不同的数据库中有不同的实现方式。比如分页SQL。
3. 程序过分依赖SQL对程序的移植及扩展,维护带来很大的麻烦。
什么是Hibernate
Hibernate是Java领域的一款开源的ORM框架技术。
Hibernate对JDBC进行了非常轻量级的对象封装。
其他主流的ORM框架技术
1. MyBatis:前身是著名的iBatis
2. Toplink:后被Oracle收购,并重新包装为OracleAS TopLink
3. EJB: 本身是JAVAEE 的规范。
第一个Hibernate例子
开发工具:Eclipse Hibernate Tools forEclipse Plugins(Hibernate Tools 是由JBoss推出的一个Eclipse综合开发工具插件,该插件可以简化ORM框架Hibernate,以及JBoss Seam,EJB3的开发工作。)
安装插件 点击打开链接
基本步骤:
1. 创建Hibernate的配置文件。(hibernate.cfg.xml)
2. 创建持久化类。
3. 创建对象-关系映射文件。
4. 通过Hibernate API编写访问数据库的代码。
1.导入jar包,window/preference/UserLibraries ,新建并导入我们需要的jar包,然后在对应工程中加入。
2.创建Hibernate的配置文件,如果配置文件中没有提示功能,我们还需要导入一个dtd文件
Hibernate-release-xxxx/project/hibernate-core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd
Hibernate.cfg.xml的配置<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.password">limeng</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://127.0.0.1:3306/hibernate?useUnicode=true&characterEncoding=UTF-8</property>
<!-- 指定mysql的方言 -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">create</property>
<mapping resource="com/hibernate/beans/Students.hbm.xml"/>
</session-factory>
</hibernate-configuration>
创建实体类
//学生类
public class Students {
private int sid;//学号
private String sname;//姓名
private Date birthday;//出生日期
private String gender;//性别
public Students(){}
public Students(int sid, String sname, Date birthday, String gender) {
super();
this.sid = sid;
this.sname = sname;
this.birthday = birthday;
this.gender = gender;
}
public String toString() {
return "Students [sid=" + sid + ", sname=" + sname + ", birthday="
+ birthday + ", gender=" + gender + "]";
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
创建映射文件
<hibernate-mapping>
<class name="com.hibernate.beans.Students" table="STUDENTS">
<id name="sid" type="int">
<column name="SID" />
<generator class="assigned" />
</id>
<property name="sname" type="java.lang.String">
<column name="SNAME" />
</property>
<property name="birthday" type="java.util.Date">
<column name="BIRTHDAY" />
</property>
<property name="gender" type="java.lang.String">
<column name="GENDER" />
</property>
</class>
</hibernate-mapping>
在cfg文件中加入映射文件
<mapping resource="com/hibernate/beans/Students.hbm.xml"/>
创建Junit测试类
public class StudentsTest {
/**
* before注解在test注解前执行,一般用来初始化
* test用来执行测试
* after释放资源
*/
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void init(){
//1.创建配置对象
Configuration config = new Configuration().configure();
//2.创建服务注册对象
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();
//3.创建会话工厂对象
sessionFactory = config.buildSessionFactory(serviceRegistry);
//4.创建会话对象
session = sessionFactory.openSession();
//5.开启事务
transaction = session.beginTransaction();
}
@After
public void destory(){
transaction.commit();//提交事务
session.close();
sessionFactory.close();//关闭会话工厂
}
@Test
public void testSaveStudents(){
//生成学生对象
Students s1 = new Students(2, "张四丰", new Date(), "男");
//保存对象到数据库
session.save(s1);
}
}
一个简单的Hibernate使用的例子就完成了。
Hibernate.cfg.xml常用配置
属性名字 | 含义 |
Hibernate.show_sql | 是否把Hibernate运行时的SQL语句输出到控制台,编码阶段便于测试。 |
Hibernate.format_sql | 输出到控制台的SQL语句是否进行排版,便于阅读。 |
Hbm2ddl.auto | 可以帮助由java代码生成生成数据库脚本,进而生成具体的表结构。Create | update | create-drop |validate Create表示每次重新生成表结构 Update可以保持原有的数据 |
Hibernate.default_schema | 默认的数据库,会给语句前加前缀。 |
Hibernate.dialect | 配置Hibernate数据库方言,Hibernate可针对特殊的数据库优化。 |
Hibernate的执行流程
Session简介
Hibernate是对jdbc的封装,不建议直接使用jdbc的connection操作数据库,而是通过使用session操作数据库。Session可以理解为操作数据库的对象。
Session与connection,是多对一关系,每个session都有一个与之对应的connection,一个connection不同时刻可以供多个session使用。
把对象保存在关系数据库中需要调用session的各种方法,如save(),update(),delete(),createQuery()等。
Transaction简介
Hibernate对数据的操作都是封装在事务当中,并且默认是非自动提交的方式。所以用session保存对象时,如果不开启事务,并且手工提交事务,对象并不会真正保存在数据库中。
如果你想让hibernate像jdbc那样 自动提交事务,必须调用session对象的 dowork()方法,获得jdbc的connection后,设置其为自动提交事务模式。(通常不推荐这么做)
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
connection.setAutoCommit(true);
}
});
//设置自动提交之后还要执行这句,发出sql语句,不然没有效果
//session.flush();
Session详解
如何获得session对象?
1. openSession
2. getCurrentSession
如果使用getCurrentSession需要在hibernate.cfg.xml文件中进行配置
如果是本地事务(jdbc事务)
<property name=”hibernate.current_session_context_class”>thread</property>
如果是全局事务(jta事务)
<propertyname=”hibernate.current_session_context_class”>jta</property>
openSession与getCurrentSession的区别
1. getCurrentSession在事务提交或者回滚之后会自动关闭,而openSession需要你手动关闭。如果使用openSession而没有手动关闭,多次之后会导致连接池溢出。
2. openSession每次创建新的session对象,getCurrentSession使用现有的session对象。public class SessionTest {
@Test
public void testOpenSession(){
Configuration config = new Configuration().configure();//获得配置对象
//获取注册对象
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();
//获得sessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory(serviceRegistry);
//获得session对象
Session session = sessionFactory.openSession();
Session session1 = sessionFactory.openSession();
System.out.println(session == session1);//false
/*if(session != null){
System.out.println("session创建成功");
}else{
System.out.println("session创建失败");
}*/
}
@Test
public void testGetCurrentSession(){
Configuration config = new Configuration().configure();//获得配置对象
//获取注册对象
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();
//获得sessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory(serviceRegistry);
//获得session对象
Session session = sessionFactory.getCurrentSession();
Session session1 = sessionFactory.getCurrentSession();
System.out.println(session == session1);//true
/*if(session != null){
System.out.println("session创建成功");
}else{
System.out.println("session创建失败");
}*/
}
@Test
public void testSaveStudentsWithOpenSession(){
Configuration config = new Configuration().configure();//获得配置对象
//获取注册对象
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();
//获得sessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory(serviceRegistry);
//获得session对象
Session session = sessionFactory.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
Students s = new Students(1,"张三",new Date(),"男");
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
System.out.println("connection hashcode"+connection.hashCode());
}
});
session.save(s);
// session.close();
transaction.commit();//提交事务
Session session2 = sessionFactory.openSession();
//开启事务
transaction = session2.beginTransaction();
s = new Students(6,"张三",new Date(),"男");
session2.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
//打印出的Connection不是同一个对象
System.out.println("connection hashcode"+connection.hashCode());
}
});
session2.save(s);
// session.close();
transaction.commit();//提交事务
}
@Test
public void testSaveStudentsWithgetCurrentSession(){
Configuration config = new Configuration().configure();//获得配置对象
//获取注册对象
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(config.getProperties()).buildServiceRegistry();
//获得sessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory(serviceRegistry);
//获得session对象
Session session = sessionFactory.getCurrentSession();
//开启事务
Transaction transaction = session.beginTransaction();
Students s = new Students(10,"张三",new Date(),"男");
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
System.out.println("connection hashcode"+connection.hashCode());
}
});
session.save(s);
// session.close();
transaction.commit();//提交事务
Session session2 = sessionFactory.getCurrentSession();
//开启事务
transaction = session2.beginTransaction();
s = new Students(16,"张三",new Date(),"男");
session2.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
//打印出的Connection不是同一个对象
System.out.println("connection hashcode"+connection.hashCode());
}
});
session2.save(s);
// session.close();
transaction.commit();//提交事务
}
}
Hbm配置文件常用配置
<hibernate-mapping
Schema=”schemaName”
Catalog=”catalogName”
Default-cascade=”cascade_style” //级联风格
Default-access=”field|property|ClassName” //访问策略
Default-lazy=”true|false” //加载策略
Package=”packagename”
/>
<class
Name=”ClassName” //映射的是那个类
Table=”tableName” //映射成的表名
Batch-size=”N”//抓取策略,一次可以抓取多少条记录
Where=”condition”//抓取的条件
Entity-name=”EntityName”//支持同一个类映射成多个表
/>
<id //表示主键
Name =”propertyName”
Type=”typename”
Column=”column_name”
Length=”length”
<generator class=”generatorClass”/> //主键生成策略
</id>
主键生成策略
标识符生成器(主键生成策略) | 描述 |
Increment | 适用于代理主键。由Hibernate自动以递增方式生成。 |
Identity | 适用于代理主键。由底层数据库生成标识符。 |
Sequence | 适用于代理主键。Hibernate根据底层数据库的序列生成标识符,这要求底层数据库支持序列。 |
Hilo | 适用于代理主键,Hibernate分局high/low算法生成标识符。 |
Seqhilo | 适用于代理主键。Hibernate分局high/low算法生成标识符。 |
Native | 适用于代理主键。根据底层数据库对自动生成标识符的方式,自动选择identity、sequence或hilo。 |
Uuid.hex | 适用于代理主键。Hibernate 采用128位的UUID算法生成标识符。 |
Uuid.string | 适用于代理主键。UUID被编码成一个16字符长的字符串。 |
Assigned | 适用于自然主键。由Java应用程序负责生成标识符。 |
Foreign | 适用于代理主键。使用另外一个相关联的对象标识符。 |
单一主键
Assigned由Java应用程序负责生成(手工赋值)
Native 由底层数据库自动生成标识符,如果是MySQL就是increment,如果是Oracle就是sequence。
Hibernate基本类型
Hibernate映射类型 | Java类型 | 标准SQL类型 | 大小 |
Integer/int | Java.lang.Integer/int | INTEGER | 4字节 |
Long | Java.lang.Long/long | BIGINT | 8字节 |
Short | Java.lang.Short/short | SMALLINT | 2字节 |
Byte | Java.lang.Byte/byte | TINYINT | 1字节 |
Float | Java.lang.Float/float | FLOAT | 4字节 |
Double | Java.lang.Double/double | DOUBLE | 8字节 |
Big_decimal | Java.math.BigDecimal | NUMERIC |
|
Character | Java.lang.Character/java.lang.String/char | CHAR(1) | 定长字符 |
String | Java.lang.String | VARCHAR | 变长字符 |
Boolean/yes_no/true_false | Java.lang.Boolean/Boolean | BIT | 布尔类型 |
Date | Java.util.Date/java.sql.Date | DATE | 日期 |
Timestamp | Java.util.Date/java.util.Timestamp | TIMESTAMP | 日期 |
Calendar | Java.util.Calendar | TIMESTAMP | 日期 |
Calendar_date | Java.util.Calendar | DATE | 日期 |
Hibernate对象类型
映射类型 | Java类型 | 标准SQL类型 | MYSQL类型 | Oracle类型 |
Binary | Byte[] | VARCHER(或BLOB) | BOLB | BLOB |
Text 大文本 | Java.lang.String | CLOB | TEXT | CLOB |
Clob 大文本 | Java.sql.Clob | CLOB | TEXT | CLOB |
Blob 二进制 | Java.sql.Blob | BLOB | BLOB | BLOB |
Mysql 不支持标准SQL的CLOB类型,在Mysql中,用TEXT,MEDIUMTEXT 及LONGTEXT类型来表示长度超过255的长文本数据。
//学生类
public class Students {
private int sid;//学号
private String sname;//姓名
private Date birthday;//出生日期
private String gender;//性别
private Blob picture;//照片
private Address address;//地址
}
测试在数据库中写入照片和读取照片
//保存一个二进制的字段
@Test
public void testWriteBlob() throws IOException{
Students s= new Students(1,"张丽英",new Date(),"女");
//获取照片文件
File f =new File("e:"+File.separator+"girl.jpg");
//获取照片的输入流
InputStream input = new FileInputStream(f);
//创建一个Blob对象
Blob image = Hibernate.getLobCreator(session).createBlob(input,input.available());
s.setPicture(image);
//保存学生
session.save(s);
}
@Test
public void testReadBlob() throws SQLException, IOException{
Students s = (Students) session.get(Students.class, 1);
Blob image = s.getPicture();
InputStream inputStream = image.getBinaryStream();
//创建输出流
File f = new File("e:"+File.separator+"dest.jpg");
//获得输出流
OutputStream output = new FileOutputStream(f);
//创建缓冲区
byte[] buff = new byte[inputStream.available()];
inputStream.read(buff);
output.write(buff);
inputStream.close();
output.close();
}
组件属性
实体类中的某个属性属于用户自定义的类的对象。
public class Students {
private int sid;//学号
private String sname;//姓名
private Date birthday;//出生日期
private String gender;//性别
private Blob picture;//照片
private Address address;//地址 该属性为自定义类对象
public Students(){}
}
//自定义类对象
public class Address {
private String postcode;
private String phone;
private String address;
public Address(){}
}
<hibernate-mapping>
<class name="com.hibernate.beans.Students" table="STUDENTS">
<id name="sid" type="int">
<column name="SID" />
<generator class="assigned" />
</id>
<property name="sname" type="java.lang.String">
<column name="SNAME" />
</property>
<property name="birthday" type="java.util.Date">
<column name="BIRTHDAY" />
</property>
<property name="gender" type="java.lang.String">
<column name="GENDER" />
</property>
<property name="picture" type="java.sql.Blob">
<column name="PICTURE" />
</property>
<component name="address" class="com.hibernate.beans.Address">
<property name="postcode" column="POSTCODE"></property>
<property name="phone" column="PHONE"></property>
<property name="address" column="ADDRESS"></property>
</component>
</class>
</hibernate-mapping>
单表CRUD操作实例
Save/update/delete/get和load(查询单个记录)
Get与load的区别
1.在不考虑缓存的情况下,get方法会在调用之后立即向数据库发出sql语句,返回持久化对象。
Load方法会在调用后返回一个代理对象。
该代理对象只保存了实体对象的id,直到使用对象的非主键属性时才会发出sql语句。
2查询数据库中不存在数据时,get方法返回null,load方法抛出异常org.hibernate.ObjectNotFoundException
Hibernate 映射类型
一对多(one-to-many)
多对一(many-to-one)
一对一(one-to-one)
多对多(many-to-many)
一对多的映射
一方对多方,如班级和学生的映射关系。
在数据库中,可以通过添加主外键的关联,表现一对多的关系。
在Hibernate中,通过在一方持有多方的集合实现,即在“一”的一端中使用<set>元素表示持有”多”的一端的对象。
Set元素的常用属性
属性 | 含义和作用 | 必须 | 默认值 |
name | 映射类属性的名称 | Y |
|
Table | 关联类的目标数据库表 | N |
|
Lazy | 指定关联对象是否使用延迟加载 | N | Proxy |
Inverse | 标识双向关联中被动的一方 | N | False |
例:班级表和学生表
建表语句,建立外键关系create table grade(
gid int primary key,
gname varchar(20) not null,
gdesc varchar(50)
);
create table student(
sid int primary key,
sname varchar(20) not null,
sex char(2),
gid int
);
alter table student add constraint fk_student_gid foreign key (gid) REFERENCES grade(gid);
//班级实体类
public class Grade implements Serializable{
private int gid;
private String gname;
private String gdesc;
//在班级一方定义多方的集合
private Set<Student> students = new HashSet<Student>();
}
班级实体类映射hbm文件
<hibernate-mapping>
<class name="com.hibernate.entity.Grade" table="grade">
<id name="gid" column="gid" type="java.lang.Integer">
<generator class="increment"></generator>
</id>
<property name="gname" type="java.lang.String">
<column name="gname" length="20" not-null="true"></column>
</property>
<property name="gdesc">
<column name="gdesc"></column>
</property>
<!-- 配置一对多关联关系 -->
<set name="students" table="student">
<key column="gid"></key>
<one-to-many class="com.hibernate.entity.Student"/>
</set>
</class>
</hibernate-mapping>
学生实体类
public class Student {
private int sid;
private String sname;
private String sex;
}
学生实体类hbm文件
<hibernate-mapping>
<class name="com.hibernate.entity.Student" table="student">
<id name="sid" column="sid" type="java.lang.Integer">
<generator class="increment"></generator>
</id>
<property name="sname" type="java.lang.String">
<column name="sname" length="20" not-null="true"></column>
</property>
<property name="sex">
<column name="sex"></column>
</property>
</class>
</hibernate-mapping>
测试类
/**
* 单向一对多关系(班级 ->学生) 1 -- N
* 建立关联关系以后,可以方便的从一个对象导航到另一个对象
*/
public class Test {
public static void main(String[] args){
add();
//findStudentsByGrade();
//update();
// delete();
}
//将学生添加到班级
public static void add(){
Grade g = new Grade("Java一班","Java软件开发");
Student stu1 = new Student("张三", "男");
Student stu2 = new Student("李四","女");
//如果希望在学生表中添加对应的班级编号,需要在班级中添加学生,建立关联关系
g.getStudents().add(stu1);
g.getStudents().add(stu2);
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
session.save(g);
session.save(stu1);
session.save(stu2);
transaction.commit();
HibernateUtil.closeSession(session);
}
//查询班级中包含的学生信息
public static void findStudentsByGrade(){
Session session = HibernateUtil.getSession();
Grade grade = (Grade)session.get(Grade.class, 1);
System.out.println(grade.getGname()+","+grade.getGdesc());
Set<Student> students = grade.getStudents();
for(Student stu:students){
System.out.println(stu.getSname()+","+stu.getSex());
}
HibernateUtil.closeSession(session);
}
//修改学生的信息,加入新的班级
public static void update(){
Grade g = new Grade("Java二班","Java软件开发二班");
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
Student stu = (Student) session.get(Student.class, 1);
g.getStudents().add(stu);
session.save(g);
transaction.commit();
HibernateUtil.closeSession(session);
}
//删除学生信息
public static void delete(){
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
Student stu = (Student) session.get(Student.class, 1);
session.delete(stu);
transaction.commit();
HibernateUtil.closeSession(session);
}
}
单向多对一关联
多对一的关系和关系数据库中的外键参照关系最匹配,即在己方的表中的一个外键参照另一个表的主键。
通过在多方持有一方的引用实现,需要在“多”的一端使用<many-to-one>配置。
Student类中持有一个Gradle的引用public class Student {
private int sid;
private String sname;
private String sex;
//在多方持有一个一方的引用
private Grade grade;
}
Hbm映射配置文件
<hibernate-mapping>
<class name="com.hibernate.entity.Student" table="student">
<id name="sid" column="sid" type="java.lang.Integer">
<generator class="increment"></generator>
</id>
<property name="sname" type="java.lang.String">
<column name="sname" length="20" not-null="true"></column>
</property>
<property name="sex">
<column name="sex"></column>
</property>
<!-- 配置多对一的关联关系 -->
<!-- name 表示对一方的引用
class 指定一方对应的实体类
column 用来指定 外键的列名
-->
<many-to-one name="grade" class="com.hibernate.entity.Grade" column="gid"></many-to-one>
</class>
</hibernate-mapping>
测试类
/**
* 单向的多对一 (N ---1) 学生 -- 班级
*/
public class Test {
public static void main(String[] args){
// add();
findGradeByStudent();
}
//将学生添加到班级
public static void add(){
Grade g = new Grade("Java一班","Java软件开发");
Student stu1 = new Student("张三", "男");
Student stu2 = new Student("李四","女");
//设置关联关系
//下面这样就同时设置了多对一和一对多的关系
g.getStudents().add(stu1);
g.getStudents().add(stu2);
stu1.setGrade(g);
stu2.setGrade(g);
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
session.save(g);//级联操作,保存班级时,发现有学生的信息,则把学生信息也加入到数据库中
// session.save(stu1);
// session.save(stu2);
transaction.commit();
HibernateUtil.closeSession(session);
}
//查询学生所在班级信息
public static void findGradeByStudent(){
Session session = HibernateUtil.getSession();
Student stu = (Student) session.get(Student.class, 2);
System.out.println(stu.getSname()+","+stu.getSex());
Grade g = stu.getGrade();
System.out.println(g.getGname()+","+g.getGdesc());
HibernateUtil.closeSession(session);
}
}
Inverse属性
<set>节点的inverse属性指定关联关系的控制方向,默认由一方来维护,设置为true则由多方来维护关联关系。一对多关联一般都将控制方交给多端。
例子:
一个Parent有多个Child,一个Child只能有一个Parent。public class Child {
private Long id;
private String name;
private Parent parent;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
<?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="com.xian.Child" table="child">
<id name="id" column="childId">
<generator class="native" />
</id>
<property name="name" type="string"></property>
<many-to-one name="parent" column="parentId" not-null="true">
</many-to-one>
</class>
</hibernate-mapping>
父亲类
public class Parent {
private Long id;
private String name;
private Set children = new HashSet();
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getChildren() {
return children;
}
public void setChildren(Set children) {
this.children = children;
}
}
映射文件
<?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="com.xian.Parent" table="parent">
<id name="id" column="parentId">
<generator class="native"></generator>
</id>
<property name="name" type="string"></property>
<set name="children" inverse="true">
<!-- 此处inverse设置为true,则关联的控制方交给了child,一对多关联一般都将控制方交给多端 -->
<key column="parentId" not-null="true"></key>
<one-to-many class="com.xian.Child"/>
</set>
</class>
</hibernate-mapping>
测试结果:
Parent p = new Parent();
p.setName("parent");
Child c = (Child) session.load(Child.class, 4l); //原child表中已存在id=4的child
p.getChildren().add(c); // 我希望用parent端来修改关联,即将id=4的child的外键变为现在这个parent的主键值
session.save(p); //这里保存parent,同时希望关联也得到修改
/*但是我们发现parent确实保存了,而child的外键还是原值,没有关联到我们现在的外键
原因就是我们将关联的控制方交给了child端,这样一来parent就不能够控制关联了。*/
Parent p = new Parent();
p.setName("parent");
Child c = (Child) session.load(Child.class, 4l);
c.setParent(p); //这样由child端修改关联就ok了
session.save(p);
Cascade属性
当设置了cascade属性不为none时,Hibernate会自动持久化所关联的对象。
Cascade属性的设置会带来性能上的变动,需谨慎设置。
属性值 | 含义和作用 |
All | 对所有操作进行级联操作 |
Save-update | 执行保存和更新时进行级联操作 |
Delete | 执行删除操作时进行级联操作 |
None | 对所有操作不进行级联操作 |
使用MyEclipse反向工程自动生成实体类和映射文件
1. 首先打开数据库视图,新建一个数据库的连接。
2. 选择需要进行反向工程的表。右键—选择hibernate反向工程。按步骤操作就会生成实体类和对应的映射文件。