Jimoshi_Hibernate 框架学习(四)--事务隔离级别、Hibernate执行SQL、HQL语句、连接池、Hibernate二级缓存

来源:互联网 发布:无线点菜系统源码 编辑:程序博客网 时间:2024/06/06 10:55
Jimoshi成长经历:前面的笔记后面再慢慢整理-------方便自己

目录:事务隔离级别、Hibernate执行SQL语句、Hibernate执行HQL语句、连接池、Hibernate二级缓存

Hibernate 框架学习(四):

一、事务隔离级别
 
  1、数据库事务的定义(作为单个逻辑工作单元执行的一系列操作)

     描述:一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。

      原子性(atomic),事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行

    一致性(consistent),事务在完成时,必须使所有的数据都保持一致状态。

    隔离性(insulation),由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。

    持久性(Duration),事务完成之后,它对于系统的影响是永久性的。

  2、数据库事务并发可能带来的问题(第一类丢失更新、脏读、虚读、不可重复读、第二类丢失更新)

     第一类丢失更新(lost update):在完全未隔离事务的情况下,两个事物更新同一条数据资源,某一事物异常终止,回滚造成第一个完成的更新也同时丢失。
     脏读(dirty read):如果第二个事务查询到第一个事务还未提交的更新数据,形成脏读。
     虚读(phantom read):一个事务执行两次查询,第二次结果集包含第一次中没有或者某些行已被删除,造成二次结果不一致,只是另一个事务在这两次查询中间插入或者删除了数据造成的。
     不可重复读(unrepeated read):一个事务两次读取同一行数据,结果得到不同状态结果,如中间正好另一个事 务更新了该数据,两次结果相异,不可信任
     第二类丢失更新(second lost updates):是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都 进行写操作,并提交,第一个事务所做的改变就会丢失。

  3、数据库事务隔离级别(由数据库底层提供的隔离级别四种)

     3.1.Serializable 串行化
            Repeatable Read 可重复读
            Read Commited 可读已提交
            Read Uncommited 可读未提交

     3.2.在Hibernate的配置文件中可以显示的配置数据库事务隔离级别。每一个隔离级别用一个整数表示:
            8 - Serializable 串行化
            4 - Repeatable Read 可重复读
            2 - Read Commited 可读已提交
            1 - Read Uncommited 可读未提交
     在hibernate.cfg.xml中使用hibernate.connection.isolation参数配置数据库事务隔离级别。

     代码示例:

     <!-- 配置数据底层事务隔离级别 -->
     <property name="hibernate.connection.isolation">4</property>

   注:从低到高,随着隔离型级别增高,并发性能就越低(操作同一个数据,等待时间有可能就比较久)

  4、Hibernate 映射类型

  代码示例:
   
  @Column(name="s_name",length=20)
    @Type(type = "string")
    public String getName() {
        return name;
    }
注:注解一般来说可以不用去设置Type类型,具体根据你声明对象属性的时候自动帮你映射到数据库生成对应类型
  (集合映射和继承映射了解,推荐网址)
   http://blog.csdn.net/zhang_xinxiu/article/details/27485119
   http://blog.csdn.net/wangli325/article/details/7063573  
   http://shyf12054213.iteye.com/blog/1629891

  5、检索策略( 查询的策略)

  一对多的情况,在一的一方设置lazy 属性(load方法是支持延迟加载的,get方法是不支持延迟加载的)
 
  单向代码示例:
            @OneToMany(fetch=FetchType.LAZY)
        @Fetch(FetchMode.JOIN)
        @JoinColumn(name = "tid")
        public Set<Student> getStudents() {
            return students;
        }
        public void setStudents(Set<Student> students) {
            this.students = students;
        }

  测试:
 
    @Test
    public   void  testLazyFalse(){
        Teacher  t = (Teacher) session.get(Teacher.class, Integer.valueOf(1));
        Set<Student> ss  =  t.getStudents();
        System.out.println(ss.size());
    }
    @Test
    public   void  testLazyTrue(){
        Teacher  t = (Teacher) session.load(Teacher.class, Integer.valueOf(1));
        System.out.println(t.getTname());
        
    }
    

   batch-size(批量处理)
   测试:
    @Test
    public   void  testBathSize(){
        Teacher  t = (Teacher) session.load(Teacher.class, Integer.valueOf(1));
        Set<Student> s =t.getStudents();
        System.out.println(s.size());
        
    }

  属性:Fetch
  默认的采取select所谓的内连接通过ID来进行一个连接查询

