8.2 Hibernate:多对一单向关联(unidirectional)
来源:互联网 发布:js杀破狼无损百度云 编辑:程序博客网 时间:2024/06/05 04:44
1 建立多对一应用场景
以人与手机的关系为例,同一时间点上,一部手机只能由一个人使用,而一个人可以同时使用一部或多部手机。手机与人之间是多对一的关系。
使用 MySQL 数据库:
CREATE TABLE `test`.`person` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(16) NOT NULL, `birth` TIMESTAMP NOT NULL, PRIMARY KEY (`id`), UNIQUE INDEX `id_UNIQUE` (`id` ASC))ENGINE = InnoDBDEFAULT CHARACTER SET = utf8COMMENT = '人';
CREATE TABLE `test`.`phone` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `imei` VARCHAR(15) NOT NULL, `number` VARCHAR(11) NOT NULL, `owner_id` INT UNSIGNED NULL, PRIMARY KEY (`id`), UNIQUE INDEX `id_UNIQUE` (`id` ASC), UNIQUE INDEX `imei_UNIQUE` (`imei` ASC), UNIQUE INDEX `number_UNIQUE` (`number` ASC), INDEX `FK_PHONE_idx` (`owner_id` ASC), CONSTRAINT `FK_PHONE` FOREIGN KEY (`owner_id`) REFERENCES `test`.`person` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)ENGINE = InnoDBDEFAULT CHARACTER SET = utf8COMMENT = '手机';
2 定义映射类
2.1 表 person
的映射类定义:
package hibernate;import java.util.Date;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name = "person")public class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "name") private String name; @Column(name = "birth") private Date birth; public Person() {} public Person(String name, Date birth) { this.name = name; this.birth = birth; } // 省略 Getters 和 Setters ...}
2.2 表 phone
的映射类定义:
package hibernate;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.ForeignKey;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.Table;@Entity@Table(name = "phone")public class Phone { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "imei") private String imei; @Column(name = "number") private String number; @ManyToOne @JoinColumn(name = "owner_id", foreignKey = @ForeignKey(name = "FK_PHONE")) private Person person; public Phone() {} public Phone(String imei, String number) { this.imei = imei; this.number = number; } // 省略 Getters 和 Setters ...}
3 测试
3.1 新增
@Testpublic void test() { Configuration configuration = new Configuration().configure("hibernate.cfg.xml"); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Person person = new Person("Jack", new Date()); session.save(person); Phone phone1 = new Phone("866661234567890", "18012345678"); phone1.setPerson(person); session.save(phone1); Phone phone2 = new Phone("866660987654321", "18087654321"); phone2.setPerson(person); session.save(phone2); transaction.commit(); session.close(); sessionFactory.close();}
运行测试,对象 person
,phone1
和 phone2
都被持久化存储到对应的 person
和 phone
数据表中,且 phone1
和 phone2
对应记录的外键都是新插入的 person
对应记录的主键(日志省略)。
如果将单元测试代码中 session.save(phone1);
和 session.save(phone2);
屏蔽掉,则只会持久化存储 person
对象。
如果将单元测试代码中 session.save(person);
屏蔽掉,默认情况下单元测试报异常,不能成功持久化存储任一对象数据。
java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance beforeQuery flushing
由此可见:新增多对一关系数据时,默认首先需要保存“一”方的数据,只能成功保存了一”方的数据后才有可能保存“多”方的数据,除非修改 @ManyToOne
的 cascade
属性,才能实现级联插入和更新(后续会详细阐述 cascade
属性的用途)
3.2 删除
基于以上测试新增的数据进行删除测试。
@Testpublic void test() { Configuration configuration = new Configuration().configure("hibernate.cfg.xml"); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); List<Phone> phones = session.createQuery(" FROM Phone").list(); for (Phone phone : phones) { session.delete(phone); } Person person = (Person) session.createQuery(" FROM Person").list().get(0); session.delete(person); transaction.commit(); session.close(); sessionFactory.close();}
注意:
(1) 可以只删除 phone
,默认不会对其关联的 person
产生影响,除非修改 @ManyToOne
的 cascade
属性(后续会详细阐述 cascade
属性的用途);
(2) 删除 person
前必须首先删除外键关联的 phone
,否则出现以下异常。
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails
3.3 更新
@Testpublic void test() { Configuration configuration = new Configuration().configure("hibernate.cfg.xml"); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Phone phone = (Phone) session.createQuery(" FROM Phone").list().get(0); phone.setImei("123456789012345"); phone.setNumber("15912345678"); phone.getPerson().setName("Bruce"); phone.getPerson().setBirth(new Date()); transaction.commit(); session.close(); sessionFactory.close();}
运行测试,phone
关联的 person
级联更新。
3.4 查询
@Testpublic void test() { Configuration configuration = new Configuration().configure("hibernate.cfg.xml"); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); List<Phone> phones = session.createQuery(" FROM Phone").list(); for (int i = 1; i <= phones.size(); i++) { System.out.println("---------- Phone " + i + "----------"); System.out.println("IMEI : " + phones.get(i - 1).getImei()); System.out.println("Number : " + phones.get(i - 1).getNumber()); System.out.println("Owner Name : " + phones.get(i - 1).getPerson().getName()); System.out.println("Owner Birth : " + phones.get(i - 1).getPerson().getBirth()); } transaction.commit(); session.close(); sessionFactory.close();}
运行测试,打印结果:
---------- Phone 1----------IMEI : 866661234567890Number : 18012345678Owner Name : JackOwner Birth : 2017-07-09 21:07:49.0---------- Phone 2----------IMEI : 866660987654321Number : 18087654321Owner Name : JackOwner Birth : 2017-07-09 21:07:49.0
- 8.2 Hibernate:多对一单向关联(unidirectional)
- 8.3 Hibernate:一对多单向关联(unidirectional)
- Hibernate多对一单向关联映射
- hibernate单向多对一关联
- Hibernate多对一单向关联
- hibernate:多对一单向关联映射
- hibernate多对一单向关联
- Hibernate多对一单向关联
- hibernate多对一单向关联_Annotation
- hibernate多对一单向关联_XML
- Hibernate学习:单向多对一关联
- Hibernate多对一映射单向关联
- Hibernate Annotation 多对一单向关联
- Hibernate多对一关联映射(单向)
- hibernate多对一单向关联
- Hibernate单向多对一关联
- Hibernate单向多对一关联
- Hibernate单向多对一关联
- memcached高速缓存学习笔记003---利用JAVA程序操作memcached crud操作
- java代理
- 详细解析Java中抽象类和接口的区别
- c++版本之单例模式
- 揭示最危害程序员职业生涯的三大观念
- 8.2 Hibernate:多对一单向关联(unidirectional)
- 图像处理之滤波器介绍
- 326. Power of Three
- Vmware复制虚拟机的网卡配置
- PAT A1088 Rational Arithmetic (20)
- swift 3.0 字典简单学习
- 水题 第二站 AC Me
- 使用jbox2d物理引擎打造摩拜单车贴纸动画效果
- 容器与外部互通