Hibernate 1、引入依赖:
2、创建Hibernate配置文件
对于java项目必须放在根目录下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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.dialect" > org.hibernate.dialect.MySQLDialect</property > <property name ="hibernate.connection.driver_class" > com.mysql.jdbc.Driver</property > <property name ="hibernate.connection.url" > jdbc:mysql://localhost:3306/for_test</property > <property name ="hibernate.connection.username" > root</property > <property name ="hibernate.connection.password" > </property > <property name ="hibernate.show_sql" > true</property > <property name ="hibernate.format_sql" > true</property > <mapping resource ="com/bean/Customer.xml" /> </session-factory > </hibernate-configuration >
3、创建HibernateUtil工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.util;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.boot.MetadataSources;import org.hibernate.boot.registry.StandardServiceRegistry;import org.hibernate.boot.registry.StandardServiceRegistryBuilder;public class HibernateUtil { private static SessionFactory sessionFactory; static { StandardServiceRegistry registry = new StandardServiceRegistryBuilder ().configure().build(); try { sessionFactory = new MetadataSources (registry).buildMetadata().buildSessionFactory(); }catch (Exception e){ e.printStackTrace(); StandardServiceRegistryBuilder.destroy(registry); } } public static Session openSession () { return sessionFactory.openSession(); } public static void closeSessionFactory () { sessionFactory.close(); } }
HelloWorld 1 2 3 4 5 6 7 8 9 10 11 12 13 <?xml version="1.0" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping package ="com.bean" > <class name ="Customer" table ="customer" > <id name ="id" column ="id" /> <property name ="name" column ="name" /> </class > </hibernate-mapping >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.bean;public class Customer { private int id; private String name; public int getId () { return id; } public void setId (int id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public Customer (int id, String name) { this .id = id; this .name = name; } public Customer () { } }
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import com.bean.Customer;import com.util.HibernateUtil;import org.hibernate.Session;import org.hibernate.Transaction;import org.junit.Test;public class HibernateTest { @Test public static void main (String[] args) { Customer customer = new Customer (3 ,"jjw2" ); saveCustomer(customer); } public static void saveCustomer (Customer c) { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); session.save(c); tran.commit(); session.close(); } }
单实体映射 对象-关系映射文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <hibernate-mapping package ="com.bean" > <class > <id /> <property /> </class > </hibernate-mapping > <class > </class > 用于指定类和表之间的映射<id > </id > 设定持久化类的 OID(对象标识符) 和表的主键的映射关系。<property > </property > 设定类的其它属性和表的字段的映射关系。
单实体的属性映射 property的属性
在对象-关系映射文件中元素的 access 属性用于指定Hibernate访问持久化类属性的方式
property : 默认值,通过getter(增删改)和setter(查)方法访问属性值;
field : 通过Java反射机制直接访问属性值。
场景:当持久化类属性与数据库字段不对称时,可以利用access属性调用对应的getter、setter方法
1 2 3 4 5 6 7 8 9 public String getUserName () { return firstName + "" +lastName; } public void setUserName (String name) { String[] strName = userName.split("" );this .firstName = strName[0 ]; this .lastName = strName[1 ]; )
场景:User 需要订单总额属性,但数据库表中没有这个字段。可在元素的 formula 属性设置查询语句(formula属性仅在查询操作中起作用)
1 2 3 <property name ="totalPrice" formula ="(select sum(o.price) from orders as o where o.userId=id)" />
控制持久化类的insert和update
这些属性用于控制insert和update,例如update=”false”时,不更新这个字段 ,dynamic-update=”true”时,当执行更新操作时,如果设置的属性为null则不改变之前的值,但是使用dynamic-update=”true”的前提是先获取一次这个数据到缓存中,才能用新的数据对比缓存中的数据,进而修改不需要改变的数据
单实体的对象标识符映射 Hibernate 采用对象标识符(OID)区分对象。
Hibernate 自带了很多种标识符生成器
increment 采用 Hibernate 数值递增的方式;
identity 采用数据库提供的自增长方式;
assigned 主键由应用逻辑产生;
sequence 采用数据库提供的序列方式;
hilo 通过hi/lo算法 // Hibernate 5.0 以后不支持;
seqhilo 通过hi/lo算法;
native 自动选择合适的标识符生成器;
uuid.hex 通过uuid算法。
使用注解映射单实体
@Entity:声明一个实体
@Table(name=”table_name”):为实体类指定对应的数据库表。
@Id:声明实体类的OID属性。
@GeneratedValue(generator=”increment_generator”):声明OID的生成策略。(JPA通用注解)
@GenericGenerator(name=”increment_generator”, strategy=”increment”):使用Hibernate提供的生成策略
@Column(name=”columnName”) :将属性映射到列。
这个类只标明了他是一个注解类,并且主键是自增长的,然而其他的一些属性并没有配置注解,那么他一样会在数据库的表中存在,因为这些属性默认就有@Column注解。因此如果没有添加注解,则hibernate会自动在属性前面添加@Column注解。
name=”columnName” 字段名称;
unique=false 是否在该字段上设置唯一约束;
nullable=true 字段是否能为空;
insertable=true 控制 insert语句;
updatable=true 控制 update语句;
length=255 指定字段长度。
@Access(AccessType.PROPERTY):
通过 getter 和 setter 方法访问实体类的属性;
需要在 getter 方法上定义字段的属性
@Access(AccessType.FIELD):
直接访问实体类的属性,可以不定义 getter 和 setter 方法;
需要在变量上定义字段的属性。
@Formula:将属性映射到SQL语句。
@DynamicInsert:动态生成 INSERT 语句。
@DynamicUpdate:动态生成 UPDATE 语句。
注意:
对于属性字段和表的字段关系对应的注解属性的位置,一般我们采用以下两种方式
第一种: 是把注解@Column(name =”xx”)放在field上
第二种: 是把注解@Column(name= “xx”)放在get方法上
但是第一种方式这样做实际上破坏了java面向对象的封装性 ,原因是一般我们写javaBean,成员变量通常定义为private,目的就是不让别人来直接访问的私有属性,而我们把注解放在私有成员的变量上,就是默认hibernate可以直接访问我们的私有的成员变量,所以我们定义属性为private,就实际没有多大意义,至于hibernate为什么能访问,hibernate采用java的反射机制完全可以访问私有成员变量!所以应该放在get方法上,第二种方式这个时候就显得更加合理。
Hibernate继承关系映射 场景:现要为某公司开发一个员工信息管理系统,已经了解到该公司的员工中有按小时计薪和按月计薪两种方式,这种情况下系统中该如何维护员工的基本信息呢?
三种不同的解决方案:
一方案:
关系数据模型不支持域模型中的继承关系和多态。
每个子类所对应的表中同时存在从父类继承的属性和自己特有的属性。
如果父类不是抽象类并且也需要被持久化,还需要为父类创建对应的表。
映射文件形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <class name ="HourlyEmployee" table ="HOURLYEMPLOYEE" > <id name ="id" > <generator class ="increment" /> </id > <property name ="name" /> <property name ="rate" /> </class > <class name ="SalariedEmployee" table ="SALARIEDEMPLOYEE" > <id name ="id" > <generator class ="increment" /> </id > <property name ="name" /> <property name ="salary" /> </class >
注解形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Entity @Table(name="HourlyEmployee") public class HourlyEmployee extends Employee { private String name; private String rate; ... } @Entity @Table(name="SalariedEmployee") public class SalariedEmployee extends Employee { private String name; private String salary; ... }
Employee基类
1.标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。
2.标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。
1 2 3 4 5 6 7 8 9 10 11 @MappedSuperclass public class Employee { @Id @GeneratedValue public Integer getId () { return this .id; } public void setId (Integer id) { this .id = id; } }
方案二:
关系数据模型支持继承关系和多态。
在表中加入额外的字段区分子类的类型,表中包含父类和所有子类的属性对应的字段。
支持多态查询,就是从数据库中检索父类对象时,同时包含所有子类的对象。
在数据库表中会有这样的一个字段用来区别记录的属性,如:在客户表中有一个字段表示客户级别,当这个记录为A时是一级客户,为B时是二级客户;然后,在程序中手动控制flag的值,但是这样当每个级的客户有不同的属性时Customer类将包含所有级别的属性 ,这样不是很好。
hibernate提供一个Discriminator映射的方法,就是把一个表映射成不同的类,有不同的属性 。
xml文件方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <class name ="Employee" table ="EMPLOYEE" > <id name ="id" > <generator class ="increment" /> </id > <discriminator column ="EMPLOYEETYPE" /> <property name ="name" /> <subclass name ="HourlyEmployees" discriminator-value ="HE" > <property name ="rate" /> </subclass > <subclass name ="SalariedEmployees" discriminator-value ="SE" > <property name ="salary" /> </subclass > </class >
注解形式
Employee基类
指定继承关系的生成策略
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
指定区分子类类型的字段。
@DiscriminatorColumn(name=”EMPLOYEETYPE”)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Entity @Table(name="employee") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="employee_type") public class Employee { private Integer id; private String name; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId () { return id; } ... }
各个子类使用注解:
指定各个子类区分字段的值。
@DiscriminatorValue(value = “”)
1 2 3 4 5 6 7 8 @Entity @DiscriminatorValue(value="HE") public class HourlyEmployee extends Employee { private double rate; ... }
方案三:
在关系数据模型中,用外键参照关系来表示继承关系,子类对应的表中存在外键参照父类对应表的主键。
继承关系中的每个类及接口都对应一个表。
支持多态查询。
xml文件形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <class name ="Employee" table ="EMPLOYEE" > <id name ="id" > <generator class ="increment" /> </id > <property name ="name" /> <joined-subclass name ="HourlyEmployee" table ="HOURLYEMPLOYEE" > <key column ="EMPLOYEEID" /> <property name ="rate" /> </joined-subclass > <joined-subclass name ="SalariedEmployee" table ="SALARIEDEMPLOYEE" > <key column ="EMPLOYEEID" /> <property name ="salary" /> </joined-subclass > </class >
注解形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Entity @Table(name="employee") @Inheritance(strategy=InheritanceType.JOINED) public class Employee { private Integer id; private String name; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId () { return id; } ... } @Entity @Table(name="hourly_employee") @PrimaryKeyJoinColumn(name="employee_id") public class HourlyEmployee extends Employee { ... }
Hibernate一对一关联映射 参考:https://www.cnblogs.com/whgk/p/6128395.html
一对一关系映射
实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class User { private Integer id; private String userName; private String password; private Person person; …… } public class Person { private Integer id; private String name; private String idNumber; private User user; …… }
Hibernate提供两种映射一对一关联关系的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 <hibernate-mapping package ="com.hibernate.entity" > <class name ="Person" table ="person" > <id name ="id" column ="person_id" > <generator class ="foreign" > <param name ="property" > user</param > </generator > </id > <property name ="name" /> <property name ="idNumber" /> <one-to-one name ="user" class ="User" constrained ="true" /> </class > </hibernate-mapping > <hibernate-mapping package ="com.hibernate.entity" > <class name ="User" table ="user" > <id name ="id" column ="id" > <generator class ="identity" /> </id > <property name ="userName" > <column name ="user_name" > </column > </property > <property name ="password" /> <one-to-one name ="person" class ="Person" cascade ="all" > </one-to-one > </class > </hibernate-mapping >
1 2 3 4 5 6 User u = session.get(User.class, id);u.setPerson(p); p.setUser(u); session.save(p);
级联操作(保存为例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 User u = new User ("李四" , "8888888" ); Person p = new Person (); p.setName("Tom" ); p.setIdNumber("1111111" ); u.setPerson(p); p.setUser(u); Session session = HibernateUtil.openSession();Transaction tran = session.beginTransaction();session.save(u); tran.commit(); session.close();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <hibernate-mapping package ="com.hibernate.entity" > <class name ="Person" table ="person" > <id name ="id" column ="person_id" > <generator class ="foreign" > <param name ="property" > user</param > </generator > </id > <property name ="name" /> <property name ="idNumber" /> <one-to-one name ="user" class ="User" property-ref ="person" /> </class > </hibernate-mapping > <hibernate-mapping package ="com.hibernate.entity" > <class name ="User" table ="user" > <id name ="id" column ="id" > <generator class ="identity" /> </id > <property name ="userName" > <column name ="user_name" > </column > </property > <property name ="password" /> <one-to-one name ="person" column ="per_id" class ="Person" unique ="true" /> </class > </hibernate-mapping >
级联操作(保存为例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static void save (User u, Person p) { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); u.setPerson(p); p.setUser(u); session.save(u); session.save(p); tran.commit(); session.close(); }
使用注解映射主键关联的一对一
@OneToOne(cascade=CascadeType.ALL) //指定一对一关系,并设置级联属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 @Entity @Table(name="user") public class User { private Integer id; private String userName; private String password; private Person person; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId () { return id; } ... @OneToOne(targetEntity=Person.class, cascade=CascadeType.REMOVE) @PrimaryKeyJoinColumn(name="person_id") public Person getPerson () { return person; } public void setPerson (Person person) { this .person = person; } ... @Column(name="user_name") public String getUserName () { return userName; } ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Entity @Table(name="person") public class Person { private Integer id; private String name; private String idNumber; private User user; @Id @GeneratedValue(generator="my_gen") @GenericGenerator(name="my_gen", strategy="foreign", /* 设置参数 */ parameters= {@Parameter(value="user",name="property")}) public Integer getId () { return id; } ... @OneToOne(mappedBy="person",targetEntity=User.class) public User getUser () { return user; } ... }
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name=”PERSONID”):指明USER表中的外键列名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Entity @Table(name="user") public class User { private Integer id; private String userName; private String password; private Person person; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId () { return id; } ... @OneToOne @JoinColumn(name="per_id") public Person getPerson () { return person; } ... @Column(name="user_name") public String getUserName () { return userName; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Entity @Table(name="person") public class Person { private Integer id; private String name; private String idNumber; private User user; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId () { return id; } ... @OneToOne(mappedBy="person") public User getUser () { return user; } }
组合关系映射
xml映射文件方式
Address类不能持久化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <hibernate-mapping package ="com.hibernate.entity" > <class name ="Contact" table ="contact" > <id name ="id" > <generator class ="identity" /> </id > <property name ="phoneNum" /> <component name ="homeAddress" class ="Address" > <property name ="province" column ="home_pro" /> <property name ="city" column ="home_city" /> </component > <component name ="workAddress" class ="Address" > <property name ="province" column ="work_pro" /> <property name ="city" column ="work_city" /> </component > </class > </hibernate-mapping >
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class Test { public static void main (String[] args) { Address home = new Address (); home.setProvince("河北省" ); home.setCity("邯郸市" ); Address work = new Address (); work.setProvince("河北省" ); work.setCity("石家庄市" ); Contact c = new Contact (); c.setPhoneNum("15000001222" ); c.setHomeAddress(home); c.setWorkAddress(work); saveContact(c); HibernateUtil.closeSessionFactory(); } public static void saveContact (Contact c) { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); session.save(c); tran.commit(); session.close(); } }
注解方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Embeddable public class Address { ...... } @Embedded @AttributeOverrides(value={ @AttributeOverride( name = "province", column = @Column(name=“HOMEPROVINCE")), @AttributeOverride( name = "city", column = @Column(name=“HOMECITY")), ...... }) public class Contact { ...... }
Hibernate一对多关联映射
xml映射文件
实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class User { private Integer id; private String userName; private String password; private Set orderSet = new HashSet <Order>(); ...... } public class Order { private Integer id; private Double price; ...... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <hibernate-mapping package ="com.hibernate.entity" > <class name ="User" table ="user" > <id name ="id" column ="id" > <generator class ="identity" /> </id > <property name ="userName" column ="user_name" /> <property name ="password" not-null ="true" length ="11" /> <set name ="orders" cascade ="all" > <key column ="user_id" > </key > <one-to-many class ="Order" /> </set > </class > </hibernate-mapping > <hibernate-mapping package ="com.hibernate.entity" > <class name ="Order" table ="orders" > <id name ="id" > <generator class ="identity" > </generator > </id > <property name ="orderNum" /> <property name ="price" /> </class > </hibernate-mapping >
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class Test { public static void main (String[] args) { Order o = new Order (); o.setOrderNum("QW121212121212121" ); o.setPrice(100.0 ); saveOrder(111 , o); HibernateUtil.closeSessionFactory(); } public static void saveOrder (Integer userId,Order o) { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User u = session.get(User.class, userId); u.getOrders().add(o); session.save(o); tran.commit(); session.close(); } }
xml文件形式
1 2 3 4 5 6 7 8 9 10 11 12 <hibernate-mapping package ="com.hibernate.entity" > <class name ="Order" table ="orders" > <id name ="id" > <generator class ="identity" > </generator > </id > <property name ="orderNum" /> <property name ="price" /> <many-to-one name ="user" class ="User" column ="user_id" /> </class > </hibernate-mapping >
注解形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Entity @Table(name="orders") public class Order { private Integer id; private String orderNum; private double price; private User user; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId () { return id; } ... @ManyToOne(targetEntity=User.class) @JoinColumn(name="user_id") public User getUser () { return user; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Entity @Table(name="user") public class User { private Integer id; private String userName; private String password; private Set<Order> orders = new HashSet <Order>(); @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId () { return id; } ... @OneToMany(targetEntity=Order.class, cascade=CascadeType.REMOVE, mappedBy="user" /*表示在另一头的user属性中已经映射了*/) public Set<Order> getOrders () { return orders; } public void setOrders (Set<Order> orders) { this .orders = orders; } }
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class Test { public static void main (String[] args) { Order o = new Order (); o.setOrderNum("QW121212121212121" ); o.setPrice(100.0 ); saveOrder(111 , o); HibernateUtil.closeSessionFactory(); } public static void saveOrder (Integer userId,Order o) { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); User u = session.get(User.class, userId); u.getOrders().add(o); o.setUser(u); session.save(o); tran.commit(); session.close(); } }
Hibernate多对多关联映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Student { private int id; private String name; private String studentNo; private Set<Course> courseSet = new HashSet <Course>(); ...... } public class Course { private Integer id; private String name; private int credit; private Set<Student> studentSet = new HashSet <Student>(); ...... }
xml文件形式
inverse 是 Hibernate 中双向关联关系中的基本概念,用来设置关系由哪一方来维护
inverse=true 表示被控方,=false 表示主控方
在多对多关系中需要设置哪一方为被控方,即设置inverse=true
只能在双向一对多,多对多中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <set name ="courseSet" table ="student_course" inverse ="false" > <key column ="student_id" /> <many-to-many class ="Course" column ="course_id" /> </set > <set name ="studentSet" table ="student_course" inverse ="true" > <key column ="course_id" /> <many-to-many class ="Student" column ="student_id" /> </set >
注解形式
Hibernate操作持久化对象 session缓存
缓存介于应用程序和永久性存储源之间,其作用是降低应用程序直接读写永久性存储源的频率,从而提高应用的运行效率。
缓存内的数据是永久性存储源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件同步缓存和永久性存储源的数据。
当 Session 执行查询方法时,先从 Session 缓存中读取据,如果缓存中有则直接读取,如果缓存中没有,从数据库中查询并加载到 Session 缓存中,再从缓存中读取。
当 Session 执行 save()、update() 方法时,将对象持久化到数据库中并将对象加载到 Session 缓存中。
session清理缓存
Session在某一时间点按照缓存中对象的属性变化来同步更新数据库的这一过程被称为 Session 清理缓存。
缓存清理的时间点:
当调用 transaction.commit() 方法时,会先清理缓存,再向数据库提交事务;
当显式调用 Session.flush() 方法时,会清理缓存;
当调用 Session 的查询(不包括 load() 和 get() )方法时,如果缓存中对象的属性有变化则清理缓存。
Session清理缓存的模式
setHibernateFlushMode() 用于设定 Session 清理缓存的模式。
Hibernate实体对象生命周期
Transient(临时状态) : 刚刚被 new 关键字创建,还没有被持久化,不在Session的缓存中。
Persistent(持久化状态) : 已经被持久化,并加入到 Session 缓存中。
Detached(游离状态) : 已经被持久化,但不再处于 Session 缓存中(给id赋值了)。
Removed(删除状态) : Session 已经计划将其从数据库删除,并且不再处于 Session 缓存中。
Hibernate检索方式 HQL检索方式
HQL语句中关键字大小写无关,但习惯将关键字小写。
from 关键字后面是类名不是数据库表名,类名需区分大小写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 public static void testHQL () { Session session = HibernateUtil.openSession(); String hql = "select u from User u" ; Query<User> query = session.createQuery(hql); List<User> users = query.list(); System.out.println(users); String hql = "select u.userName from User u" ; Query query = session.createQuery(hql); List<String> users = query.list(); System.out.println(users); String hql = "select u.userName, u.password from User u" ; Query query = session.createQuery(hql); List<User> users = query.list(); List<Object[]> users = query.list(); for (Object[] o : users) { System.out.println("用户名:" + o[0 ]); System.out.println("密码:" + o[1 ]); } String hql = "select u from User u where u.userName='张三'" ; Query<User> query = session.createQuery(hql); List<User> users = query.list(); System.out.println(users); String hql = "select u from User u where u.id=104" ; Query<User> query = session.createQuery(hql); User u = query.uniqueResult(); System.out.println(u); String hql = "select u from User u order by u.userName, u.id desc" ; Query<User> query = session.createQuery(hql); List<User> users = query.list(); System.out.println(users); String hql = "select u.userName, count(u) from User u group by u.userName having u.userName != '张三'" ; Query query = session.createQuery(hql); List<Object[]> users = query.list(); for (Object[] o : users) { System.out.println("用户名:" + o[0 ]); System.out.println("个数:" + o[1 ]); } String hql = "select u from User u where u.userName=?" ; Query query = session.createQuery(hql); query.setParameter(0 , "张三" ); List<User> users = query.list(); System.out.println(users); String hql = "select u from User u where u.userName=:name" ; Query query = session.createQuery(hql); query.setParameter("name" , "张三" ); List<User> users = query.list(); System.out.println(users); String hql = "select u from User u where u.userName=:userName" ; Query query = session.createQuery(hql); User u = new User (); u.setUserName("张三" ); query.setProperties(u); List<User> users = query.list(); System.out.println(users); String hql = "select u from User u where u.userName=:userName" ; Query query = session.createQuery(hql); Map<String, Object> map = new HashMap <>(); map.put("userName" , "张三" ); query.setProperties(map); List<User> users = query.list(); System.out.println(users); String hql = "select u from User u where (select count(o) from u.orders o) > 0" ; Query query = session.createQuery(hql); List<User> users = query.list(); System.out.println(users); session.close(); } public static void hqlUpdate () { Session session = HibernateUtil.openSession(); Transaction tran = session.beginTransaction(); String hql = "delete from User u where u.userName=?" ; Query<User> query = session.createQuery(hql); query.setParameter(0 , "张三" ); int row = query.executeUpdate(); System.out.println("影响的条数:" + row); tran.commit(); session.close(); }
HQL子查询说明以下几点:
子查询分为相关子查询和无关子查询;
相关子查询:子查询语句引用了外层查询语句定义的别名。
无关子查询:子查询语句没有引用外层查询语句定义的别名。
HQL子查询功能依赖于底层数据库对子查询的支持;
HQL子查询返回的是多条记录,使用以下关键字量化。
如果HQL子查询的是集合,HQL提供了一组操作集合的函数。
size(),获得集合中元素的个数;
maxIndex(),对于建立索引的集合,获得最大索引值;
minIndex(),对于建立索引的集合,获得最小索引值;
elements(),获得集合中所有元素。
做批量查询时,如果数据量很大就需要分页功能,HQL提供了用于分页查询的方法:
引用查询指在映射文件中定义查询语句。
QBC检索方式
Query By Criteria(QBC) 可以看作是传统SQL的对象化表示。它主要由Criteria接口,Criterion接口,Restrictions类组成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Criteria criteria=session.createCriteria(User.class); Criterion c1= Restrictions.eq("userName" , "张三" ); criteria.add(c1); List result = criteria.list();
本地SQL检索方式
1 2 3 4 5 6 7 8 String sql = "select * from user" ;NativeQuery query = session.createNativeQuery(sql, User.class);List list = query.list();
Hibernate检索策略
类级别检索策略:
立即检索:立即加载检索方法指定的对象。
加载多于需要的对象白白浪费内存空间
select 语句数量多,频繁访问数据库,影响系统性能
1 2 映射配置文件中<class > 元素的 lazy 属性设置为 false。 <class name ="User" table ="USER" lazy ="false" >
延迟检索:延迟加载检索方法指定的对象。
避免多加载应用程序不需要访问的数据对象
1 2 3 映射配置文件中<class > 元素的 lazy 属性设置为 true。 <class name ="User" table ="USER" lazy ="true" >
关联级别检索策略:
在映射文件中用 元素 来配置 一对多 和 多对多 关联关系。
1 2 3 4 5 一对多和多对多 修改User 一对多关联的Order对象的检索策略,User.hbm.xml 中<set > 元素 lazy 和 outer-join 属性 多对一 修改Order 多对一关联的 User 对象检索策略,Order.hbm.xml 中 <many-to-one > 元素 outer-join 属性和 User.hbm.xml 中<class > 元素的 lazy 属性。
迫切左外连接检索:利用SQL外连接查询功能加载检索方法指定对象。
减少执行select语句的数量,减少数据库访问,提高系统性能。
Hibernate二级缓存机制 SessionFactory有一个内置缓存 (实现机制跟Session缓存类似)和一个可以配置的缓存插件被称为外置缓存
Session缓存是事务范围的缓存。
SessionFactory缓存是进程范围或者集群范围的缓存。
进程范围和集群范围的缓存可能被进程内的多个事务并发访问,因此需要采取必要的并发访问策略。
持久化层的二级缓存,在查询时先在事务缓存中查找,如果没有查询到相应数据,再到进程范围或集群范围缓存中查找,如果还没找到再数据库中查找。
Hibernate二级缓存配置 Hibernate的第二级缓存是可配置的缓存插件,允许选用以下类型的缓存插件,表中给出了各个缓存插件支持的并发访问策略。
选择EHCache缓存插件的配置步骤如下
1、在Hibernate.cfg.xml配置文件中配置
1 2 3 4 5 6 <property name ="cache.use_second_level_cache" > true</property > <property name ="cache.region.factory_class" > org.hibernate.cache.ehcache.EhCacheRegionFactory</property >
2、设置实体映射配置文件中或元素的子元素的usage属性
1 2 3 4 5 6 7 8 9 <class name ="User" > <cache usage ="read-write" /> …… </class > transactional:一般缓存插件没有此策略(除jboss-cache) nonstrict-read-write:不严格的读写(如:帖子的回帖量) read-write:严格的读写(如:银行系统数据) read-only : 只读策略(对象不能修改,修改会报异常),效率最高