A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 丶笑笑 初级黑马   /  2018-6-27 16:17  /  601 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 小石姐姐 于 2018-6-29 10:50 编辑

【石家庄校区】Hibernate总结

概念:
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用`对象编程思维来操纵数据库`。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用。
ORM:
对象关系映射(英语:Object RelationMapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
对象-关系映射,是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
ORM模型的简单性简化了数据库查询过程。使用ORM查询工具,用户可以访问期望数据,而不必理解数据库的底层结构。

Hibernate基本配置:导包+前提:
导包:
    1.导入lib/required下所有的jar
    2.导入数据库的驱动jar包
    3.日志相关jar包:
       log4j-1.2.16.jar
       slf4j-api-1.6.1.jar
       slf4j-log4j12-1.7.2.jar
    4.拷贝hibernate-release-5.0.7.Final\lib\optional\c3p0下所有jar包
      
       c3p0-0.9.2.1.jar
       hibernate-c3p0-5.0.7.Final.jar
       mchange-commons-java-0.2.3.4.jar
      
    5.将hibernate-release-5.0.7.Final目录下project/etc/log4j.properties文件拷贝到工程src目录下
前提:
    数据库表
    实体类
   
核心jar包:hibernate-core-5.0.7.Final.jar
配置映射文件:
映射配置文件主要是用于描述<实体类与数据表>之间的映射关系
    1.位置:配置文件和实体类在同一包下
    2.名称:类名.hbm.xml
    3.约束:hibernate核心jar包下的org.hibernate包下hibernate-mapping-3.0.dtd文件中查找
    4.标签:
       <hibernate-mapping>(mapping:映射)
           <class>
              <id></id>
              <property></property>
           </class>
       </hibernate-mapping>
      
<!-- package属性代表javabean所在的包-->
<hibernate-mapping>
    <!--
            name    实体类的全名
            table   表的名称
            catalog 数据库名称
      -->
    <class name="com.b3a4a.domain.Customer" table="t_customer" catalog="db_hibernate_study">
        <!--
                id它是用于描述主键
                name      实体类中哪个属性对应的是主键
                column    数据库表中哪一列是主键
                -->
        <id name="id" column="id">
            <!--主键生成策略 -->
            <generator class="native"></generator>
        </id>
        <!--
使用property来描述属性与字段的对应关系
                name   实体类中的属性
                column 实体类中属性对应数据库表中的列
                length 该列的长度限制
                -->
        <property name="name" column="name" length="20" type="string"></property>
        <property name="address" column="address" length="50"></property>
        <property name="sex" column="sex" length="20"></property>
    </class>
</hibernate-mapping>
配置核心文件:
2.配置核心配置文件
它主要是hibernate框架所使用的,它主要包含了连接数据库相关信息,hibernate相关配置等。
    1.位置+名称:在src下创建一个hibernate.cfg.xml
    2.约束:约束文件所在位置:hiberante核心jar包下的org.hibernate包下hibernate-configuration-3.0.dtd文件
    3.在这个文件中如何配置:
       可以参考hibernate-release-5.0.7.Final\project\etc\hibernate.properties文件
<hibernate-configuration>

    <session-factory>
        <!-- 配置关于数据库连接的四个项 driverClass url username password -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql:///HibernateTest</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">123</property>

        <!--设置连接提供者 -->
        <property name="hibernate.connection.provider_class">
          org.hibernate.connection.C3P0ConnectionProvider
        </property>
        <!-- c3p0连接池的配置 -->
        <property name="hibernate.c3p0.max_size">20</property> <!--最大连接数 -->
        <property name="hibernate.c3p0.min_size">5</property> <!--最小连接数 -->
        <property name="hibernate.c3p0.timeout">120</property> <!--超时 -->
        <property name="hibernate.c3p0.idle_test_period">3000</property> <!--空闲连接 -->

        <!-- 可以将向数据库发送的sql显示出来 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 格式化sql -->
        <property name="hibernate.format_sql">true</property>

        <!-- hibernate的方言 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 自动创建表 -->
        <property name="hibernate.hbm2ddl.auto">update</property>

        <!-- 用于设置事务提交方式 -->
        <property name="hibernate.connection.autocommit">false</property>

        <!-- 设置seesion和线程绑定 需要配合SessionFactory的getCurrentSession()使用 -->
        <property name="hibernate.current_session_context_class">thread</property>

        <!-- 配置hibernate的映射文件所在位置-->
        <mapping resource="com/b3a4a/domain/Customer.hbm.xml" />
    </session-factory>

</hibernate-configuration>  
基本入门操作:
@Test
    public void modifyCustomerTest() {
       // 创建一个Customer,提供数据
       Customer c = new Customer();
       c.setName("张三");
       c.setAddress("北京");
       c.setSex("男");

       // 使用hibernate的api来完成将customer信息保存到mysql中操作
       Configuration config = new Configuration().configure(); // 加载hibernate.cfg.xml
       SessionFactory sessionFactory = config.buildSessionFactory();
       Session session = sessionFactory.openSession(); // 相当于得到一个Connection
       // 开启事务
       Transaction transaction = session.beginTransaction();
      
       //--------------------------操作数据库-----------------------
       //-----------添加操作-------------
       //session.save(c);
       //--------------------------------
       //-----------查询操作-------------
       //查询一条数据
       //get/load
       //Customer c =session.load(Customer.class, 1);
       //查询多条数据
       //Query query =session.createQuery("from Customer"); // 这里的from Customer不是sql语句,是HQL,这里的Customer代表的Customer
       //List<Customer> list= query.list();
       //--------------------------------
       //-----------修改操作-------------
       //Customer c =session.get(Customer.class, 2);
       //c.setName("王五");
       //session.update(c);
       //--------------------------------
       //-----------删除操作-------------
       //Customer c =session.get(Customer.class, 1);
       //session.delete(c);
       //--------------------------------
       //-----------------------------------------------------------
      
       // 事务提交
        //和session.getTransaction().commit();区别?
       transaction.commit();
       session.close();
       sessionFactory.close();
    }
Hibernate配置详解:
1.核心配置文件 hibernate.cfg.xml
参考hibernate-release-5.0.7.Final\project\etc\hibernate.properties文件
##auto schema export

#hibernate.hbm2ddl.autocreate-drop  每次都会创建一个新的表,执行完成后删除。一般在测试中使用
#hibernate.hbm2ddl.autocreate      每次都会创建一个新的表,一般是在测试中使用
#hibernate.hbm2ddl.autoupdate      如果数据库中有表,不创建,没有表创建,如果映射不匹配,会自动更新表结构(只能添加)
#hibernate.hbm2ddl.autovalidate    只会使用存在的表,并且会对映射关系进行校验.
2.映射配置文件:类名.hbm.xml
    2.关于<class>标签配置
    name属性:类的全名称
    table 表的名称,可以省略,这时表的名称就与类名一致
    catalog属性:数据库名称 可以省略.如果省略,参考核心配置文件中url路径中的库名称
       3.  关于<id>标签
       首先它必须存在,且位于第一个。<id>是用于建立类中的属性与表中的主键映射。
       name 类中的属性名称
       column 表中的主键名称  column它也可以省略,这时列名就与类中属性名称一致
       length 字段长度
       type属性 指定类型

       <generator>它主要是描述主键生成策略.
      
       4.  关于<property>标签
       它是描述类中属性与表中非主键的映射关系

       关于hibernate的映射文件中类型问题
       对于type属性它的取值,可以有三种(配置时使用Hibernate中的数据类型):
       1.  java中的数据类型
       2.  hibernate中的数据类型
       3.  SQL的数据类型
       数据类型:看图
核心API介绍:1.Configuration
Configuration config=new Configuration().config(); 主要加载src下的hibernate.cfg.xml(看源码)

Configuration config=new Configuration();主要加载的src下的hibernate.properties

可以手动加载映射配置文件

2.SessionFactory
SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。
需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
* 问题:怎样可以保证在一个项目中所使用的SessionFactory是同一个哪?
public class HibernateUtils{

    //一个项目加载一次此class,静态属性跟随class加载而加载,因此sessionFactory在一个项目中为同一个

    private static Configuration config;

    private static SessionFactorysessionFactory;

    static{
        config = new Configuration().config();
        sessionFactory=config.buildSessionFactory;
    }

    public static openSession(){
        return sessionFactory.openSession();
    }
}
* 通过SessionFactory可以获得session
1.SessionFactory.openSession();
    线程不安全
2.SessionFactory.getCurrentSession();
    获取一个与线程绑定的Session.线程安全
    还需要在hibernate.cfg.xml中配置   
* SessionFactory内部还维护了一个连接池,如果我们要想使用c3p0连接池,应该怎样处理?
1.  我们要导入c3p0的相关jar包
    在hibernate/lib/options下有关于c3p0连接池jar包
2.  在hibernate.cfg.xml文件中配置c3p0连接
    可以查看etc/hibernate.properties中关于c3p0的配置
3.  配置完成后需要配置连接提供者,配置了以后hibernate才知道使用什么连接池
3.session
    Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)。但需要注意的是Session对象是非线程安全的。
    问题:我们如何解决session的安全问题?
       我们只需要在方法内部来使用Session就可以。
