您的位置:首页 > 其它

Hibernate 一对多 如何建立表结构以及如何使用的注意事项和实例

2017-12-30 19:33 666 查看
1.先明确一对多和多对多定义,以及方向的问题。

Ⅰ.比如班级和学生 Class和Student 一个班级多个学生是一对多;班级和老师 Class和Teacher 一个班级可以有多个老师,一个老师也可以教多个班级,所以这是一个多对多。

Ⅱ.方向。拿一对多为例,单向一对多和单向多对一和双向一对多是不一样的。班级和学生的两个实体,如果班级里存放学生的List,学生里没有班级的引用,则查询班级的时候,就会从班级朝学生方向索取,是单向一对多;如果班级里不作处理,学生里存放了班级的引用,则查询学生的时候会朝班级索取,是单向多对一;如果班级中存放学生List同时又学生里存放了班级id,则是双向多对一。这三种情况的表结构也是不同的。

2.单向多对一

Ⅰ.下载hibernate完整包hibernate5

Ⅰ.创建java工程,在src下建立lib,把hibernate-release-5.1.0.Final\lib\required的基本包和mysql驱动包mysqlDriver复制进lib文件夹,选中lib下所有的jar包,右键add to build path



Ⅱ.在src下建立hibernate.cfg.xml,配置内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>
<!-- 数据库连接配置 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">123</property>

<property name="current_session_context_class">thread</property>
<!-- SQL 方言 -->
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<!-- 在控制台输出sql语句 -->
<property name="show_sql">true</property>
<!-- 格式化sql语句 -->
<property name="format_sql">true</property>
<!-- 设置事务隔离级别 -->
<property name="connection.isolation">2</property>
<!-- 在启动时根据配置更新数据库 -->
<property name="hbm2ddl.auto">update</property>

<!-- c3p0数据源配置 -->
<property name="hibernate_c3p0.max_size">10</property>
<property name="hibernate_c3p0.min_size">5</property>
<property name="c3p0.acquire_increment">2</property>

<mapping resource="com/ft/Class-hbm.xml"/><!-- 注册我们的实体映射类-->
<mapping resource="com/ft/Student-hbm.xml"/><!-- 注册我们的实体映射类-->
</session-factory>
</hibernate-configuration>


Ⅲ.在src下建立类Class、student,MainClass:

Class.java

package com.ft;

public class Class {

private Integer id;

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
private String Name;
@Override
public String toString() {
return "Class [id=" + id + ", Name=" + Name + "]";
}

}


Student.java

package com.ft;

public class Student {
public com.ft.Class getsClass() {
return sClass;
}
public void setsClass(com.ft.Class sClass) {
this.sClass = sClass;
}
private Integer id;

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "Student [sClass=" + sClass + ", id=" + id + ", name=" + name
+ "]";
}
private String name;
private com.ft.Class sClass;//回避class关键字,Class使用的时候也注意回避java.lang.Class
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

public Student(){

}
public Student(Class sClass, int id, String name) {
super();
this.sClass = sClass;
this.id = id;
this.name = name;
}
}


MainClass.java

package com.ft;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import com.mchange.v2.c3p0.impl.NewProxyStatement;

import java.lang.Class;

public class MainClass {
StandardServiceRegistry serviceRegistry = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction tran = null;

public void init() {
System.out.println("before");
serviceRegistry = new StandardServiceRegistryBuilder().configure()
.build();
sessionFactory = new MetadataSources(serviceRegistry).buildMetadata()
.buildSessionFactory();
session = sessionFactory.openSession();
tran = session.beginTransaction();
}

public static void main(String[] args) {
MainClass mc = new MainClass();
mc.init();
// 添加
System.out.println("测试添加");
mc.testAdd();

// 更新
//System.out.println("测试更新");
//mc.testUpdate();

// 查询
//System.out.println("测试查询");
//mc.testQuery();
// 删除
//System.out.println("测试删除");
//mc.testDelete();

mc.tran.commit();
mc.destroy();
}

private void testUpdate() {
// TODO Auto-generated method stub
Student st2 = session.get(Student.class, 1);
System.out.println(st2);
st2.setName("Fuck");
}

private void testDelete() {
// TODO Auto-generated method stub
Student st3 = session.get(Student.class, 1);
session.delete(st3);
}

private void testQuery() {
// TODO Auto-generated method stub

Student st = session.get(Student.class, 2);
System.out.println(st);

}

public void testAdd() {

Student student1 = new Student();
Student student2 = new Student();
student1.setName("LiuMing");
student2.setName("LiuMing2");
com.ft.Class cls1 = new com.ft.Class();
com.ft.Class cls2 = new com.ft.Class();
cls1.setName("MidOne");
cls2.setName("MidTwo");
student1.setsClass(cls1);
student2.setsClass(cls2);
session.save(cls1);
session.save(cls2);
session.save(student1);
session.save(student2);

}

public void destroy() {
sessionFactory.close();
}
}


