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,配置内容
Ⅲ.在src下建立类Class、student,MainClass:
Class.java
Student.java
MainClass.java
Ⅳ.在实体类同路径下建立映射文件
Class-hbm.xml
Student-hbm.xml
Ⅴ.在mysql数据库里建立数据库模型
Ⅵ.执行MainClass
测试添加:
数据呗成功添加进数据库
删除、更新、查询,自己去试吧~~~
3.双向一对多:既在Class里添加Set students,又保留在Student中的Class对象
Ⅰ.复制工程,即基于2里的程序继续测试双向一对多
修改Class.java,添加一个Set并加上get set方法
Ⅱ.修改Class-hbm.xml,添加新的元素Set标签
Ⅲ.清空数据库class和student表,并修改MainClass中的testQuery()。
清空数据库
修改testQuery()
对MainClass逐步执行:添加-查询,
则得到控制台输出结果,由此可知,在查阅到class对象以后,只在要访问class里的学生set的时候,hibernate才会执行查询语句,如果只对class对象进行操作,学生set不会实际加载,这便是hibernate的延迟加载。
4.多对多的处理和一对多差不多,只是中间添加了一个连表
比如Teacher和Class多对多,可以建立一个连表(tid,cid),两列分别外键引用到teacher和class表,如果是单向多对多,从class→teacher,则只需要在class里添加Set teachers,并Teacher-hbm.xml里添加:
如果是双向多对多,则还有要在Teacher里添加Set classes,并向xml里添加
值得注意的,双向多对多必须在其中一个set标签里设置inverse属性,
不然就会抛出主键异常,因为在存一个class行的时候,实际上是更新了一条class表的insert和teacher_class关联表的insert,而在存teacher的时候,也会更新一条关联表的insert,比如一班的李老师在更新的时候,更新班级一和更新老师,会向中间表更新同一条数据,造成主键冲突,设置inverse=”true”即会让一端放弃维护,避免二次主键问题。
Ⅰ.比如班级和学生 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”即会让一端放弃维护,避免二次主键问题。
相关文章推荐
- Qt中如何使用样式表QPalette以及相关注意事项(转)
- Qt中如何使用样式表QPalette以及相关注意事项
- Qt中如何使用样式表QPalette以及相关注意事项
- Qt中如何禁掉所有UI操作以及注意事项(处理各个widget的eventFilter这一层,但是感觉不好,为什么不使用QApplication呢)
- 使用aidl的项目结构以及小的注意事项
- 如何使用spring @component 以及注意事项
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
- Qt中如何使用样式表QPalette以及相关注意事项
- Qt中如何使用样式表QPalette以及相关注意事项
- Qt中如何使用样式表QPalette以及相关注意事项
- 如何在MAC环境下(Xcode)使用svn,以及新手在团队使用svn注意事项
- 如何不用oracle client直接使用plsql远程连接oracle数据库以及需要注意的事项
- Qt中如何使用样式表QPalette以及相关注意事项
- Android中AsyncTask的使用场景、使用时的注意事项以及如何关闭
- Qt中如何使用样式表QPalette以及相关注意事项
- (转)Qt中如何使用样式表QPalette以及相关注意事项
- React 中import时如何正确使用花括号'{ }',以及default,export的用法注意事项
- pg_reload 如何使用以及注意事项。
- hibernate中session的获取使用以及其他注意事项
- 老南瓜:如何建立基于SSAS的Reporting Services报表,以及参数(parameters)使用