二、Hibernate执行SQL语句

  1、 //执行SQL查询语句,查询结果需要添加到对应的实体中addEntity
    @Test
    public  void  testSQL(){
        String sql =  "select * from t_student";
        Query  query  =  session.createSQLQuery(sql).addEntity(Student.class);
        List<Student>  ss = query.list();
        for (Student student : ss) {
            System.out.println(student.getName());
        }
    }

  2、 //占位符的使用
    @Test
    public  void  testSQL1(){
        String sql =  "select * from t_student limit :start,:scount";
        Query  query  =  session.createSQLQuery(sql).addEntity(Student.class);
        query.setInteger("start", 0);
        query.setInteger("scount", 2);
        List<Student>  ss = query.list();
        for (Student student : ss) {
            System.out.println(student.getName());
        }
    }

  3、 //sql增删改
    @Test
    public  void  testSQL2(){
        String sql =  "insert into t_student (name) values (:stuname)";
        Query  query =  session.createSQLQuery(sql);
        query.setString("stuname", "wwj");
        int i  = query.executeUpdate();
        
    }

  4、//查询转为自定义的实体,注意:自定的实体类属性名需要跟数据库中查出的数据列名保持一致
    @Test
    public  void  testSQL3(){
        String sql =  "select t.tname,s.name sname from t_teacher  t,t_student s where          t.tid=s.teacher_tid";
        Query  query =  session.createSQLQuery(sql);
        List<TSMsg>  ss = query.setResultTransformer(Transformers.aliasToBean(TSMsg.class)).list();
        System.out.println(ss.size());
        for (TSMsg tsMsg : ss) {
            System.out.println(tsMsg.getTname());
        }
        
    }
    
