Hibernate
Hibernate中常用的注解
@Entity表示该类是持久化类
@Table表示将该类映射到对应的表
@Id表示主键ID
@GenerateValue表示主键生成策略
@Column表示属性和字段的映射
@Transient表示忽略该属性
@OneToMany表示一对多
@ManyToOne表示多对一
@ManyToMany表示多对多
@OneToOne表示一对一
如果不想使用id作为主键,可以使用例如下面的这种方式
<property name="属性名称" type=“类型” column=“数据库字段名称”>
<generator class="assigned">
</property>
assigned表示主键由用户决定
@OneToMany一对多单向配置时:
package com.how2java.hibernateTest;
import org.hibernate.annotations.Entity;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "Category")
public class Category {
private Long id;
private String type;
private List<Product> products;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "type")
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
@JoinColumn(name = "cid")//name使用的是数据库字段名
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
package com.how2java.hibernateTest;
import org.hibernate.annotations.Entity;
import javax.persistence.*;
@Entity
@Table(name = "Product_")
public class Product {
private Long id;
private String name;
private Double price;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "price")
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
@OneToMany双向配置
package com.how2java.hibernateTest;
import org.hibernate.annotations.Entity;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "Category")
public class Category {
private Long id;
private String type;
private List<Product> products;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "type")
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
//mappedBy表示在多的一方Category的属性名,防止生成中间表
@OneToMany(cascade = CascadeType.ALL,mappedBy = "category")
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
package com.how2java.hibernateTest;
import org.hibernate.annotations.Entity;
import org.hibernate.annotations.ManyToAny;
import javax.persistence.*;
@Entity
@Table(name = "Product_")
public class Product {
private Long id;
private String name;
private Double price;
private Category category;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "price")
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@ManyToOne
@JoinColumn(name = "cid",referencedColumnName = "id") //name表示在本表中的数据库字段名,referencedColumnName表示对应的在连接的表中的数据库字段名
@Basic(fetch=FetchType.LAZY)
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
Hibernate中的Session接口是Hibernate向应用程序提供数据库操作的主要接口,它提供了基本的增删改查java对象的方法。
Session中的缓存:
session缓存是hibernate的一级缓存,Session缓存可以减少Hibernate应用访问数据库的频率。
session中的flush():将缓存中的对象属性变化更新数据库中的记录,使缓存中的对象和数据库记录保持一致。
调用flush()的时间点有:
1.手动调用flush()方法
2.事务提交的时候,会首先调用flush()方法,然后再提交事务
3.当程序执行一些查询操作的时候,如果缓存中的对象的属性已经发生变化,会先调用flush()方法,将变化更新到数据库中,以保证查询的对象属性是最新的。
session中的refresh()方法:刷新缓存中的数据
session中的clear()方法:清除缓存
实体对象在hibernate中的三种状态:
1 . 临时状态:对象创建出来,没有session管理,数据库中没有记录。
- 持久化状态:实体对象在数据库中有记录,并且有session管理。
- 游离状态:实体对象在数据库中有记录,但是对应的session已经关闭。
HIbernate的三种查询:
- HQL(HIbernate Query Language):Hibernate专门的查询语言
是使用类名而不是表名,不需要写select *,
例如:
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session session = sf.openSession();
session.beginTransaction();
String name = "iphone";
Query q = session.createQuery(' from Product p where p.name like ? ');//Product使用的是类名
q.setString(0,"%" + name + "%" );
List<Product> products = q.list();
......
- Criteria查询完全是面向对象的,完全看不到语句
例如:
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session session = sf.openSession();
session.beginTransaction();
String name = "iphone";
Criteria c = s.createCriteria(Product.class);
c.add(Restrictions.like("name","%"+name+"%"));
List<Product> products = c.list();
......
- 使用标准的SQL语句进行查询
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session session = sf.openSession();
session.beginTransaction();
String name = "iphone";
String sql = "select * from product_ p where p.name like "%"+name+"%"";
Query q = session.createSqlQuery(sql);
List<Product> products = q.list();
......
HIbernate事务:
Hibernate中任何对数据进行改动的操作都应该放在事务中。一个事务中,多个操作要么都成功,要么都失败。
事务是由Session的beginTransaction()开始,由Session的getTransaction().commit()结束。
HIbernate延迟加载:
属性延迟加载:使用load()方法取对象的时候,如果不访问对象的属性,是不会去数据库中查找该对象。只有在访问该对象的属性的时候,才会去数据库中查找该对象。
关系延迟加载:在一对多或多对多关系中可以设置延迟加载,在取多的对象的时候才去查数据库加载。
HIbernate级联:
如果配置了级联,简单的说就是删除一个一方时,其对应的多的一方也会被删除。
有四种类型的级联
- all:所有的数据库操作都执行级联操作
- none:所有的数据库操作都不执行级联操作
- delete:删除操作执行级联操作
- save-update:执行级联操作
默认是none
Hibernate的一级缓存和二级缓存:
Hibernate的一级缓存:默认开启一级缓存,一级缓存放在session上
例如:
public static void main(String[] args){
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Category p1 = (Category) s.get(Category.class, 1);
Category p2 = (Category) s.get(Category.class, 1);
s.getTransaction().commit();
s.close();
Session s2 = sf.openSession();
s2.beginTransaction();
Category p3 = (Category) s2.get(Category.class, 1);
s2.getTransaction().commit();
s2.close();
sf.close();
}
上面的代码中,获取p1的时候会执行sql查询,获取p2的时候不执行sql直接从缓存中取,获取p3的时候执行sql,因为它们不是同一个session
Hibernate二级缓存:
二级缓存是放在SessionFactory上,二级缓存需要使用第三方插件开启
上面的代码中,只有在获取p1的时候执行sql查询,获取p2、p3的时候都不需要执行sql查询,直接从缓存中取。
Hibernate的分页:
使用Criteria的setFirstResult和setMaxResults实现分页
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Criteria criteria = s.createCriteria(Category.class);
criteria.add(Restrictions.like("name","%"+"iphone"+"%"));
criteria.setFirstResult(3); //从第4条开始
criteria.setMaxResults(5); //一共查询5条数据
Hibernate中的load和get的区别:
get不会延迟加载,会立即执行查询,当查询对象不存在的时候,返回null
load会延迟加载,在访问对象的属性或方法的时候,才去查询对象,当查询对象不存在的时候,会报错。
Hibernate中两种获取session的方式:
openSession():每次都会获取一个新的session,查询操作不需要事务,其他操作需要事务。
getCurrentSession():在同一个线程中,每次获取的都是同一个session,增删改查操作都需要事务。事务提交之后会自动关闭。
Hibernate的乐观锁:
当多个用户同时修改某个数据的时候,就会出现问题,这个时候可以给对象上添加version字段,用于版本控制,version字段必须紧挨着id字段。
当一个用户修改了数据库对象的时候,相应的version也会改变,当另一个已经获取version改变前的对象,进行修改操作的时候会和数据库中该对象当前的version进行比较,如果version不等于数据库中该对象当前的version,操作就会失败。
深入理解session中的flush()方法:
例如:
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session s = sf.openSession();
s.beginTransaction();
Product o = (Product) s.get(Product.class, 1); //从数据库中查id为1的product
System.out.println(o.getName()); //会把查询结果保存到session中
o.setName("iphone7");
s.flush(); //准备执行update操作
System.out.println(o.getName()); //获取到的是更新后的名字
Product o1 = (Product) s.get(Product.class, 1); //从session中获取
System.out.println(o1.getName());
输出为:
Hibernate: select product0_.id as id0_0_, product0_.name as name0_0_, product0_.price as price0_0_ from product_ product0_ where product0_.id=?
iphone
Hibernate: update product_ set name=?, price=? where id=?
iphone7