Hibernate持久化类的理解
对于映射(mapping),有两套API,一个是Hibernate Session
,另一个是Java Persistence EntityManager
。后者是Java持久化的标准,因此,允许改变持久化实现而不会出现问题,很多实现都是参考了这个标准的。这里讲的是Hibernate Session。
1 持久化类的三个状态
Using Hibernate is different from using SQL. If you call session.save(customerObject)
then there is no insert into customer… query into the database. Hibernate will set the id property (if the id is generated) and bind the entity to a persistence context
. The persistence context is synchronized with the database when transaction.commit()
is called.
三个状态的关系及可以使用的操作
由图可知,
- 1 新建的对象,处于transient
,其还没有主键(如果主键自动生成的话),与数据库无半毛钱关系。
- 2 当session.save()
之后,处于persistent
状态,hibernate会设置主键,并将其与persistent context
(A persistence context handles a set of entities which hold data to be persisted in some persistence store (e.g. a database),你可以把它看作缓存。)绑定。此时,对对象所做的修改,会reflect到cache
(in-memory)中。因此,此时在database中也看不到插入的数据。只有tx.commit()
(事务结束)之后,才会插入到database中。我试验过,确实这样,不commit,在数据库中是看不到的。
- 3 在session.close()
之后,对象就处于detached
状态。对其所做的修改,不会reflect到cache中。当其通过session.update()
或者 session.lock()
操作之后,就可以将其转化为persistent状态。
2 CRUD操作
CRUD操作几乎是工作中最常见的操作,这里也学习一下。
mysql数据库
create database podemo;
create table car (
car_id int(11) not null auto_increment primary key,
brand varchar(20),
type varchar(20),
price int(255)
)ENGINE=InnoDB;
PO类
package com.chris.po;
@Entity
@Table(name="car")
public class Car {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY )
@Column(name="car_id")
private Integer id;
private String brand;
private String type;
//单位为分,不是元
private int price;
public int getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
- insert
新建对象,调用setter方法,然后session.save()
和tx.commit()
Transaction tx = session.beginTransaction();
Car car = new Car();
car.setBrand("Audi");
car.setType("ranger");
car.setPrice(30000000);
session.save(car);
tx.commit();
- update
要想update一个已经存在于数据库中的对象,必须先将其加载为持久化对象,可以通过session.get()
或者session.load()
方法。
Transaction tx = session.beginTransaction();
Car car = (Car) session.get(Car.class, 1);
car.setBrand("BMW");
tx.commit();
- delete
对于可以删除持久化态的对象,也可以删除detached
状态的对象。(注意:
对于JPA来说,必须先转化为persistent状态,才能删除。)
如果两个实体之间存在外键约束,可以设置级联(cascading)删除。
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
Car car = new Car();
car.setBrand("Buick");
car.setType("ranger");
car.setPrice(20000000);
session.save(car);
tx.commit();
session.close();
Session sess2 = sf.openSession();
Transaction tx2 = sess2.beginTransaction();
sess2.delete(car);
tx2.commit();
sess2.close();
3 getCurrentSession()和openSession()
current_session_context_class
使用sessionFactory.getCurrentSession()
默认会将session
绑定到当前上下文(current context),默认的context是线程(thread,局部事务)。换句话说,调用openSession()
的线程会和这个打开的session
绑定。current_session_context_class除了thread这个选项,还可以和jta绑定(全局事务)或者自己实现org.hibernate.context.CurrentSessionContext(不常用)。
openSession()
这个方法每次调用都会返回一个新的Session
对象,是org.hiberante.impl.SessionImpl的实例。
- 这个方法不会自动的flush()
和close()
打开的session,因此需要我们自己进行。
getCurrentSession()
获取current session,默认与thread绑定。当getCurrentSession()
方法被调用时,打开一个session
,如果已经存在了session,则利用这个已经存在的session对象;当事务结束时,关闭session。通过这个方法打开的session会自动flush()
和close()
。
在Web应用中,一般是一个请求对应一个thread,故如果将current_session_context_class
设置为thread
,使用sessionFactory.getCurrentSession()
,则不同的请求会有不同的session。