这一章讲的是简单的多对一关系映射。
1.首先是开发环境,使用Maven版本为3.5,jdk版本为9.0.1,Hibernate版本为5.0.1Final,数据库为MySQL5.7.20
2.配置Maven的pom.xml文件,由于我当前的jdk版本以及Hibernate版本所以依赖如配置文件中所列出。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cc.acme_me.hibernate</groupId> <artifactId>Hibernate03</artifactId> <version>1.0-SNAPSHOT</version> <name>Hibernate01</name> <dependencies> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.12.Final</version> </dependency> <dependency> <groupId>antlr</groupId> <artifactId>antlr</artifactId> <version>2.7.7</version> </dependency> <dependency> <groupId>com.fasterxml</groupId> <artifactId>classmate</artifactId> <version>1.3.4</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.hibernate.common</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>5.0.1.Final</version> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.0.Final</version> </dependency> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.1-api</artifactId> <version>1.0.0.Final</version> </dependency> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.20.0-GA</version> </dependency> <dependency> <groupId>org.jboss</groupId> <artifactId>jandex</artifactId> <version>2.0.3.Final</version> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.0.Final</version> </dependency> <dependency> <groupId>org.jboss.spec.javax.transaction</groupId> <artifactId>jboss-transaction-api_1.2_spec</artifactId> <version>1.0.1.Final</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version> </dependency> </dependencies> </project>
3.Hibernate的全局配置文件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">root</property> <property name="connection.url">jdbc:mysql://localhost:3306/db_hibernate</property> <property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property> <!--数据库方言--> <property name="dialect">org.hibernate.dialect.MySQL57Dialect</property> <!--显示sql语句--> <property name="show_sql">true</property> <!--格式化sql语句--> <property name="format_sql">true</property> <!--设置ddl 根据设置自动更新表结构 包括添加删除表 更新表结构--> <property name="hbm2ddl.auto">create-drop</property> <!--告诉Hibernate映射的实体类--> <mapping class="cc.acme_me.model.Student"/> <mapping class="cc.acme_me.model.Group"/> </session-factory> </hibernate-configuration>
4.新建两个实体类Student和Group并且表示一对多的关系
package cc.acme_me.model; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; @Entity @Table(name = "t_group") public class Group { @Column(name = "groupID") @Id @GenericGenerator(name = "native", strategy = "native")//定义策略然后下面使用 @GeneratedValue(generator = "native") private int groupID;//组ID @Column(name = "groupName") private String groupName;//组名 public String getGroupName() { return groupName; } public void setGroupName(String groupName) { this.groupName = groupName; } public int getGroupID() { return groupID; } public void setGroupID(int groupID) { this.groupID = groupID; } @Override public String toString() { return "Group{" + "groupID=" + groupID + ", groupName='" + groupName + '\'' + '}'; } }
通常,我们在一对多的关系中,在多的一方增加少的一方的关联关系。
这也是这一章所讲到的注解@ManyToOne和@JoinColumn,当然,这两个注解还有属性,我在后续的章节中慢慢增加。JoinColumn的name属性便是外键的列名
package cc.acme_me.model; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; @Entity @Table(name = "t_student") public class Student { @Id @GenericGenerator(name = "native", strategy = "native") @GeneratedValue(generator = "native") private long id;//作为主键 @Column(name = "studentname") private String name;//姓名 @Column(name = "studentage") private int age;//年龄 @ManyToOne @JoinColumn(name = "groupID") private Group group;//所属组 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 int getAge() { return age; } public void setAge(int age) { this.age = age; } public Group getGroup() { return group; } public void setGroup(Group group) { this.group = group; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", group=" + group + '}'; } }
5.接下来便是使用Junit测试进行测试
首先贴上工具类(其实是偷懒)
package cc.acme_me.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.service.ServiceRegistry; public class SessionUtils { public static Session openSession() { ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build(); SessionFactory sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory(); return sessionFactory.openSession(); } }
测试类
package cc.acme_me.test; import cc.acme_me.model.Group; import cc.acme_me.model.Student; import cc.acme_me.utils.SessionUtils; import org.hibernate.Session; import org.junit.After; import org.junit.Before; import org.junit.Test; public class TestStudent { private Session session = null; @Before public void openSession() { session = SessionUtils.openSession(); session.beginTransaction(); } @After public void closeSession() { session.getTransaction().commit(); session.close(); } @Test public void testAdd() { //创建组并保存 Group group = new Group(); group.setGroupName("Group 1"); session.save(group);//因为没有配置cascade,所以需要手动保存一下组 //组里面添加一个学生 Student student = new Student(); student.setAge(18); student.setName("Admin"); student.setGroup(group); session.save(student); //组里面再添加一个学生 student = new Student(); student.setName("Admin2"); student.setAge(20); session.save(student); student.setGroup(group); session.save(student); } }
首先是添加方法,同时也看看Hibernate打印出来的sql语句。
Hibernate: insert into t_group (groupName) values (?) Hibernate: insert into t_student (studentage, groupID, studentname) values (?, ?, ?) Hibernate: insert into t_student (studentage, groupID, studentname) values (?, ?, ?) Hibernate: update t_student set studentage=?, groupID=?, studentname=? where id=?
插入成功后我们也可以在表中查看到刚刚插入的数据,同时也可以查看一下表的结构。
当然,也可以使用show create table 'tb_name'来查看表创建的语句。
上面展示了表内的数据,接着就试试查询。
@Test public void testFind() { Student student = session.get(Student.class, 1L); System.out.println(student); }
可以看到控制台的sql语句滚动以及打印出来的student信息。
而且同样也可以查询Group的内容。
@Test public void testFindGroup() { Group group = session.get(Group.class, 1); System.out.println(group); }
接下来的update和delete便不再一一列出,因为这并没有什么意思。
我这个时候对Group操作,我要删除它。但是Group的主键是Student的外键,删除时Group的时候Hibernate会如何出来Student表内的数据?是将外键值置为为空(0)?还是同事删除Group内的Student的数据?
@Test public void testDeleteGroup() { Group group = session.get(Group.class, 1); session.delete(group); }
执行这个操作,结局红红的异常,并且,异常会明确的告诉你:java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`db_hibernate`.`t_student`, CONSTRAINT `FKeyqu03o2m70hvm5iymc7cj5kd` FOREIGN KEY (`groupID`) REFERENCES `t_group` (`groupID`))
这个时候肯定有人想说,我就是想要干掉Student内的数据,级联操作,全部给我干。
这个就放到后面去配置cascade来实现。