三、Hibernate执行HQL语句(类名当成表名,属性名当成字段名)

  1、//HQL 执行查询
    @Test
    public  void testHQL(){
        String hql = "from Teacher";
        Query query = session.createQuery(hql);
        List<Teacher> ts =  query.list();
        Teacher  t =  ts.get(0);
        System.out.println(t.getTname());
        List<Student>  ss =  t.getStudents();
        System.out.println(ss.get(0).getName());
        }

  2、 //HQL获取单独的字段,占位符
    @Test
    public  void testHQL1(){
        String hql = "select t.tname from Teacher t where t.tid=:tid";
        Query query = session.createQuery(hql);
        query.setInteger("tid", 1);
        List<Object> ts =  query.list();
        System.out.println(ts.get(0));
        }

  3、//HQL 通过老师的id 来获取 学生

    @Test
    public  void testHQL2(){
        String hql = "select t.students from Teacher t where t.tid=:tid";
        Query query = session.createQuery(hql);
        query.setInteger("tid", 1);
        List<Student> ts =  query.list();
        for (Student student : ts) {
            System.out.println(student.getName());
        }
        }

  4、//HQL 分页 使用hibernate 提供的方法

    @Test
    public  void testHQL3(){
        String hql = "select t.students from Teacher t where t.tid=:tid";
        Query query = session.createQuery(hql);
        query.setInteger("tid", 1);
        query.setFirstResult(0);// 起始位置
        query.setMaxResults(2);//记录数
        List<Student> ts =  query.list();
        for (Student student : ts) {
            System.out.println(student.getName());
        }
        }

  5、//删除当前老师下面的所有学生

    @Test
    public  void testHQL4(){
        Teacher t = (Teacher) session.get(Teacher.class, Integer.valueOf(1));
        List<Student>  ss = t.getStudents();
        for (Student student : ss) {
            session.delete(student);
        }

  6、  //更改老师名字
        @Test
        public  void testHQL6(){
            Teacher t = (Teacher) session.load(Teacher.class, Integer.valueOf(1));
            t.setTname("xxxxxx");
         }

四、连接池

  1、概念:在访问数据库时候,是在不断打开连接,并且关闭连接,但是如果项目中访问量特别大,那么这种不断  的打开连接关闭连接,对内存的消耗就特别大。项目中执行数据的效率就特别低。提出使用连接池,也就是把很多连接放在池子里面,需要用到的时候,就直接从池子拿一个连接使用。能够提高我们程序的运行效率。

  2、连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全  的复用,避免了数据库连接频繁建立、关闭的开销。

  3、使用C3P0的连接池(Hibernate自带也有连接池)
    
    3.1.添加连接池jar包

    代码示例:
     
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-c3p0</artifactId>
      <version>4.3.5.Final</version>
    </dependency>

    3.2.配置 hibernate.cfg.xml

    代码示例:
    
     <!-- 最小的连接数 -->
      <property name="c3p0.min_size">7</property>
     <!-- 最大连接数 -->   
      <property name="c3p0.max_size">42</property>
     <!-- 获得连接的超时时间,如果超过这个时间,会抛出异常,单位毫秒 -->  
      <property name="c3p0.timeout">1800</property>
     <!-- 最大的PreparedStatement的数量 -->   
      <property name="c3p0.max_statements">50</property>

  4、日志管理(log4j)

   4.1.添加jar包
   
   代码示例:

   <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
   </dependency>

   4.2.添加属性配置文件(log4j.properties)

   代码示例:

   log4j.rootLogger=INFO,appender1,appender2
   log4j.appender.appender1=org.apache.log4j.ConsoleAppender
   log4j.appender.appender2=org.apache.log4j.FileAppender
   log4j.appender.appender2.File=C:/Users/Administrator/Desktop/log.txt
   log4j.appender.appender1.layout=org.apache.log4j.TTCCLayout
   log4j.appender.appender2.layout=org.apache.log4j.HTMLLayout
 
   
  5、Hibernate二级缓存
   
   5.1.缓存的概念: 缓存是介于物理数据源与应用程序之间,
是对数据库中的数据复制一份临时放在内存或者硬盘中 的容器,
其作用是为了减少应用程序对物理数据源访问的次数,
从而提高了应用程序的运行性能。
Hibernate 在进行读取数据的时候,根据缓存机制在相应的缓存中查询,
如果在缓存中找到了需要的数据
则就直接把命中的数据作为结果加以利用,避免了大量发送SQL语句到数据库查询的性能损耗
 
   5.2.Hibernate 缓存的分类:

    5.2.1.Session 缓存(又称作事务缓存):Hibernate 内置的,不能卸除。
缓存范围:缓存只能被当前 Session 对象访问。缓存的生命周期依赖于 Session 的生命周期,
当 Session 被关闭 后,缓存也就结束生命周期。


    5.2.2.SessionFactory 缓存(又称作应用缓存):使用第三方插件。
缓存范围:缓存被应用范围内的所有 session 共享,不同的 Session 可以共享。
这些 session 有可能是并发访问缓 存,因此必须对缓存进行更新。
缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命 周期,
二级缓存存在于应用程序范围。

   5.3.二级缓存策略提供商:
提供了 HashTable 缓存,EHCache,OSCache,SwarmCache,jBoss Cathe2,这些缓存机制,
其中 EHCache, OSCache 是不能用于集群环境(Cluster Safe)的,
而 SwarmCache,jBoss Cathe2 是可以的。
   HashTable 缓存主 要是用来测试的,
只能把对象放在内存中,EHCache,OSCache 可以把对象放在内存(memory)中,
也可以 把对象放在硬盘(disk)上。使用 EHCache  hibernate 推荐的方式
 
   5.4.什么数据适合放二级缓存中:


     5.4.1.经常被访问
     5.4.2.改动不大
     5.4.3.数量有限
     5.4.4.不是很重要的数据,允许出现偶尔并发的数据

1 0
原创粉丝点击