问题:Session如何获取到?
SessionFactory.openSession()   ;  相当于直接通过SessionFactory创建一个新的Session,使用完成后要手动调用close来关闭。
SessionFactory.getCurrentSession();获取一个与线程绑定的Session,当我们提交或事务回滚后会自动关闭。

Session常用的方法:
    save  保存对象
    update 修改操作(主要用于游离态)
    delete删除
    get/load 根据id进行查询
    savenOrUpdate 执行save或update操作
    createQuery()获取一个Query对象
    CreateSQLQUery()获取一个可以操作sql的SQLQuery对象
    createCriteria() 获取一个Criteria它可以完成条件查询
4.Transaction
Session.beginTransaction();
    Transaction接口主要用于管理事务,它是hibernate的`事务接口`,对底层的事务进行了封装。使用它可以进行事务操作。
    commit 事务提交
    rollback 事务回滚
   
session.getTransaction()只是根据session获得一个Transaction实例,但是并没有启动它
session.beginTransaction()在获得一个Transaction后调用其begin()方法

5.Query*
Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。

通过Query主要完成查询操作.
我们通过Query可以执行hql语句.
    Query query=Session.createQuery(hql);
    //hql语句面向对象:即JavaBean实体类
下面这个可以执行sql语句
    SQLQUery sqlQuery=Session.createSQLQuery(sql);
