2018-09-28:HibernateDML操作与缓存

Hibernate对象声明周期和DML

  • java对象在Hibernate中的生命周期指的是java类和数据库的关联状态。
  1. 临时状态(新建状态)
    新new出来的java类对象和对应的数据库表 数据上没有关联
  2. 持久化状态
    java类对象和对应的数据库表 数据上完全一致(同步)
  3. 托管状态
    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();


缓存

  1. 如果开启了查询缓存,不清理session情况下,在两个事务中第二次查询同一
    数据不发送sql,清理缓存(session.clear()) 后则会发送sql。
  2. 如果开启了二级缓存,无论清不清理session,两次查询都只发送一次sql
    配置hibernate二级缓存:ehcache-core.jar包中找到ehcache-....xml
    文件复制到src目录下(其中改动path和maxElementsInMemory="10"<-修改数据
    大小是查询出的数据最多多少条放内存中缓存,多出的放在指定缓存文件夹)。
    由于二级缓存存放多条数据,需要使用list,iterator这样的集合查询
    ,才会使用二级缓存并且在执行代码需要 query.setCacheable(true)
  3. 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 有序的链式集合,不知道初始大小
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容