1. PO(简单)类注解配置
在hibernate中我们使用注解,可以帮助我们简化hbm文件配置。
导入的包是javax.persisitance
@Entity //定义一个实体
@Table //来描述类与表对应
@Id //来声明一个主键
@JoinCoulumn(name = "外键") //用于指定外键类(在外键所在的类中配置)
@JoinTable来描述中间表,并在中间表中描述外键分别与两个多表的映射关系
@GenerateValue //用它来声明一个主键生成策略
默认情况下相当于native
可以选择的主键生成策略 AUTO IDENTITY SEQUENCE
@Column //来定义列
注意:对于PO类中所有属性,如果你不写注解,默认情况下也会在表中生成对应的列。
列的名称就是属性的名称
@Temporal来声明日期类型
可以选择
TemporalType.DATA 只有年月日
TemporalType.TIME 只有小时分钟秒
TemporalType.TIMESTAMP 有年月日小时分钟秒
我们最终需要在hibernate.cfg.xml文件中将我们类中的注解配置引用生效
package com.itheima.domain;
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;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity //声明一个实体
//描述与表对应
@Table(name = "t_book",catalog = "hibernateTest")
public class Book {
@Id //主键
//声明主键生成策略,不写默认是native
@GeneratedValue(strategy=GenerationType.IDENTITY) //identity
private Integer id;
//声明列。name 对应数据库的列名,length 长度,nullable 是否为空
@Column(name = "name",length=30,nullable = true)
private String name;
//声明时间类型
@Temporal(TemporalType.TIMESTAMP) //既有日期又有时分秒
private Date publicactionDate;
private Double price; //因为声明了@Entity 实体,所以这里价格就算不加注解们也会生成进表中,值都为默认值
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getPublicactionDate() {
return publicactionDate;
}
public void setPublicactionDate(Date publicactionDate) {
this.publicactionDate = publicactionDate;
}
}
在实体类中使用注解声明后,还需要在hibernate.cfg.xml底下配置
<mapping class = "实体类的全类名">
编写测试类进行保存测试
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.itheima.domain.Book;
import com.itheima.utils.HibernateUtils;
public class HibernateAnnotionTest {
@Test
public void test1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Book book = new Book();
book.setName("一言不合学java");
book.setPrice(998d);
book.setPublicactionDate(new Date());
session.save(book);
transaction.commit();
session.close();
}
}
问题:1.如果我们主键生成策略想使用UUID类型?
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(catalog = "hibernateTest")
public class Person {
//问题一:问题:1.如果我们主键生成策略想使用UUID类型?
@Id
//主键成策略扩展的标签
@GenericGenerator(name = "myuuid",strategy="uuid")
@GeneratedValue(generator="myuuid")
private String id ;
//问题二:问题2:如果设定类的属性不在表中映射?
//使用@Transient
@Transient
private String msg;
}
对于我们以上讲解的关于属性配置的注解,我们也可以在其对应的getXxx方法去使用
一对多(多对一)
@OneToMany
@ManyToOne
以Customer与Order为例
Customer类
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
//客户的实体类 ------- 一的一方
@Entity
@Table(name = "t_customer",catalog = "hibernateTest")
public class Customer {
@Id
private Integer id ; //主键
private String name ; //姓名
// 描述客户可以有多个订单
/*
* targetEntity相当于<one-to-many class="">
* mappedBy相当于inverse=true
*/
@OneToMany(targetEntity=Customer.class,mappedBy="c",orphanRemoval=true)
//描述客户可以有多个订单
private Set<Order> order = new HashSet<Order>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Order> getOrder() {
return order;
}
public void setOrder(Set<Order> order) {
this.order = order;
}
}
Order类
import javax.persistence.Entity;
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 = "t_order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Double money;
private String receiverInfo; // 收货地址
// 订单与客户关联
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "c_id") // 指定外键列
private Customer c; // 描述订单属于某一个客户
public Customer getC() {
return c;
}
public void setC(Customer c) {
this.c = c;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public String getReceiverInfo() {
return receiverInfo;
}
public void setReceiverInfo(String receiverInfo) {
this.receiverInfo = receiverInfo;
}
}
示例:保存客户时,保存订单
对于这个示例我们需要在Customer中配置(级联)cascade操作,<save-update>
第一种方式,可以使用JPA提供的注解
(推荐使用)第二种方式:可以使用hibernate提供的注解
@OneToMany(targetEntity=Customer.class,mappedBy="c")
@Cascade(CascadeType.SAVE_UPDATE)
//描述客户可以有多个订单
private Set<Order> order = new HashSet<Order>();
以下是示例代码
将id设为自动增长
@Test
//测试级联保客户时候自动保存订单
public void test2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//订单1
Order order1 = new Order();
order1.setReceiverInfo("福建");
order1.setMoney(998d);
//订单2
Order order2 = new Order();
order2.setReceiverInfo("福建");
order2.setMoney(100d);
//顾客1
Customer customer = new Customer();
customer.setName("雷老虎");
//建立关系
order1.setC(customer);
order2.setC(customer);
customer.getOrder().add(order1);
customer.getOrder().add(order2);
session.save(customer);
transaction.commit();
session.close();
}
订单中没有关联客户的id,为什么?
原因:我们在Customer中配置了mappedBy= ” c ”(相当于inverse=true) 它代表的是外键的维护由Order方来维护,而Customer不维护,这时你在保存客户时,级联保存订单,是可以的,但是不能维护外键,所以,我们必须在代码中添加订单与客户关系。
扩展:关于hibernate注解@Cascade中的DELETE_ORPHAN过时
s
使用下面方案来替换过时方案
H ibernate关联映射-多对多
使用注解完成多对多配置.
描述学生与老师.
使用@ManyToMany来配置多对多,只需要在其中一端配置中间表,另一端使用mappedBy表示放置外键维护权。
创建PO类
T eacher类中
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
@Entity
@Table(name = "t_teacher")
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToMany(targetEntity = Student.class, mappedBy = "teachers") // 代表由对方来维护外键
@Cascade(CascadeType.ALL)
private Set<Student> students = new HashSet<Student>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
S tudent类中
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
@Entity
@Table(name = "t_student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToMany(targetEntity = Teacher.class)
// 使用JoinTabl来描述中间表,并描述中间表中外键与Student,Teacher的映射关系
// joinColumns它是用来描述(本方)Student与中间表中的映射关系
// inverseJoinColums它是用来描述对方(Teacher)与中间表中的映射关系
// 其中referencedColumnName = "id"可以省略,因为默认就是和主键关联
@JoinTable(name = "s_t", joinColumns = {
@JoinColumn(name = "c_student_id", referencedColumnName = "id") }, inverseJoinColumns = {
@JoinColumn(name = "c_teacher_id", referencedColumnName = "id") })
@Cascade(CascadeType.ALL)
private Set<Teacher> teachers = new HashSet<Teacher>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
}
总结:
一对多和多对多的配置步骤:
1.添加关联关系的注解:@ManyToOne,@OneToMany,ManyToMany
配置targetEntity(对方的类.class)
2.哪方维护外键:mappedBy="对方中,表示本方的名称"
3.在维护关系的一方添加外键映射
级联保存操作测试
因为我们将外键的维护权利由Student来维护,我们演示保存学生时,将都也级联保存。
我们在Student类中配置了级联
-
级联删除操作测试
H ibernate关联映射-一对一
以人与身份证号为例
一对一操作有两种映射方式:
- 在任意一方添加外键
- 主键映射
外键映射
创建实体
User类
上述配置,t_user表放弃对外键的维护权利
IDCard类
joinColumn指定外键列名称,当前配置外键是在t_idcard表中
测试代码
-
主键映射
以Husband与Wife为例
W ife的主键生成策略是identity
@PrimaryKeyJoinColumn 说明husband与wife是使用主键映射
H usband的主键我们设置成参考wife的主键方式
测试操作