Hibernate对象声明周期和DML
- java对象在Hibernate中的生命周期指的是java类和数据库的关联状态。
- 临时状态(新建状态)
新new出来的java类对象和对应的数据库表 数据上没有关联 - 持久化状态
java类对象和对应的数据库表 数据上完全一致(同步) - 托管状态
java类对象和对应的数据库表 数据上曾经一致,现在脱离
-
save 总是发送insert语句,主键存在会主键冲突,主键不存在插入成功,只能
从新建状态或持久化状态经过evict和clear编程托管状态开始。 -
merge 无论是新建状态还是evict后的托管状态,无论主键是否修改,因为总是
先执行了select去查询数据库中是否已存在,该主键,不存在insert,存在update。 -
update 无论修改了任何内容,只要和原值不一样,都会发送update语句。
-
为什么建表时有详情表和总量表:当数据量特别巨大,查询次数特别频繁,通过
group by 等语句计算出总量特别浪费资源,宁愿每次数据变化同步修改总量表,
而且反复查询一张表Hibernate可以开缓存(一级 二级)提高效率。
TestDML.java
Session session = HibernateSessionFactory.getSession();
Transaction tran = session.beginTransaction();
**********************************************************
//1.新增 使用save方法save只认新建状态和持久化状态,新建状态是insert,
持久化状态是update,托管状态由于会发送insert语句往往会主键冲突
//连续对同一对象两次save,第二次如果有非主键字段修改,第一次发送insert
语句,第二次发送update语句。第二次修改主键字段会报错。
Teacher teacher = new Teacher("0011","zhangsan","London");//新建状态
teacher.setTno("0012");
session.save(teacher);//持久化状态
**********************************************************
//2.修改 通过get得到对象,该对象为持久化状态,但是如果clear evict对象
变为托管状态,托管状态对象执行save发送insert语句往往因为主键冲突不成功。
//不清理clear 对象为持久化状态,无论使用update还是merge如果修改值和原值
一样都发送update语句,如果执行了clear,对象变为托管状态,虽然如果和原值
不同最后都会执行update语句merge会再次查询后才update,update不会。
Teacher teacher = session.get(Teacher.class,"0001");
teacher.setSex("女");
session.evict(teacher);
session.clear();
session.update(teacher);
session.merge(teacher);
//对于持久化状态的对象 修改主键后执行save和merge 都报错不准修改主键,
如果持久化状态的对象被evict之后,修改了主键使用save无论修改的主键是否
存在都发送insert;merge修改主键存在发送update,没有发送insert。
Teacher teacher = session.get(Teacher.class,"0001");
session.evict(teacher);
teacher.setTno("0001");
session.save(teacher);
session.merge(teacher);
//新建状态的对象 如果有主键已存在 执行save报错重复的主键和merge
********************************************************
//3.删除(持久化状态情况下)
Teacher teacher = session.get(Teacher.class,"0002");
session.delete(teacher);
tran.commit();
HibernateSessionFactory.closeSession();
缓存
- 如果开启了查询缓存,不清理session情况下,在两个事务中第二次查询同一
数据不发送sql,清理缓存(session.clear()) 后则会发送sql。 - 如果开启了二级缓存,无论清不清理session,两次查询都只发送一次sql
配置hibernate二级缓存:ehcache-core.jar包中找到ehcache-....xml
文件复制到src目录下(其中改动path和maxElementsInMemory="10"<-修改数据
大小是查询出的数据最多多少条放内存中缓存,多出的放在指定缓存文件夹)。
由于二级缓存存放多条数据,需要使用list,iterator这样的集合查询
,才会使用二级缓存并且在执行代码需要query.setCacheable(true)
; - Iterator执行查询是N+1方式,数据库中有n条记录,先1条查询出主键集合,
再依次按照需要具体访问的值得主键进行查询。
TestCache.java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import gxa.dao.HibernateSessionFactory;
import gxa.entity.Student;
public class TestCache {
public static void main(String[] args) {
// 实验一 在两个事务分别进行两次 同一学生的查询,如果清理session 两次 两条,不清理两次一条
// 实验二 如果开启了二级缓存,配置二级缓存的设置和工厂类的设置
Session session = HibernateSessionFactory.getSession();
// Transaction tran1 = session.beginTransaction();
// Student student1 = session.load(Student.class, "09010101");
//
// System.out.println(student1.getName());
// session.clear();// 在 关闭二级缓存后生效
// tran1.commit();
//
// Session session2 = HibernateSessionFactory.getSession();
// Transaction tran2 = session2.beginTransaction();
// Student student2 = session2.load(Student.class, "09010101");
// System.out.println(student2.getName());
// //session2.clear();
// tran2.commit();
// 实验三 ,两次查询多条记录,开启二级缓存设置使用缓存为true 两次查询发送1条,否则都是发两条
// Transaction tran1 = session.beginTransaction();
// Query query = session.createQuery("From Student");
// //query.setCacheable(true);
// List<Student> Students1 = query.list();
// for (Student Student1 : Students1) {
// System.out.println(Student1.getName());
// }
//
// tran1.commit();
//
// Transaction tran2 = session.beginTransaction();
// Query query2 = session.createQuery("From Student");
// //query.setCacheable(true);
// List<Student> Students2 = query.list();
// for (Student Student2 : Students2) {
// System.out.println(Student2.getName());
// }
// 实验四 iterator 执行查询是 n+1 方式,数据库中有n条记录,先1条查询查处主键集合,再依次按照需要具体访问的值的主键进行查询,
//所有n条记录的主键,对应n条查询
Transaction tran4 = session.beginTransaction();
Query query4 = session.createQuery("From Student");
query4.setCacheable(true);
Iterator<Student> students = query4.iterate();
while(students.hasNext()){
Student student = students.next();
System.out.println(student.getName());
}
tran4.commit();
Transaction tran5 = session.beginTransaction();
Query query5 = session.createQuery("From Student");
query4.setCacheable(true);
Iterator<Student> students5 = query5.iterate();
while(students5.hasNext()){
Student student = students5.next();
System.out.println(student.getName());
}
tran5.commit();
session.close();
System.exit(0);
}
}
Student.java
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
public class Student implements java.io.Serializable {
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="d:/ehcache"/>
<defaultCache
maxElementsInMemory="13"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
hibernate.cfg.xml
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<property name="show_sql">true</property>
<mapping class="gxa.entity.Student"/>
<mapping class="gxa.entity.Studentreg"/>
<class-cache usage="read-only" class="gxa.entity.Student"/>
集合
- Set 无序集合,不认重复值
- List 有序集合,知道初始大小
- Iterator 有序的链式集合,不知道初始大小
网友评论