SQLQuery是Query的子.
hql:
模板:
    Session session = HibernateUtils.openSession();
    Transaction transaction = session.beginTransaction();
    ...
    session.getTransaction().commit();
    session.close();
查询所有:
    hql="from Customer";
分页查询:
    query.setFirstResult(0);//开始位置
    query.setMaxResults(3);//查询条数
查询指定列:
    Select name ,address from Customer;
    得到的是List<Object[]>结果,Object[]中:非常不方便,需要返回结果唯一(返回javabean集合)
    要想得到List<Customer>结果
    1.  在Customer类中生成以name,address为参数的构造,注意,无参数构造也要有。
    2.  Selectnew Customer(name,address) fromCustomer;(通过反射操作构造方法)

条件查询:
    from Customer where name = ?
    from Customer where name =:myname (不能有空格)
   
    query.setParameter(0, "妮娜0");
    query.setParameter("myname", "妮娜2");
    //百分百确定结果只有一条记录可以使用uniqueResult();
    Customer c = (Customer) query.uniqueResult();
sql:
要想执行本地sql
    SQLQuerysqlQuery=session.createSqlQuery(String sql);
       sql为SQL语法
    使用sqlQuery.addEntity()结果封装到指定的对象中,如果不封装,得到的是List<Object[]>
       sqlQuery.addEntity(Customer.class);
    如果sql中有参数,我们使用sqlQuery.setParameter()完成参数传递。
    如果结果就是一个可以使用uniqueResult()来得到一个单独对象。