Ⅳ.在实体类同路径下建立映射文件

Class-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 package="com.ft">
<class name="Class" table="class">
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="cname"/>
</property>
</class>
</hibernate-mapping>


Student-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="com.ft.Student" table="student">
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="sname"/>
</property>
<many-to-one name="sClass" class="com.ft.Class" column="classId"></many-to-one>
</class>
</hibernate-mapping>


Ⅴ.在mysql数据库里建立数据库模型

create table student(
id INTEGER PRIMARY KEY AUTO_INCREMENT,
sname varchar(16),
classId INTEGER
);
create table class(
id INTEGER PRIMARY KEY auto_increment,
cname varchar(20)
);
ALTER TABLE student add constraint student_class foreign key(classId) references class(id);


Ⅵ.执行MainClass

测试添加:







数据呗成功添加进数据库

删除、更新、查询,自己去试吧~~~

3.双向一对多:既在Class里添加Set students,又保留在Student中的Class对象

Ⅰ.复制工程,即基于2里的程序继续测试双向一对多

修改Class.java,添加一个Set并加上get set方法

package com.ft;

import java.util.HashSet;
import java.util.Set;

public class Class {

private Set<Student> students = new HashSet<Student>();

public Set<Student> getStudents() {
return students;
}

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

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
private String Name;
@Override
public String toString() {
return "Class [id=" + id + ", Name=" + Name + "]";
}
}


Ⅱ.修改Class-hbm.xml,添加新的元素Set标签

<?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 package="com.ft">
<class name="Class" table="class">
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="cname"/>
</property>
<set name="students" table="student">
<key column="id"></key>
<one-to-many class="Student"/>
</set>
</class>
</hibernate-mapping>


Ⅲ.清空数据库class和student表,并修改MainClass中的testQuery()。

清空数据库

delete  from class where id>0;
delete  from student where id>=0;


修改testQuery()

private void testQuery() {
// TODO Auto-generated method stub

com.ft.Class cls = session.get(com.ft.Class.class, 23);//数据库表里已经有id为23的class行,具体id数值根据添加的数据修改
System.out.println(cls);
System.out.println(cls.getStudents());

}


对MainClass逐步执行:添加-查询,

则得到控制台输出结果,由此可知,在查阅到class对象以后,只在要访问class里的学生set的时候,hibernate才会执行查询语句,如果只对class对象进行操作,学生set不会实际加载,这便是hibernate的延迟加载。

测试查询
Hibernate:
select
class0_.id as id1_0_0_,
class0_.cname as cname2_0_0_
from
class class0_
where
class0_.id=?
Class [id=23, Name=MidOne]
Hibernate:
select
students0_.id as id1_1_0_,
students0_.id as id1_1_1_,
students0_.sname as sname2_1_1_,
students0_.classId as classId3_1_1_
from
student students0_
where
students0_.id=?
[Student [sClass=Class [id=23, Name=MidOne], id=23, name=LiuMing]]


4.多对多的处理和一对多差不多,只是中间添加了一个连表

比如Teacher和Class多对多,可以建立一个连表(tid,cid),两列分别外键引用到teacher和class表,如果是单向多对多,从class→teacher,则只需要在class里添加Set teachers,并Teacher-hbm.xml里添加:

<set name="teachers" table="teacher_class">
<key column="cid"></key>
<many-to-many class="com.Teacher" column="tid"/>
</set>


如果是双向多对多,则还有要在Teacher里添加Set classes,并向xml里添加

<set name="classes" table="teacher_class" inverse="true">
<key column="tid"></key>
<many-to-many class="com.Class" column="cid"/>
</set>


值得注意的,双向多对多必须在其中一个set标签里设置inverse属性,

不然就会抛出主键异常,因为在存一个class行的时候,实际上是更新了一条class表的insert和teacher_class关联表的insert,而在存teacher的时候,也会更新一条关联表的insert,比如一班的李老师在更新的时候,更新班级一和更新老师,会向中间表更新同一条数据,造成主键冲突,设置inverse=”true”即会让一端放弃维护,避免二次主键问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hibernate
相关文章推荐