以班级和学生为例,字段自己定,要求用基于注解的Hibernate实现一对多映射。要求 :
1、实现班级和学生记录的添加;
-
1.1新建一个Hibernate项目,导入hibernate所需的jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xUXPQhff-1601389242532)(https://i.loli.net/2020/03/18/dEKn4ivFsxXurA5.png)]
-
1.2 创建Classes和Student实体类
@Entity : 设置为Entity 实体;
@Table(name = “tb_class”) : 设置数据库表名;
— name: 用来命名 当前实体类 对应的数据库 表的名字 ;
@Id : 设置主键;
@GeneratedValue(strategy=GenerationType.IDENTITY) : 用于标注主键的生成策略,通过strategy 属性指定;
— IDENTITY:采用数据库ID自增长的方式来自增主键字段,Oracle 不支持这种方式;
— AUTO: JPA自动选择合适的策略,是默认选项;
— SEQUENCE:通过序列产生主键,通过@SequenceGenerator 注解指定序列名,MySql不支持这种方式 ;
— TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。@OneToMany(fetch = FetchType.EAGER) : 一对多)单向:会产生中间表,此时可以用@onetoMany @Joincolumn(name=" ")避免产生中间表,并且指定了外键的名字(别看@joincolumn在一中写着,但它存在在多的那个表中),在数据库中并没有实际字段;
— fetch : 表示抓取策略,默认为FetchType.LAZY,因为关联的多个对象通常不必从数据库预先读取到内存 。
@ManyToOne : (多对一)单向:不产生中间表,但可以用@Joincolumn(name=" ")来指定生成外键的名字,外键在多的一方表中产生,在数据库中并没有实际字段。
hibernate中@ManyToOne默认是立即加载,@OneToMany默认是懒加载。
@Cascade(CascadeType.SAVE_UPDATE) : 表示级联操作策略,对于OneToMany类型的关联非常重要,通常该实体更新或删除时,其关联的实体也应当被更新删除。
package com.hibernate.entity; import java.util.Set; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; @Entity // 设置为Entity 实体 @Table(name = "tb_class") // 设置数据库表名 public class Classes { @Id // 设置主键 @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; private String ClassName; private String professional; @OneToMany(fetch = FetchType.EAGER) @Cascade(CascadeType.SAVE_UPDATE) // 设置级联操作 private Set<Student> students; public Classes() { super(); // TODO Auto-generated constructor stub } public Classes(String className, String professional) { super(); ClassName = className; this.professional = professional; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getClassName() { return ClassName; } public void setClassName(String className) { ClassName = className; } public String getProfessional() { return professional; } public void setProfessional(String professional) { this.professional = professional; } public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } }
package com.hibernate.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "tb_student") public class Student { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; private String stuNumber; private String stuName; private Integer stuGender; private Integer grade; @ManyToOne private Classes classes; public Student() { super(); // TODO Auto-generated constructor stub } public Student(String stuNumber, String stuName, Integer stuGender, Integer grade, Classes classes) { super(); this.stuNumber = stuNumber; this.stuName = stuName; this.stuGender = stuGender; this.grade = grade; this.classes = classes; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getStuNumber() { return stuNumber; } public void setStuNumber(String stuNumber) { this.stuNumber = stuNumber; } public String getStuName() { return stuName; } public void setStuName(String stuName) { this.stuName = stuName; } public Integer getStuGender() { return stuGender; } public void setStuGender(Integer stuGender) { this.stuGender = stuGender; } public Integer getGrade() { return grade; } public void setGrade(Integer grade) { this.grade = grade; } public Classes getClasses() { return classes; } public void setClasses(Classes classes) { this.classes = classes; } }
-
1.3 创建 hibernate.cfg.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 配置连接数据库的基本信息 --> <property name="connection.username">root</property> <property name="connection.password"></property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/hibernate-task</property> <!-- 配置hibernate 的基本信息 --> <!-- hibernate 所使用的数据库方言 --> <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> <!-- 执行操作时是否在控制台打印SQL --> <property name="show_sql">true</property> <!-- 是否对 SQL 进行格式化 --> <property name="format_sql">true</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="hibernate.c3p0.acquire_increment">2</property> <property name="hibernate.c3p0.idle_test_period">2000</property> <property name="hibernate.c3p0.timeout">2000</property> <property name="hibernate.c3p0.max_statements">10</property> <property name="hibernate.c3p0.validate">true</property> <!-- 指定关联的 .hbm.xml 配置文件 --> <!--<mapping class="com/hibernate/entity/Classes.hbm.xml"/>--> <!--<mapping class="com/hibernate/entity/Student.hbm.xml"/>--> <!-- 这里需要修改为如下形式 --> <mapping class="com.hibernate.entity.Classes"/> <mapping class="com.hibernate.entity.Student"/> </session-factory> </hibernate-configuration>
-
1.4 创建一个Test类
package com.hibernate.test; import java.util.HashSet; import java.util.Set; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.service.ServiceRegistry; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.hibernate.entity.Classes; import com.hibernate.entity.Student; public class HibernateTest { private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void init() { System.out.println("init"); // 生成一个注册机对象 ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build(); // 使用注册机机对象serviceRegistry创建sessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory(); // 创建一个 session 会话对象 session = sessionFactory.openSession(); // 开启事务 transaction = session.beginTransaction(); } @After public void destroy() { System.out.println("destroy"); transaction.commit(); session.close(); sessionFactory.close(); } /** * 添加班级和学生记录 */ @Test public void addClassesAndStudent() { Classes classes1 = new Classes("计科8班", "计算机科学与技术"); Classes classes2 = new Classes("计科9班", "计算机科学与技术"); Student student1 = new Student("202008001", "小明", 1, 17, classes1); Student student2 = new Student("202008002", "小芳", 0, 18, classes1); Student student3 = new Student("202009001", "小黄", 1, 16, classes2); Student student4 = new Student("202009002", "小红", 0, 19, classes2); Set<Student> students1 = new HashSet<Student>(); students1.add(student1); students1.add(student2); Set<Student> students2 = new HashSet<Student>(); students2.add(student3); students2.add(student4); // 设定关联关系 classes1.setStudents(students1); classes2.setStudents(students2); session.save(classes1); session.save(classes2); } }
-
1.4 此时我们可以通过控制台看到已经为我们生成数据表和添加了数据记录
注意:运行成功后我们查看数据库中是3张表!
2、通过班级遍历输出其所有学生记录;
-
2.1 在Test类中添加一个查询方法
/** * 通过班级查询学生信息 */ @Test public void getClassesOutputAllStudent() { // 查询8班的学生记录 // Classes classes = session.get(Classes.class, 1); // 查询9班的学生记录 Classes classes = session.get(Classes.class, 2); System.out.println(classes.getClassName()); for (Student student : classes.getStudents()) { System.out.print("学号:" + student.getStuNumber() + " "); System.out.print("姓名:" + student.getStuName() + " 性别:"); System.out.print(student.getStuGender() == 1?"男":"女" + " "); System.out.println(" 年级:" + student.getGrade() + "级"); } }
-
2.2 运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DiZT2zg5-1601389242543)(https://i.loli.net/2020/03/18/Z86Fw7Dd9PEkNAr.png)]
3、修改班级记录
-
3.1 这里我们只做一个示例
/** * 修改班级专业 */ @Test public void Update() { Classes classes = session.get(Classes.class, 1); classes.setProfessional("信息工程学部"); }
-
3.2 运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YLRgwg0R-1601389242545)(https://i.loli.net/2020/03/18/gzR3WxfGsFAS5IJ.png)]
4、级联删除操作
Student 是多的那一方,如果要删除一条Student记录,直接调用session.delete() 方法则会报错:
javax.persistence.EntityNotFoundException: deleted object would be re-saved by cascade (remove deleted object from associations)
解决方法:
先得到与该 Student对象对应的一的那一端(Classes对象),然后将Student对象从 Classes对象中删除,这样删除就不会出现错误了。
-
4.1 删除一条学生记录
/** * 删除学生记录 */ @Test public void delete() { Student student = session.get(Student.class, 1); student.getClasses().getStudents().remove(student); //student.setClasses(null); session.delete(student); }
-
4.2 运行效果
以上多个代码可能会冲突,则可以新建多个Test类,分文件测试。
作业上交
-
连带项目(不要jar包)一起压缩,名字包含班级-学号-姓名(格式同笔记格式)
-
时间:周五晚前统一发给班长,由班长统一发给我