6.Criteria
    Criteria接口与Query接口非常类似,允许创建并执行面向对象的标准化查询。值得注意的是Criteria接口也是轻量级的,它不能在Session之外使用。
首先我想使用Criteria,必须得到Criteria
Criteriacriteria=Session.createCriteria()

语法:使用时百度即可


注解:注解作用:
在hibernate中我们使用注解,可以帮助我们简化hbm文件配置。
注解加在哪?
映射文件是为了映射表和实体类的关系,因此注解需要加在实体类中
注解根据功能不同,加在不同位置:类,属性
    对于我们以上讲解的关于属性配置的注解,我们也可以在其对应的getXxx方法去使用
注解使用什么包(有例外):
javax.persistence
位于hibernate-jpa-2.1-api-1.0.0.Final.jar
基本注解配置:类:
@Entity 声明一个实体
@Table来描述类与表对应:
    @Table(name="表名",catalog="数据库名")
属性:
@Id来声明一个主键
@GenerateValue 用它来声明一个主键生成策略
       @GeneratedValue(strategy( 战略,策略)= GenerationType.IDENTITY)
默认情况下相当于native
可以选择的主键生成策略IDENTITY SEQUENCEUUID(额外需要记住怎么配置)
    UUID配置(hibernate扩展):
       //需要引入包org.hibernate.annotations.GenericGenerator
       @GenericGenerator(name = "myuuid", strategy = "uuid")
       @GeneratedValue(generator(生产者) = "myuuid")
           

@Column来定义列
    @Column(name="列名")
    字符串还需要指定长度,列的其他属性也可以设置,如:nullable = true
    注意:对于PO类中所有属性,如果你不写注解,默认情况下也会在表中生成对应的列。列的名称就是属性的名称
        如果类中的属性是order这类,在数据库是关键字,这种情况必须设置此注解

@Temporal来声明日期类型(属性)
可以选择
    TemporalType.DATA   只有年月日  
    TemporalType.TIME   只有小时分钟秒
    TemporalType.TIMESTAMP 有年月日小时分钟秒

@Transient:设定类的属性不在表中映射
我们最终需要在hibernate.cfg.xml文件中将我们类中的注解配置引用生效(引入类)
级联注解配置:一对多注解开发:
@OneToMany(targetEntity=类名.class,mappedBy="多的一方持有本方的对象",orphanRemoval="true")
@Cascade(CascadeType.ALL)
   
    @OneToMany:加在Set<Order>上
       mappedBy="customer":由order维护外键,order中获得客户ID通过customer的getID()方法
       cascade:
       两种方式:
       一种是JPA:javax.persistence (包)
           cascade属性:
       一种是hibernate(对JPA进行了扩展):
           @cascade(CascadeType.SAVE_UPDATE)注解形式
           导入包:
            org.hibernate.annotations.Cascade;
            org.hibernate.annotations.CascadeType;
            
       注解中DELETE_ORPHAN过时:看源码,使用orphanRemoval="true"替代
      
      
    @ManyToOner:加在对象上
       @ManyToOne(targetEntity = 类名.class)
       @JoinColumn(name = "外键列名")//
       @Cascade(CascadeType.SAVE_UPDATE)//只能设置为SAVE_UPDATE
多对多(不能做删除操作!!!!!!!!)
哪方维护外键级联保存时保存哪一方
    一方:
    @ManyToMany(targetEntity=全类名.class,mappedBy="另一方持有本方的对象")  //代表放弃维护外键
    @Cascade(CascadeType.SAVE_UPDATE)//只能设置为SAVE_UPDATE
   
    另一方
    @ManyToMany(targetEntity=全类名.class)
    //维护外键的一方设置中间表
    @Jointable(name="生成中间表表名",joinColumns="本方在中间表的列名",inverseJoinColumns="对方在中间表的列名")
    @Cascade(CascadeType.SAVE_UPDATE)//只能设置为SAVE_UPDATE
      
       //student方维护外键
       s1.getTeachers().add(t1);
       s1.getTeachers().add(t2);
      
       s2.getTeachers().add(t2);
       s2.getTeachers().add(t1);
      
      
       session.save(s2);
       session.save(s1);
