JPA是SUN公司的一个 ORM 规范,只有接口和注解,没有具体实现。JPA是 EJB3 中的子规范。
Hibernate中有两套注解规范:一套JPA,一套自己的;
使用注解开发,效率更高。
一、单表常用注解
1、简单自动创建一张数据表
/Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:
package hibernate.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity //引入javax.persistence包中的Entity注解
//表示book类是一个实体类
public class Book {
@Id //对应数据表中的主键
private Integer id;
private String name;
private Double 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 Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
/Hibernate5_d04_c04/src/hibernate/test/TestBook.java
程序代码如下:
package hibernate.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.domain.Book;
import hibernate.util.HibernateUtils;
public class TestBook {
//在数据库中自动生成一张数据表
@Test
public void testInit(){
HibernateUtils.getCurrentSession();
}
}
/Hibernate5_d04_c04/src/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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- jdbc:mysql:///hibernate_day01 -->
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate_day04</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--数据库方言 使用的数据库类型 -->
<property name="hibernate.dialect org.hibernate.dialect.MySQLDialect"></property>
<!-- 可选配置 -->
<!-- 在控制台输出sql语句 -->
<property name="show_sql">true</property>
<!-- 在控制台输出的sql语句格式化 -->
<property name="hibernate.format_sql">true</property>
<!-- 配置c3p0连接池 -->
<!-- C3P0 的供应商 -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!-- 最小连接 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">10</property>
<!-- 每 120 秒检查空闲连接 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 自动建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 把session绑定到当前线程中,使用getCurrentSession()获取当前session -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 映射文件 -->
<!-- 关联 xml 配置文件,注解方式配置 -->
<!-- 单表 -->
<mapping class="hibernate.domain.Book"/>
</session-factory>
</hibernate-configuration>
2、保存数据
/Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:
package hibernate.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity //引入javax.persistence包中的Entity注解
//表示book类是一个实体类
public class Book {
@Id //对应数据表中的主键
//主键生成策略
//AUTO = native
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private Double 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 Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
/Hibernate5_d04_c04/src/hibernate/test/TestBook.java
程序代码如下:
package hibernate.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.domain.Book;
import hibernate.util.HibernateUtils;
public class TestBook {
//在数据表中插入一条数据
@Test
public void testSave(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
Book book = new Book();
book.setName("西游记");
book.setPrice(88.88);
session.save(book);
tr.commit();
}
}
3、指定操作某个表
/Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:
package hibernate.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity //引入javax.persistence包中的Entity注解
//表示book类是一个实体类
@Table(name="t_book") //指定操作某个表
public class Book {
@Id //对应数据表中的主键
//主键生成策略
//AUTO = native
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private Double price;
...
}
4、更多常用注解
@Entity //注意引入的包名为javax.persistence.Entity
注解:可以放到属性声明上面设置,也可以在getter方法上设置,效果一样。但是:要么都放属性,要么都放getter,不能混着用。
//po实体类
@Entity //指定该po对象为实体对象,对应表
@Table(name="t_book") //类似:table="t_book"
public class Book {
@Id //指定该字段是主键,注解也可以写在getter方法上
//主键生成策略
//@GeneratedValue默认是自适应的主键策略:strategy=GenerationType.AUTO
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private Double price;
...
getter和setter方法
}
Auto 相当与 native,默认值
/Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:
...
public class Book {
@Id //指定该字段是主键,直接也可以写在getter方法上
//@GeneratedValue //默认是自适应的主键策略:strategy=GenerationType.AUTO
//@GeneratedValue(strategy=GenerationType.AUTO) //有点像native
@GenericGenerator(name="myIdGenerator",strategy="uuid") //主键策略生成器,name:是主键策略的名字,给下面用
@GeneratedValue(generator="myIdGenerator") //generator:指定一个具体的主键策略,可以自定义
private Integer id;
...
}
/Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:
...
public class Book {
...
//如果不加任何注解,则默认的属性名就是字段名
@Column(name="bname",length=30,nullable=false,unique=true) //name:字段名字
private String name;
//忽略属性:该属性不想映射为字段
@Transient //该属性不会作为数据库字段
private Double price;
...
}
name | 可选。列名(默认是属性名) |
unique | 可选。是否在该列上设置唯一约束(默认值false) |
nullable | 可选。是否设置该列的值可以为空(默认值false) |
insertable | 可选。该列是否作为生成的insert语句中的一个列(默认值true) |
updatable | 可选。该列是否作为生成的update语句中的一个列(默认值true) |
columnDefinition | 可选。为这个特定列覆盖SQL DDL片段(这可能导致无法在不同数据库间移植) |
table | 可选。定义对应的表(默认为主表) |
length | 可选。列长度(默认值255) |
precision | 可选。列十进制精度(decimal precision)(默认值0) |
scale | 可选。如果列十进制数值范围(decimal scale)可用,在此设置(默认值0) |
/Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:
...
//po实体类
@Entity //将当前类标识为一个实力类po,表名,默认就是实体类的名字
@Table(name="t_book",catalog="hb21")//table="t_book"
public class Book {
@Id //将当前字段标识为一个oid的属性,主键,主键策略默认为自动(根据数据库自动适应)
//@GeneratedValue //默认值是auto,相当于native
//@GeneratedValue(strategy=GenerationType.AUTO) //jpa内置的主键策略
//Hibernate的主键策略生成器,name:是主键策略生成器的名字,strategy:Hibernate的主键策略
@GenericGenerator(name="myIdGenerator",strategy="assigned")
@GeneratedValue(generator="myIdGenerator") //generator使用自定义扩展的主键生成器
private Integer id;
@Column(name="bname",length=30,unique=true)
//@Basic //该字段有效
private String name;
//Hibernate就不会将该属性作为字段的映射,忽略了该字段
@Transient
private Double price;
...
}
二、多表常用注解之一对多
1、注解案例
/Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:
package hibernate.domain;
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.Table;
@Entity
@Table(name="t_customer")
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private String city;
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 String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
/Hibernate5_d04_c04/src/hibernate/domain/Order.java
程序代码如下:
package hibernate.domain;
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="t_order")
public class Order {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private Double 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 Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
/Hibernate5_d04_c04/src/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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- jdbc:mysql:///hibernate_day01 -->
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate_day04</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--数据库方言 使用的数据库类型 -->
<property name="hibernate.dialect org.hibernate.dialect.MySQLDialect"></property>
<!-- 可选配置 -->
<!-- 在控制台输出sql语句 -->
<property name="show_sql">true</property>
<!-- 在控制台输出的sql语句格式化 -->
<property name="hibernate.format_sql">true</property>
<!-- 配置c3p0连接池 -->
<!-- C3P0 的供应商 -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!-- 最小连接 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">10</property>
<!-- 每 120 秒检查空闲连接 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 自动建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 把session绑定到当前线程中,使用getCurrentSession()获取当前session -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 映射文件 -->
<!-- 关联 xml 配置文件,注解方式配置 -->
<!-- 一对多 -->
<mapping class="hibernate.domain.Customer"/>
<mapping class="hibernate.domain.Order"/>
</session-factory>
</hibernate-configuration>
/Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:
...
@Entity
@Table(name="t_customer")
public class Customer {
...
//一对多
@OneToMany
private Set<Order> orders = new HashSet<>();
...
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
/Hibernate5_d04_c04/src/hibernate/domain/Order.java
程序代码如下:
...
@Entity
@Table(name="t_order")
public class Order {
...
//多对一
@ManyToOne
private Customer customer;
...
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
/Hibernate5_d04_c04/src/hibernate/test/TestOne2Many.java
程序代码如下:
package hibernate.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.domain.Customer;
import hibernate.domain.Order;
import hibernate.util.HibernateUtils;
public class TestOne2Many {
//保存数据
@Test
public void testOne2Many(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//新建一个客户
Customer c = new Customer();
c.setName("冠希");
//新建2个订单
Order o1 = new Order();
o1.setName("摄像机");
Order o2 = new Order();
o2.setName("电脑");
//双向关联
c.getOrders().add(o1);
c.getOrders().add(o2);
o1.setCustomer(c);
o2.setCustomer(c);
//保存操作
session.save(o1);
session.save(o2);
session.save(c);
tr.commit();
}
}
/Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:
...
@Entity
@Table(name="t_customer")
public class Customer {
...
//一对多
//mappedBy 除去中间表
//mappedBy 是关联对象Order类在自己的实体类中一方的属性(需要在一方配置)
//mappedBy="customer" 会在order表中生成一个外键,这里将生成叫customer_id的外键
@OneToMany(mappedBy="customer")
private Set<Order> orders = new HashSet<>();
...
}
2、更多配置
/Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:
...
public class Customer {
...
//关系:注解都直接配置关系
//@OneToMany(mappedBy="customer") //mappedBy是关联属性order在自己的实体类中的一方的属性(需要在一方配置)
//它会自动将Customer的主键作为外键,并且,自动将外键名称设置为:实体类小写_id
@OneToMany(cascade=CascadeType.ALL //级联
,fetch=FetchType.LAZY //是否懒加载
,orphanRemoval=true //是否支持孤儿删除
,mappedBy="Customer" //关系对象中关系属性的名字
,targetEntity=hibernate.domain.Order.class //关联属性的实体类的名字(全名),一般忽略。
//某些情况下不能忽略,Order如果是个借口,不是具体的实现的情况下,这里就要配置具体的实现类
)
private Set<Order> orders = new HashSet<>();
...
}
/Hibernate5_d04_c04/src/hibernate/domain/Order.java
程序代码如下:
...
@Entity
@Table(name="t_order")
public class Order {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private Double price;
//关系
@ManyToOne
@JoinColumn(name="c_id") //在关系(对象)表中配置外键名称,如果不配置,默认:实体类小写_id
private Customer customer;
...
}
三、多表常用注解之多对多
1、注解案例
/Hibernate5_d04_c04/src/hibernate/domain/Student.java
程序代码如下:
package hibernate.domain;
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;
@Entity
@Table(name="t_student")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
//多对多
@ManyToMany
private Set<Course> courses = new HashSet<>();
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<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
}
/Hibernate5_d04_c04/src/hibernate/domain/Course.java
程序代码如下:
package hibernate.domain;
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;
@Entity
@Table(name="t_course")
public class Course {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
//多对多
@ManyToMany
private Set<Student> students = new HashSet<>();
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;
}
}
/Hibernate5_d04_c04/src/hibernate/test/TestMany2Many.java
程序代码如下:
package hibernate.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.domain.Course;
import hibernate.domain.Student;
import hibernate.util.HibernateUtils;
public class TestMany2Many {
@Test
public void testMany2Many(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//新建一个学生
Student s = new Student();
s.setName("冠希");
//新建一门课程
Course c = new Course();
c.setName("摄影");
//双向关联
s.getCourses().add(c);
c.getStudents().add(s);
//保存
session.save(c);
session.save(s);
tr.commit();
}
}
/Hibernate5_d04_c04/src/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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- jdbc:mysql:///hibernate_day01 -->
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate_day04</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--数据库方言 使用的数据库类型 -->
<property name="hibernate.dialect org.hibernate.dialect.MySQLDialect"></property>
<!-- 可选配置 -->
<!-- 在控制台输出sql语句 -->
<property name="show_sql">true</property>
<!-- 在控制台输出的sql语句格式化 -->
<property name="hibernate.format_sql">true</property>
<!-- 配置c3p0连接池 -->
<!-- C3P0 的供应商 -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!-- 最小连接 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">10</property>
<!-- 每 120 秒检查空闲连接 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 自动建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 把session绑定到当前线程中,使用getCurrentSession()获取当前session -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 映射文件 -->
<!-- 关联 xml 配置文件,注解方式配置 -->
<!-- 多对多 -->
<mapping class="hibernate.domain.Course"/>
<mapping class="hibernate.domain.Student"/>
</session-factory>
</hibernate-configuration>
* *
程序代码如下:
...
@Entity
@Table(name="t_course")
public class Course {
...
//多对多
//mappedBy只会生成一张中间表
//必须在某一方配置外键关联字段
//mappedBy="courses" 对应Student类中的Set<Course> courses
//应该配置中间表的信息
//如果不配置,默认中间表的名字就是表名 1_表名 2,字段是各自的:实体类名字_id
@ManyToMany(mappedBy="courses")
private Set<Student> students = new HashSet<>();
...
}
2、更多配置
/Hibernate5_d04_c04/src/hibernate/domain/Student.java
程序代码如下:
...
@Entity
@Table(name="t_student")
public class Student {
@Id
@GeneratedValue
private Integer id;
private String name;
//多对多关系
@ManyToMany
//应该配置中间表的信息,如果不配置,默认的中间表的名字就是:表名1_表名2,字段是各自的:实体类字段_id
@JoinTable(name="t_student_course" //自定义中间关系表信息,name:中间表的名字
,joinColumns=@JoinColumn(name="s_id") //自己在关系表中的外键的名字
,inverseJoinColumns={@JoinColumn(name="c_id")} //对方在关系表中外键的名称
)
private Set<Course> courses = new HashSet<>();
...
}
/Hibernate5_d04_c04/src/hibernate/domain/Course.java
程序代码如下:
...
@Entity
@Table(name="t_course")
public class Course {
@Id
@GeneratedValue
private Integer id;
private String name;
//多对多关系
@ManyToMany(mappedBy="courses") //外键维护权,多表只能在一方配置
//必须在某一方面配置外键关联字段
private Set<Student> students = new HashSet<>();
...
}
四、抓取策略注解
.在一方Customer类中配置抓取策略
/Hibernate5_d04_c04/src/hibernate/test/TestFetch.java
程序代码如下:
package hibernate.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.domain.Customer;
import hibernate.util.HibernateUtils;
public class TestFetch {
@Test
public void testFetch(){
//获取11号客户
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
Customer c = session.get(Customer.class, 11);
//获取客户对应的所有订单数量
System.out.println(c.getName()+"-->"+c.getOrders().size());
tr.commit();
}
}
/Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:
...
@Entity
@Table(name="t_customer")
public class Customer {
...
@OneToMany(mappedBy="customer")
//配置抓取策略
@Fetch(FetchMode.JOIN)
@LazyCollection(LazyCollectionOption.TRUE)
private Set<Order> orders = new HashSet<>();
...
}
配置抓取策略前
发送两条SQL语句