注解实现的一对多
@Table(name = "persons")
public class Person {
@Id
@Column(name = "person_id")
@GenericGenerator(name = "myid", strategy = "uuid")
@GeneratedValue(generator = "myid")
private String id;
@Column(name="person_name")
private String name;
@OneToMany
@Cascade(value=org.hibernate.annotations.CascadeType.SAVE_UPDATE)
@JoinColumn(name="car_personid")
private List<Car> cars = new ArrayList<>();
@Table(name="cars")
@Entity
public class Car {
@Id
@Column(name="car")
@GenericGenerator(name="uuid",strategy="uuid")
@GeneratedValue(generator="uuid")
private String id;
private String name;
@ManyToOne
@JoinColumn(name="car_personid")
private Person person;
注解实现的多对多
Stud{
@ManyToMany
@JoinTable(name=”sc”,@JsonColumn(name=”sc_sid”,@reversJoinColum(name=”sc_cid”)
Set<Course> set:
}
对象的状态,一级缓存、二级缓存。
1:对象的状态
•瞬时(Transient) — 由 new 操作符创建,且尚未与Hibernate
Session 关联的对象被认定为瞬时(Transient)的。瞬时(Transient)对象不会被持久化到数
据库中,也不会被赋予持久化标识(identifier)。 如果瞬时(Transient)对象在程序中没
有被引用,它会被垃圾回收器(garbage collector)销毁。 使用 Hibernate Session 可以将其
变为持久(Persistent)状态。(Hibernate会自动执行必要的SQL语句)
Person p = new Person (); 领域对象,这个对象 还没有与Sesssion创建关系此时叫瞬时
•持久(Persistent) — 持久(Persistent)的实例在数据库中有对应的记录,并拥有一
个持久化标识(identifier)。 持久(Persistent)的实例可能是刚被保存的,或刚被加载
的,无论哪一种,按定义,它存在于相关联的 Session 作用范围内。 Hibernate会检测到处于持
久(Persistent)状态的对象的任何改动,在当前操作单元(unit of work)执行完毕时将对
象数据(state)与数据库同步(synchronize)。 开发者不需要手动执行 UPDATE 。将对象从持
久(Persistent)状态变成瞬时(Transient)状态同样也不需要手动执行 DELETE 语句。
Session.ssave(p);//此时的p对象叫持久,与一个Session相关
•脱管(Detached) — 与持久(Persistent)对象关联的 Session 被关闭后,对象就变为脱管
(Detached)的。对脱管(Detached)对象的引用依然有效,对象可继续被修改。脱管
(Detached)对象如果重新关联到某个新的 Session 上, 会再次转变为持久(Persistent)的
(在Detached其间的改动将被持久化到数据库)。 这个功能使得一种编程模型,即中间会给用
户思考时间(user think-time)的长时间运行的操作单元(unit of work)的编程模型成为可
能。我们称之为应用程序事务,即从用户观点看是一个操作单元(unit of work)。
Session.close();
P.setname(“..”) 不会影响数据库中的值。
2:状态的与脏检查
@Test
public void test() {
Session s = HibernateUitls.openSession();
s.beginTransaction();
//根据id查询这个Person对象
Person p =
s.get(Person.class, "4028806a556d8c5701556d8c598b0000");//此时p对象叫持久化状态
p.setName("Smith");//脏检查
//s.update(p);
s.getTransaction().commit();
s.close();
}
3:懒加载
Session.get(Class,id) : 非懒加载,如果id不存在,则返回null- 命中数据库。
Session.load(CLass,id) :懒加载 - r返回的是一个代理,即使是id不存在,也返回一个对象
<class name="cn.hib.domain.Person" table="persons" lazy="false">
<id name="id" type="java.lang.String" length="32">
Session.load(CLass,id) 方法的使用的特点:
Session s = HibernateUitls.openSession();
s.beginTransaction();
Stud stud = s.get(Stud.class, "S002");
//只是为了设置关系,没有必要命中数据库,只要知道C001的id即可
Course c = s.load(Course.class, "C001");
stud.getCourses().add(c);
s.getTransaction().commit();
s.close();
4:延迟加载
Enumerated Values :
- true
- false
- extra 延迟加载
<set name="courses" table="sc" cascade="save-update" lazy="extra">
<key column="sc_sid"></key>
<many-to-many class="cn.hib.domain.Course" column="sc_cid"></many-to-many>
</set>
5:一级缓存与二级缓存
Session级别的缓存:一级缓存。它的特点是:容量没有限制。
事务级别的缓存,生命周期很短。
openSession() :..开始。
Session.close(); 关闭
一级缓存默认是打开的,且无法关闭。
SessionFactory级别的缓存 -
默认的是关闭的。必须配置以后才可以打开。
所有Session都共享同一个二级缓存。JVM级别的缓存。
容量是配置,且必须要使用第三方的框架。
1:一级缓存
@Test
public void test() {
Session s = HibernateUitls.openSession();
Person p1 = s.get(Person.class, "S001");//执行过程是:1:先去命中一级缓存,2:再去命中二级缓存 3:于是命中了数据库
//4:将这个对象放到二级缓存中去 5:放到一级缓存中去
Person p2 = s.get(Person.class, "S001");
System.err.println(p1==p2);
s.close();
可以操作删除一级缓存中的数据:
Session s = HibernateUitls.openSession();
Person p1 = s.get(Person.class, "S001");//执行过程是:1:先去命中一级缓存,2:再去命中二级缓存 3:于是命中了数据库
//4:将这个对象放到二级缓存中去 5:放到一级缓存中去
//s.evict(p1);//删除放到一级缓存中的p1这一个对象
s.clear();//删除放到一级缓存中的所有对象
Person p2 = s.get(Person.class, "S001");
System.err.println(p1==p2);
s.close();
2:一级缓存与批量处理
@Test
public void test() {
Session s = HibernateUitls.openSession();
s.beginTransaction();
for(int i=0;i<50;i++){
Person p = new Person();
p.setName("Jerry"+i);
s.save(p);
if(i%20==0){
s.flush();
s.clear();
}
}
6:二级缓存
SessionFactory级别的缓存。
步1:添加第三方的缓存包 ehcache
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-ehcache -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.1.0.Final</version>
</dependency>
步2:添加ehcache的配置文件
<defaultCache
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
步3:配置对哪一个类进行二级缓存
<!-- 配置启用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<mapping resource="cn/hib/domain/Person.hbm.xml" />
<mapping resource="cn/hib/domain/Stud.hbm.xml" />
<!-- 配置哪一个类进行二级缓存 -->
<class-cache usage="read-only" class="cn.hib.domain.Person" />
<!-- 配置哪一个类进行二级缓存 -->
<class-cache usage="read-only" class="cn.hib.domain.Person"/>
测试:
打开两个Session
@Test
public void test() {
Session s = HibernateUitls.openSession();
Person p = s.get(Person.class, "S001");
s.close();
Session s2 = HibernateUitls.openSession();
Person p2 = s2.get(Person.class, "S001");
s2.close();
7:统计二级缓存的命中次数
<!-- 打开统计信息 -->
<property name="generate_statistics">true</property>
public class Demo01 {
@Test
public void test() {
Session s = HibernateUitls.openSession();
Person p = s.get(Person.class, "S001");//hit=0 miss=1 put=1
s.clear();
Person pp = s.get(Person.class, "S001");//hit=1,miss=1,put=1
s.close();
//删除二级缓存中的数据
HibernateUitls.getSessionFactory().getCache().evictAllRegions();
Session s2 = HibernateUitls.openSession();
Person p2 = s2.get(Person.class, "S001");//hit=1,miss=2,put=2
s2.close();
SessionFactory sf =
HibernateUitls.getSessionFactory();
Statistics stat = sf.getStatistics();
System.err.println("命中数次:"+stat.getSecondLevelCacheHitCount());
System.err.println("没有命中:"+stat.getSecondLevelCacheMissCount());
System.err.println("放过几次:"+stat.getSecondLevelCachePutCount());
}
}