一对一(了解)检索方式:
分为五种:
    1.导航对象图检索方式,根据已加载的对象导航到其它对象
    2.OID检索方式,按照对象的OID来检索对象
    3.HQL检索方式,使用面向对象的HQL查询语言
    4.QBC检索方式,使用QBC(Query by Criteria)API来检索对象,这种API封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口
    5.本地SQL检索方式,使用本地数据库的SQL查询语句
导航对象图检索方式(常用于多表查询)
Customer c=session.get(Customer.class,2);
c.getOrders().size()
通过在hibernate中进行映射关系,在hibernate操作时,可以通过导航方式得到
其关联的持久化对象信息。

会导致N+1问题
OID检索方式
Session.get(Customer.class,3);
Session.load(Order.class,1);
Hibernate中通过get/load方法查询指定的对象,要通过OID来查询。
HQL
HQL是我们在hibernate中是常用的一种检索方式。
HQL(Hibernate Query Language)提供更加丰富灵活、更为强大的查询能力,因此Hibernate将HQL查询方式立为官方推荐的标准查询方式.
HQL查询在涵盖Criteria查询的所有功能的前提下,提供了类似标准SQL语句的查询方式,同时也提供了更加面向对象的封装。
完整的HQL语句形式如下:
    Select/update/delete…… from …… where ……group by …… having …… order by …… asc/desc
    其中的update/delete为Hibernate3中所新添加的功能,可见HQL查询非常类似于标准SQL查询。
基本步骤:
1.  得到Session
2.  编写HQL语句
3.  通过session.createQuery(hql)创建一个Query对象
4.  为Query对象设置条件参数
5.  执行list查询所有,它反胃的是List集合  uniqueResut()返回一个查询结果。

重写toString()方法时需要将对象属性去掉

1)基本检索   from 类名
eg:
//关键字不区分大小写,类名区分
String hql = "from Customer";
Query query = session.createQuery(hql).list();

2)排序检索 from 类名 order by 属性 asc/desc
eg:
String hql = "from Orderorder by money desc"; // desc 降序 默认是asc 升序
List<Order> list =session.createQuery(hql).list();

3)条件检索  

方式一:from 类名 where 属性=? and 属性=?
eg:
String hql = "from Orderwhere money>? and name=?";
List<Order> list =session.createQuery(hql).setParameter(0,2000).setParameter(1,"张三").list();

//条件为外键时以对象作为条件
Customercustomer = session.load(Customer.class,1);
String hql = "from Orderwhere customer =?";
Query query = session.createQuery(hql);
query.setParameter(0,customer);

方式二:from 类名 where 属性 = :名称
注意:名称随意,要和后面setParameter中的key对应起来,`:名称 `之间不能有空格
eg:
String hql = "from Orderwhere money>:mmmoney and name=:nnname";
List<Order> list =session.createQuery(hql).setParameter("mmmoney",2000).setParameter("nnname","张三").list();

4)分页检索
query.setFirstResult(开始位置)和query.setMaxResults(多少条)
eg:
Query query = session.createQuery("fromOrder");
// 每页显示6条件 ,我们要得到第二页数据
query.setFirstResult((2 - 1) * 6); // 设定开始位置
query.setMaxResults(6); // 设置条数
List<Order> list =query.list();

5)分组统计检索

统计:  select 统计函数(属性) from 类名
eg:
// *符号只有在统计函数中才不会被识别为属性
String hql="selectcount(*) from Order";
Object count = session.createQuery(hql).uniqueResult();

sum()对属性有要求:必须为number类型

分组:  select 统计函数(属性) from 类名 group by 属性
eg:
String hql="selectcount(*) from Order group by mCostomer";
Object count = session.createQuery(hql).uniqueResult();

6)投影检索(将查询结果封装到po中)    select new 类名(属性1,属性2) from 类名

eg:
//必须在PO类中提供无参和对应参数的构造方法
String hql = "select newCustomer(id,name) from Customer";
List<Customer> cs= session.createQuery(hql).list();

7)命名检索(了解)

SQL多表操作:
看文档中ORACLE语句
外连接规范语法: 左外LEFT OUTER JOIN 右外RIGHT OUTER JOIN
OUTER可以省略
SELECT * FROM t_customer c LEFT JOIN t_order o ONc.id=o.c_customer_id;
HQL多表操作(了解):
多表(fetch和distinct一起使用(查询一的一方需要去重))
迫切内连接
迫切左外连接

查询结果被封装了,封装成from后面的对象!!!
Hibernate事务管理:1.事务介绍:
问题:什么是事务?
    事务就是逻辑上的一组操作,组成这组操作的各个单元要么全部成功,要么全都失败。
问题:事务四个特性?
    原子性:不可分割
    一致性:事务在执行前后,要保证数据的一致。
    隔离性:一个事务在执行的过程中,不应该受到其它事务的干扰。
    持久性:事务一旦结束,数据持久化到数据库。
问题:不考虑事务的**隔离性**,会产生什么问题?
    脏读:一个事务读取到另一个事务的未提交数据
    不可重复读:一个事务读取到另一个事务提交的数据(主要是指update),会导致两次读取的结果不一致(提交前后不一样)。
    虚读(幻读): 一个事务读取到另一个事务提交的数据(主要是指insert),会导致两次读取结果不一致(提交前后不一样)。   
问题:对于上述问题如何解决?
    我们可以通过设置隔离级别来解决.
    READ_UNCOMMITED 读取未提交,它引发所有的隔离问题(基本不用)   
    READ_COMMITTED  读已提交,阻止脏读,可能发生不可重复读与虚读.
    REPEATABLE_READ 重复读  阻止脏读,不可重复读 可能发生虚读
    SERIALIZABLE 串行化 解决所有问题 不允许两个事务,同时操作一个目标数据。(效率低下)(基本不用)

**一般使用默认级别,不修改
ORACLE  默认的是事务隔离级别 READ_COMMITTED
MYSQL 默认的事务隔离级别  REPEATABLE_READ
2.Hibernate中设置事务隔离级别:
**hibernate.connection.isolation (隔离)**
它可取的值有 1 2 4 8
1代表的事务隔离级别为READ UNCOMMITTED
2代表的事务隔离级别为READ COMMITTED
4.代表的事务隔离级别为 REPEATABLE READ
8代表的事务隔离级别为 SERIALIZABLE

**取值原因:任意组合不会重复

在hibernate.cfg.xml文件中配置
3.Hibernatesession管理
Hibernate提供了三种管理session的方式:
1. Session对象的生命周期与本地线程绑定(ThreadLocal)
       底层map key:sessionFactory value:session
2.Session对象的生命周期与JTA事务绑定(分布式事务管理)
3.Hibernate委托程序来管理Session的生命周期

我们之前所使用的是第三种 ,通过程序获取一个Session对象,使用它,最后session.close();
在实际开发中我们一般使用的是前两种

主要介绍关于本地线程绑定Session。(看截图)
步骤:
1.  需要在hibernate.cfg.xml文件配置
       <propertyname="hibernate.current_session_context_class">thread</property>
2.  在获取session时不要在使用openSession而是使用getCurrentSession()方法。

**使用getCurrentSession获取的与线程绑定的session对象,在事务关闭时,session对象也会close,简单说,就不需要我们在手动close;**
Hibernate优化方案1.HQL优化1.使用参数绑定
```
1.使用绑定参数的原因是让数据库一次解析SQL,对后续的重复请求可以使用用生成好的执行计划,这样做节省CPU时间和内存。
2.避免SQL注入
```
2.尽量少使用NOT
```
如果where子句中包含not关键字,那么执行时该字段的索引失效。  ```
3.尽量使用where来替换having
Having在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录的数目,能减少这方面的开销
4.减少对表的查询
在含有子查询的HQL中,尽量减少对表的查询,降低开销
5.使用表的别名
当在HQL语句中连接多个表时,使用别名,提高程序阅读性,并把别名前缀与每个列上,这样一来,可以减少解析时间并减少列歧义引起的语法错误。
6.实体的更新与删除
在hibernate3以后支持hql的update与delete操作
2.一级缓存优化
一级缓存也叫做session缓存,在一个hibernate session有效,这级缓存的可干预性不强,大多于hibernate自动管理,但它提供清除缓存的方法,这在大批量增加(更新)操作是有效果的,例如,同时增加十万条记录,按常规进行,很可能会出现异常,这时可能需要手动清除一级缓存,session.evict以及session.clear.
3.检索策略(抓取策略)延迟加载
延迟加载 是hibernate为提高程序执行的效率而提供的一种机制,即只有真正使用该对象的数据时才会创建。
可以减少缓存的压力
    load方法采用的策略延迟加载.
    get方法采用的策略立即加载。
检索策略分为两种:
1. 类级别检索 (针对load方法)
2. 关联级别检索(导航对象图查询)
检索总结:
类级别(延迟/立即加载)
@Proxy(lazy="false") 针对load方法
关联级别(1对多)
@LazyToOne(多的一方)
@LazyCollection(1的一方)
上面2个注解只是控制加载数据的时机

@Fetch(查询语句的方式   简单sql查询/连接查询/子查询)
上面这个注解决定加载数据的时候是使用哪种sql语句
@LazyToOne(false/proxy)
/*
    proxy:跟随主表(一的一方)类级别的策略
*/
@LazyCollection(true/false/extra)
/*
    true:立即加载
    false:用到时再加载,只要使用就会查询出所有信息
    extra:用到什么加载什么,eg:只查订单个数就不会查订单信息
*/


@Fetch(select/join/subselect)
/*
    select:简单查询(单表上的查询,格式为多条简单SQL语句)
    join:使用join时lazy注解会失效,全部为立即加载,格式为:迫切左外连接
    subselect:子查询
*/

记住各个属性,能够自己说出组合的意思
eg:
一的一方
Customerc = session.get(Customer.class,1);
list =c.getOrders();
通过客户查询该客户的所有订单的时候,延迟加载,并且加载的时候是使用的简单sql查询
* 如何对一个延迟代理对象进行初始化?
为何要初始化return c1session.close()已经关闭,此时c1中没有数据,get方法也无法使用
通过load形式加载的延迟加载的对象如何进行初始化
1.对象.get方法()
2.hibernate.initilize(对象)
**3.openSessionInViewfilter (Spring框架)
a.类级别检索
类级别检索是通过session直接检索某一类对应的数据,例如
    Customer c=session.load(Customer.class,1)
    Session.createQuery(“from Order”)
类级别检索策略分为立即检索与延迟检索,`默认是延迟检索`,类级别的检索策略可以通过<class>元素的lazy属性来设置 ,默认值是true
如果将lazy设置为false,代表类级别检索也使用立即检索。这时load与get就一样,都是立即检索。

在hbm配置文件中设置 :
    lazy="true"
在类中使用注解:
    @Proxy(lazy=true)
b.关联级别检索
查询到某个对象,获得其关联的对象或属性,这种称为关联级别检索
eg:
c.getOrders().size()
c.getName()
对于关联级别检索我们就要研究其检索策略(抓取策略)(检索总结中的组合)
4.N+1问题
Customer c
Order o1
Order o2
Order o3
      
通过客户查询该客户的所有订单时(n+1)   @BatchSize =4
    客户    1条sql
    select * from customer where id =1;
    订单   3条sql
    select * from t_order where customer_id = 1 and oid =1;
    select * from t_order where customer_id = 1 and oid =2;
    select * from t_order where customer_id = 1 and oid =3;





0 个回复

您需要登录后才可以回帖 登录 | 加入黑马