Hibernate框架

1.什么是hibernate框架

Hibernate 是一个面象对象的ORM持久层框架
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的ORM框架。Hibernate可自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

2.hibernate的优缺点?

1.Hibernate优点:

  (1)对象/关系数据库映射(Basic O/R Mapping)

  它使用时只需要操纵对象,使开发更对象化,抛弃了数据库中心的思想,完全的面向对象思想。

  (2)透明持久化(Persistent)

  带有持久化状态的、具有业务功能的单线程对象,此对象生存期很短。这些对象可能是普通的JavaBeans/POJO,这个对象没有实现第三方框架或者接口,唯一特殊的是他们正与(仅仅一个)Session相关联。一旦这个Session被关闭,这些对象就会脱离持久化状态,这样就可被应用程序的任何层自由使用。(例如,用作跟表示层打交道的数据传输对象。)

  (3)事务Transaction (org.Hibernate.Transaction)

  应用程序用来指定原子操作单元范围的对象,它是单线程的,生命周期很短。它通过抽象将应用从底层具体的JDBC、JTA以及CORBA事务隔离开。某些情况下,一个Session之内可能包含多个Transaction对象。尽管是否使用该对象是可选的,但无论是使用底层的API还是使用Transaction对象,事务边界的开启与关闭是必不可少的。

  (4)它没有侵入性,即所谓的轻量级框架。

  (5)移植性会很好。

  (6)缓存机制。提供一级缓存和二级缓存。

  (7)简洁的HQL编程。

  2.Hibernate缺点:

  (1)Hibernate在批量数据处理的时候是有弱势。

  (2)针对某一对象(单个对象)简单的查\改\删\增,不是批量修改、删除,适合用Hibernate;而对于批量修改、删除,不适合用Hibernate,这也是OR框架的弱点;要使用数据库的特定优化机制的时候,不适合用Hibernate。

3.jdbc与Hibernate的区别

JDBC与Hibernate在性能上相比,JDBC灵活性有优势。而Hibernate在易学性,易用性上有些优势。当用到很多复杂的多表联查和复杂的数据库操作时,JDBC有优势。

相同点:

◆两者都是JAVA的数据库操作中间件。

◆两者对于数据库进行直接操作的对象都不是线程安全的,都需要及时关闭。

◆两者都可以对数据库的更新操作进行显式的事务处理。

不同点:

◆使用的SQL语言不同:JDBC使用的是基于关系型数据库的标准SQL语言,Hibernate使用的是HQL(Hibernate query language)语言

◆操作的对象不同:JDBC操作的是数据,将数据通过SQL语句直接传送到数据库中执行,Hibernate操作的是持久化对象,由底层持久化对象的数据更新到数据库中。

◆数据状态不同:JDBC操作的数据是“瞬时”的,变量的值无法与数据库中的值保持一致,而Hibernate操作的数据是可持久的,即持久化对象的数据属性的值是可以跟数据库中的值保持一致的。

4. Hiberante工作原理

#  术语解释
+ 持久化:把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)
+ ORM:Object Relation Mapping就是对象到关系的映射,把对表的操作变成对持久化对象的操作


5.Hibernate创建过程

##1 pom.xml 导入hibernate依赖包

```xml
    <!-- Hibernate -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.1.0.Final</version>
    </dependency>
```


##2 核心配置文件hibernate.cfg.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/scm?useUnicode=true&amp;characterEncoding=utf-8</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">root123</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.show_sql">false</property>
    <property name="hibernate.format_sql">true</property>


    <mapping resource="com/mipo/domain/Employee.hbm.xml" />
  </session-factory>
</hibernate-configuration>
```

##3 映射文件*.hbm.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="com.mipo.domain.Employee" table="T_EMPLOYEE">
    <id name="empId" column="EMP_ID">
      <!--
      <generator class="native" />
      -->
      <generator class="identity" />
    </id>
    <property name="empName" column="EMP_NAME" />
    <property name="empSex" column="EMP_SEX" />
    <property name="empMemo" column="EMP_MEMO" />
  </class>
</hibernate-mapping>
```

##4 编写测试用例

+ 1) 获取SessionFactory
```java
public SessionFactory getSessionFactory() {
    final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
    try {
        return new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
    } catch (Exception e) {
        e.printStackTrace();
        StandardServiceRegistryBuilder.destroy(serviceRegistry);
    }
}
```

##5 编写测试dao

 public void testEvict() {
        Session session = sessionFactory.openSession();
        session.beginTransaction();


        Employee employee = (Employee) session.get(Employee.class, 1);
        Employee evictEmployee = new Employee();
        evictEmployee.setUid(1);
        session.evict(employee);// 手工清除一级缓存


        // evictEmployee.setEmpId(Integer.valueOf(4));
        evictEmployee.setEmpName("刘备");
        evictEmployee.setEmpSex("M");
        evictEmployee.setEmpMemo("刘大耳朵。。。");
        session.update(evictEmployee);


        session.getTransaction().commit();
        session.close();
    }

##6 一对一的关系

一对一的加载方式默认为立即加载
<hibernate-mapping>
  <class name="com.mipo.domain.Employee" table="T_EMPLOYEE">
    <id name="uid" column="uid">
      <generator class="identity" />
    </id>
    <property name="empName" column="EMP_NAME" />
    <property name="empSex" column="EMP_SEX" />
    <property name="empMemo" column="EMP_MEMO" />


    <!-- 
         属性名     描述
         ##########################################
         name   com.mipo.domain.Employee#idCard
         lazy   指定加载策略,立即加载还是延迟加载
        class   指定name对应数据类型
      cascade   级联操作all、save-update、delete、none
     -->
    <one-to-one name="idCard" lazy="false" class="com.mipo.domain.IDCard" cascade="all" />
  </class>
</hibernate-mapping>

bean
public class Employee implements Serializable {


    private static final long serialVersionUID = -5864118345201555279L;
    private Integer uid;
    private String empName;
    private String empSex;
    private String empMemo;


    private IDCard idCard;

<hibernate-mapping>
  <class name="com.mipo.domain.IDCard" table="T_IDENTITY_CARD">
    <id name="uid" column="UID">
      <!-- 通过取对应表的主键 -->
      <generator class="foreign">
        <param name="property">employee</param>
      </generator>
    </id>
    <property name="num" column="NUM"/>


    <one-to-one name="employee" class="com.mipo.domain.Employee" cascade="none" />
  </class>
</hibernate-mapping>

bean

public class IDCard implements Serializable {


    private static final long serialVersionUID = -3343609137822895893L;
    private Integer uid;
    private String num;


    private Employee employee;

不同的关系,级联的属性也不相同

对关联的对象如何级联操作,取值:

"none" :做任何操作都不影响关联对象

"save-update" :级联保存或修改

"delete" :级联删除

"delete-orphan" :级联删除并从缓存中清除关联对象

"all" :级联保存、修改、删除。 


##7一对多和多对一的关系

hibernate.cfg.xml

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/scm?useUnicode=true&amp;characterEncoding=utf-8</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">root123</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL57InnoDBDialect</property>
    <property name="hibernate.show_sql">false</property>
    <property name="hibernate.format_sql">true</property>


    <mapping resource="com/mipo/domain/Employee.hbm.xml" />
    <mapping resource="com/mipo/domain/Department.hbm.xml" />
  </session-factory>
</hibernate-configuration>

Hiberante中对象的状态
 
临时状态:刚创建出来的对象,跟session是没有关系
持久状态:已经存在与数据库中。跟session有关系;
托管状态:曾经跟session有关系,后来跟session脱离关系


Lazy和fetch区别:
Lazy:false【立即检索】:获取一个对象之后,会立即再组装此对象所关联的对象
Lazy:true【延迟加载】:不立即组装和它关联的对象,一对多默认是这种加载策略
预抓取:和立即检索相比,预先抓取可以减少SQL语句的条数,提高查询速度。 


创建session工厂

public final class HibernateUtil {


    private static final SessionFactory sessionFactory = buildSessionFactory();


    private HibernateUtil() {
        // do nothing
    }


    private static SessionFactory buildSessionFactory() {
        final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
        try {
            return new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
        } catch (Exception e) {
            StandardServiceRegistryBuilder.destroy(serviceRegistry);


            throw new ExceptionInInitializerError(e);
        }
    }


    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }


}

department.hbm.xml

<hibernate-mapping>
  <class name="com.mipo.domain.Department" table="T_DEPARTMENT">
    <id name="uid" column="uid" type="integer">
      <generator class="identity" />
    </id>
    <property name="depName" column="DEP_NAME" type="string" />
    <property name="depAddress" column="DEP_ADDRESS" type="string" />


    <!--
         set节点: 指定一对多存放集合


        name属性: 指定com.mipo.domain.Department类中employees属性;
     cascade属性: 级联操作,操作主表时,是否同时操作从表;
     inverse属性: 反转,外键控制权交由对方维护;
        lazy属性: 延迟加载,通常用于加载多条数据;
    -->
    <set name="employees" lazy="true" cascade="save-update" inverse="true">
      <!-- 
      column属性:T_EMPLOYEE表关联的外键
      -->
      <key column="DEPT_ID" />
      <!--
      one-to-many节点:指定一对多


            class属性:指定Department类employees属性的数据类型;
      -->
      <one-to-many class="com.mipo.domain.Employee" />
    </set>


    <!--
    <list name="listData">
      <key column="DEP_ID" />
      <list-index column="EMP_ID" base="1" />
      <one-to-many class="com.mipo.domain.Employee" />
    </list>
    <map name="mapData">
      <key column="DEP_ID" />
      <index column="EMP_ID" type="integer" />
      <one-to-many class="com.mipo.domain.Employee" />
    </map>
    -->
  </class>
</hibernate-mapping>

Department
public class Department implements Serializable {


    private static final long serialVersionUID = -2222647138773687754L;
    private Integer uid;
    private String depName;
    private String depAddress;


    private Set<Employee> employees = new HashSet<Employee>();

Employee.hbm.xml
<hibernate-mapping>
  <class name="com.mipo.domain.Employee" table="T_EMPLOYEE">
    <id name="uid" column="uid" type="integer">
      <generator class="identity" />
    </id>
    <!-- <property name="depId" column="DEP_ID" insert="false" update="false" type="integer" /> -->
    <property name="empName" column="EMP_NAME" type="string" />
    <property name="empSex" column="EMP_SEX" type="string" />
    <property name="empMemo" column="EMP_MEMO" type="string" />


    <!--
        属性         描述
      ##############################################
      name        指定Employee类中department属性
     class        指定Employee类中department属性的数据类型
    column        指定T_EMPLOYEE表关联的外键
    -->
    <many-to-one name="department" class="com.mipo.domain.Department" column="DEPT_ID" cascade="save-update" lazy="proxy"/>
  </class>
</hibernate-mapping>

Employee.java

public class Employee implements Serializable {


    private static final long serialVersionUID = -8483463007573917074L;
    private Integer uid;
    private String empName;
    private String empSex;
    private String empMemo;


    private Department department;

##8  多对多的关系

Role

<hibernate-mapping>
  <class name="com.mipo.domain.Role" table="T_ROLE">
    <id name="uid" column="UID" type="integer">
      <generator class="identity" />
    </id>
    <property name="name" column="NAME" type="string" />
    <property name="memo" column="MEMO" type="string" />


    <set name="users" table="T_USER_ROLE_REL" cascade="save-update" lazy="true">
      <key column="ROLE_ID" />
      <many-to-many column="USER_ID" class="com.mipo.domain.User" />
    </set>
  </class>
</hibernate-mapping>


public class Role implements Serializable {


    private static final long serialVersionUID = 267803398483097335L;
    private Integer uid;
    private String name;
    private String memo;

    private Set<User> users = new HashSet<User>(0);

User.hbm.xml
<hibernate-mapping>
  <class name="com.mipo.domain.User" table="T_USER">
    <id name="uid" column="UID" type="integer">
      <generator class="identity" />
    </id>
    <property name="name" column="NAME" type="string" />
    <property name="pwd" column="PWD" type="string" />


    <set name="roles" table="T_USER_ROLE_REL" cascade="save-update" lazy="true">
      <key column="USER_ID" />
      <many-to-many column="ROLE_ID" class="com.mipo.domain.Role" />
    </set>
  </class>
</hibernate-mapping>

UserBean
public class User implements Serializable {


    private static final long serialVersionUID = -1287292866725348553L;
    private Integer uid;
    private String name;
    private String pwd;


    private Set<Role> roles = new HashSet<Role>(0);


hibernate.hbm.xml

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/scm?useUnicode=true&amp;characterEncoding=utf-8</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">root123</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL57InnoDBDialect</property>
    <property name="hibernate.show_sql">false</property>
    <property name="hibernate.format_sql">true</property>


    <mapping resource="com/mipo/domain/User.hbm.xml" />
    <mapping resource="com/mipo/domain/Role.hbm.xml" />
  </session-factory>
</hibernate-configuration>

===============================注解============================
字段级别注解
@Entity  加载类上面
@Table(name=" ") 对应的表
下面的注解都在属性对应的get方法上面
@Id  表明这个属性对应着表的主键
@GeneratedValue(strategy = GenerationType.IDENTITY)  i d的增长方式
@Column(name = "UID")  对应字段的名字
* @Entity     映射实体类
* @Id     映射生成主键
* @Table    映射表格
* @Column     映射表格列
* @Transient     定义暂态属性
@Entity( name="EntityName")
必须,name 为可选 , 对应数据库中一的个表
@Table( name="",catalog="",schema="")
可选, 通常和 @Entity 配合使用 , 只能标注在实体的class 定义处 , 表示实体对应的数据库表的信息
name: 可选 , 表示表的名称. 默认地 , 表名和实体名称一致, 只有在不一致的情况下才需要指定表名
catalog: 可选 , 表示 Catalog 名称 , 默认为 Catalog("").
schema: 可选 , 表示 Schema 名称 , 默认为 Schema(“”).

@id必须
@id定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键.置于 getXxxx()前 .
@ GeneratedValue( strategy=GenerationType, generator="")
可选
strategy: 表示主键生成策略, 有AUTO,INDENTITY,SEQUENCE 和TABLE 4种 ,分别表示让 ORM 框架自动选择 
@Column可选
@Column描述了数据库表中该字段的详细定义 , 这对于根据JPA注解生成数据库表结构的工具非常有作用 .
name:表示数据库表中该字段的名称 , 默认情形属性名称一致
nullable:表示该字段是否允许为 null,默认为 true
unique:表示该字段是否是唯一标识 , 默认为false
length:表示该字段的大小 , 仅对String 类型的字段有效
insertable:表示在 ORM框架执行插入操作时 , 该字段是否应出现INSETRT 语句中, 默认为true 
@Transient
可选
@Transient表示该属性并非一个到数据库表的字段的映射 ,ORM 框架将忽略该属性 .
如果一个属性并非数据库表的字段映射, 就务必将其标示为 @Transient, 否则 ,ORM 框架默认其注解为 @Basic
示例:
    // 根据 birth 计算出 age 属性
    @Transient
    public int getAge() {
      return getYear(new Date()) - getYear(birth);
    } 
* @ ManyToOne    多对一关联(单向或双向)
* @ OneToOne      一对一关联(单向或双向)
* @ OneToMany    一对多关联(单向或双向)
* @ ManyToMany   多对多关联(单向或双向)

@ ManyToOne(fetch=FetchType,cascade=CascadeType ) 可选
@ ManyToOne 表示一个多对一的映射 , 该注解标注的属性通常是数据库表的外键
optional: 是否允许该字段为 null, 该属性应该根据数据库表的外键约束来确定 , 默认为 true
fetch: 表示抓取策略 , 默认为 FetchType.EAGER
cascade:表示默认的级联操作策略 , 可以指定为 ALL,PERSIST,MERGE,REFRESH 和 REMOVE 中的若干组合 , 默认为无级联操作
targetEntity: 表示该属性关联的实体类型 . 该属性通常不必指定 ,ORM 框架根据属性类型自动判断 targetEntity.

@OneToMany(fetch=FetchType,cascade=CascadeType)
可选
@ OneToMany 描述一个一对多的关联, 该属性应该为集体类型, 在数据库中并没有实际字段.
fetch: 表示抓取策略, 默认为 FetchType.LAZY, 因为关联的多个对象通常不必从数据库预先读取到内存,可取值:
 LAZY(默认值)采用延时加载,查询数据时,不一起查询关联对象的数据。而是当访问关联对象时(如:getStudnets()时)才触发相应的查询操作,获取关联对象数据。
EAGER:是在查询数据时,也直接一起获取关联对象的数据。
一般对于fetch属性来说,取默认值就可以了。 

@ OneToOne(fetch=FetchType,cascade=CascadeType)
可选
@ OneToOne描述一个一对一的关联
fetch: 表示抓取策略, 默认为 FetchType.LAZY
cascade: 表示级联操作策略(见前面内容)
示例:
    @OneToOne(fetch=FetchType.LAZY)
    public Blog getBlog(){
       return blog;
    } 

* @ ManyToMany
* 可选
* @ ManyToMany 描述一个多对多的关联 . 多对多关联上是两个一对多关联 , 但是在 ManyToMany 描述中 , 中间表是由 ORM 框架自动处理
* targetEntity : 表示多对多关联的另一个实体类的全名 , 例如 : package.Book.class
* mappedBy : 表示多对多关联的另一个实体类的对应集合属性名称
* 示例 :
*     User 实体表示用户 ,Book 实体表示书籍 , 为了描述用户收藏的书籍 , 可以在 User Book 之间建立 ManyToMany 关联 

 */
@Entity
@Table(name = "T_DEPARTMENT")
public class Department implements Serializable {

    private static final long serialVersionUID = -2222647138773687754L;
    private Integer uid;
    private String depName;
    private String depAddress;

    private Set<Employee> employees = new HashSet<Employee>();

    public Department() {
        // Auto-generated constructor stub
    }

    public Department(String depName, String depAddress) {
        this.depName = depName;
        this.depAddress = depAddress;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "UID")
    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    @Column(name = "DEP_NAME")
    public String getDepName() {
        return depName;
    }

    public void setDepName(String depName) {
        this.depName = depName;
    }

    @Column(name = "DEP_ADDRESS")
    public String getDepAddress() {
        return depAddress;
    }

    public void setDepAddress(String depAddress) {
        this.depAddress = depAddress;
    }

    /**
     * mappedBy: 用于指定在双向关系中两个实体中哪个实体是被关联处理的,在OneToMany中定义。
     *
     * @return
     */
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.ALL)
    public Set<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(Set<Employee> employees) {
        this.employees = employees;
    }

    @Override
    public int hashCode() {
        final int prime = 37;
        int result = 17;
        result = prime * result + ((depAddress == null) ? 0 : depAddress.hashCode());
        result = prime * result + ((uid == null) ? 0 : uid.hashCode());
        result = prime * result + ((depName == null) ? 0 : depName.hashCode());

        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;

        if (obj == null)
            return false;

        if (getClass() != obj.getClass())
            return false;

        Department other = (Department) obj;
        if (depAddress == null && other.depAddress != null)
            return false;
        else if (!depAddress.equals(other.depAddress))
            return false;
        if (uid == null && other.uid != null)
            return false;
        else if (!uid.equals(other.uid))
            return false;
        if (depName == null && other.depName != null)
            return false;
        else if (!depName.equals(other.depName))
            return false;

        return true;
    }
    @Override
    public String toString() {
        return "department {\"uid\": " + uid + ", \"depName\": \"" + depName + "\", \"depAddress\": \"" + depAddress + "\"}";
    }

}
=============================sql和hql==============================

Hql

  public void queryMulEntity() {
        Session session = sessionFactory.openSession();
        session.beginTransaction();


        String hql = "select new Employee(e.empName, e.empSex) from Employee e where e.uid = 1";
        Query query = session.createQuery(hql);


        @SuppressWarnings("unchecked")
        List<Employee> data = query.list();


        for (Employee employee : data) {
            System.out.println(employee);
        }


        session.getTransaction().commit();
        session.close();
    }

sql

    @Test
    public void queryMulEntity() {
        Session session = sessionFactory.openSession();
        session.beginTransaction();


        SQLQuery query = session.createSQLQuery("SELECT T.* FROM T_EMPLOYEE T");
        query.addEntity(Employee.class);
        // query.addEntity("com.mipo.domain.Employee");


        @SuppressWarnings("unchecked")
        List<Employee> list = query.list();
        for (Employee employee : list) {
            System.out.println(employee);
        }


        session.getTransaction().commit();
        session.close();
    }
============================缓存===========================

什么是数据缓存

缓存是数据在内存中的临时容器,它包含数据库表的数据在内存中的临时拷贝,位于数据库和数据访问层之间 
* Hibernate的数据缓存策略主要包括3种:
* 事务级缓存
* 应用级缓存
* 分布式缓存
* 为了提高性能,Hibernate使用了缓存机制。在Hibernate的框架中,主要包括一级缓存和二级缓存
* Hibernate缓存主要两个方面发生作用
* 通过主键值加载数据
* 延迟加载

* Hibernate一级缓存主要是由session提供。它的存在和session的生命周期有关,当session关闭时,session管理的一级缓存也就消失。
* 我们也可以对session中的一级缓存进行手动干预:
* evict():用于将某个对象从session的一级缓存中清除
* clear():用于将一级缓存中的对象全部清除

* 一个Session中不能同时存在两个ID相同的持久化对象
* 例如:一个empId为1001的员工emp1己经存在于session中,如果利用此empId试图产生一个emp2的对象,则会产生异常:
* Transactiontr = session.beginTransaction();
* IntegerempId= new Integer(1001);
* Empemp1= (Emp)session.get(Emp.class, empId);
* Empemp2 = new Emp();
* emp2.setEmpId(empId);
* session.update(emp2);
* tr.commit();
* 上述代码运行后,则会产生异常.

* Hibernate二级缓存是一个可插拔的的缓存插件,由SessionFactory负责管理
* 二级缓存工作原理:
* 如果查询的结果集为实体对象,就把这些对象放入根据ID键放入到缓存中(以key-value形式存放)
* 根据ID查询,首先从一级缓存中查找,如果查不到并且配置了二级缓存,就从二级缓存中查找,如果还查不到就会查询数据库,把结果按照ID放入缓存中
* 删除、更新和增加数据时,同时更新缓存

适合放入Hibernate二级缓存的数据
1、较少被修改的数据
2、不重要、容许出现偶尔并发的数据不会被并发访问的数据参数数据

不适合放入Hibernate二级缓存的数据
1、经常被修改的数据
2、绝不容许出现并发的数据与其他应用共享的数据

二级缓存配置步骤如下:
1、首先要打开二级缓存,在hibernate.cfg.xml中添加如下配置:  
<propertyname="hibernate.cache.use_second_level_cache">true</property>
2、Hibernate的二级缓存使用第三方的缓存工具来实现,所以我们需要指定Hibernate使用哪个缓存工具。如下配置指定Hibernate使用EhCache缓存工具。
<propertyname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
3、Hibernate在默认情况下并不会对所有实体对象进行缓存,所以,我们需要指定缓存哪些对象,在实体对象的映射文件中(相应的<class>标签内部),添加如下配置:   
 <cacheusage="read-only"/>  //代表的是只读缓存策略,若为read-write代表可读写缓存
注意,这个<cache>标签只能放在<class>标签的内部,而且必须处在<id>标签的前面!!!  
这个<cache>标签放在哪些<class>标签下面,就说明会多这些类的对象进行缓存   

HQL执行数据库的查询的list方法和iterator方法
list方法:首先检查是否配置了查询缓存,如果配置了查询缓存则从查询缓存中寻找是否已经对该查询进行了缓存,否则从数据库中进行获取。 然后填充一级缓存、二级缓存和查询缓存
iterator方法:首先会使用查询语句获得ID值的列表,然后使用session的load方法获得所需要对象的值



==============================面试题===========================
1. HQL SQL 的区别和联系?

1、首先,hql是面向对象查询的;sql是面向数据库做查询。

2、hql的语法结构:from  + 类名+类对象 +where+类对象属性的条件;

      sql的语法结构:from  +数据库表名+ where +表字段条件

3、新增:hql不需要再用insert语句,只需构造新增对象后调用save()方法

4、修改:hql不需要再用update语句,只需得到修改对象后调用update()方法

5、删除:hql不需要再用delete语句,只需得到要删除的对象后调用delete()方法

6.   hql严格区分大小写,sql不区分大小写


2. 缓存对load()与get()方法的影响:
*load方法:先查一级缓存,然后根据是否存在二级缓存配置来查询二级缓存,如果仍然获取不到则在数据库中获取,最后将获取的值填充一级缓存和二级缓存
*get方法:get方法和load方法的区别在于是否查询二级缓存,如果get方法获得不到指定对象时会直接从数据库中查询 

3.Hibernate中save、persist和saveOrUpdate这三个方法的不同之处? 

除了get和load,这又是另外一个经常出现的Hibernate面试问题。 所有这三个方法,

也就是save()、saveOrUpdate()和persist()都是用于将对象保存到数据库中的方法,但

其中有些细微的差别。例如,save()只能INSERT记录,但是saveOrUpdate()可以进

行 记录的INSERT和UPDATE。还有,save()的返回值是一个Serializable对象,而

persist()方法返回值为void。你还可以访问 save、persist以及saveOrUpdate,找到它

们所有的不同之处。

4.Hibernate中的SessionFactory有什么作用? SessionFactory是线程安全的吗? 

这也是Hibernate框架的常见面试问题。顾名思义,SessionFactory就是一个用于创建

Hibernate的Session对象的工厂。SessionFactory通常是在应用启动时创建好的,应

用程序中的代码用它来获得Session对象。作为一个单个的数据存储,它也是 线程安全

,所以多个线程可同时使用同一个SessionFactory。Java JEE应用一般只有一个

SessionFactory,服务于客户请求的各线程都通过这个工厂来获得Hibernate的

Session实例,这也是为什么SessionFactory接口的实现必须是线程安全的原因。还

有,SessionFactory的内部状态包含着同对象关系影射有关的所有元数据,它是  不可

变的 ,一旦创建好后就不能对其进行修改了。

5.Hibernate中的SessionFactory有什么作用? SessionFactory是线程安全的吗? 

这也是Hibernate框架的常见面试问题。顾名思义,SessionFactory就是一个用于创建

Hibernate的Session对象的工厂。SessionFactory通常是在应用启动时创建好的,应

用程序中的代码用它来获得Session对象。作为一个单个的数据存储,它也是 线程安全

,所以多个线程可同时使用同一个SessionFactory。Java JEE应用一般只有一个

SessionFactory,服务于客户请求的各线程都通过这个工厂来获得Hibernate的

Session实例,这也是为什么SessionFactory接口的实现必须是线程安全的原因。还

有,SessionFactory的内部状态包含着同对象关系影射有关的所有元数据,它是 不可

变的,一旦创建好后就不能对其进行修改了。

6.Hibernate中Session的lock()方法有什么作用? 


这是一个比较棘手的Hibernate面试问题,因为Session的lock()方法重建了关联关系却

并没有同数据库进行同步和更新。因此,你在使用lock()方法时一定要多加小心。顺便

说一下,在进行关联关系重建时,你可以随时使用Session的update()方法同数据库进

行同步。有时这个问题也可以这么来问:Session的lock()方法和update()方法之间有什

么区别?。这个小节中的关键点也可以拿来回答这个问题

7.Hibernate中二级缓存指的是什么?


 这是同Hibernate的缓存机制相关的第一个面试问题,不出意外后面还会有更多这方面

的问题。二级缓存是在SessionFactory这个级别维护的缓存,它能够通过节省几番数据

库调用往返来提高性能。还有一点值得注意,二级缓存是针对整个应用而不是某个特定

的session的。

8.bernate中的查询缓存指的是什么?


 这个问题有时是作为上个Hibernate面试问题的后继问题提出的。查询缓存实际上保存

的是sql查询的结果,这样再进行相同的sql查询就可以之间从缓存中拿到结果了。为了

改善性能,查询缓存可以同二级缓存一起来使用。Hibernate支持用多种不同的开源缓

存方案,比如EhCache,来实现查询缓存


9.为什么在Hibernate的实体类中要提供一个无参数的构造器这一点非常重要?


每个Hibernate实体类必须包含一个 无参数的构造器, 这是因为Hibernate框架要使用

Reflection API,通过调用Class.newInstance()来创建这些实体类的实例。如果在实体

类中找不到无参数的构造器,这个方法就会抛出一个InstantiationException异常。


10.可不可以将Hibernate的实体类定义为final类?

是的,你可以将Hibernate的实体类定义为final类,但这种做法并不好。因为

Hibernate会使用代理模式在延迟关联的情况下提高性能,如果你把实体类定义成final

类之后,因为 Java不允许对final类进行扩展,所以Hibernate就无法再使用代理了,如

此一来就限制了使用可以提升性能的手段。不过,如果你的持久化类实现了一个接口而

且在该接口中声明了所有定义于实体类中的所有public的方法轮到话,你就能够避免出

现前面所说的不利后果。


11.hibernate对象状态?

临时状态:数据库中不存在一条与对象对应的数据,对此对象操作不会影响数据库的数                   据
持久状态:对象已经被保存在数据库的实体对象,并且这个实体对象会处于hibernate的                   缓存管理之中。(对此对象进行任何修改都会影响到数据库中的数据)

托管状态:无论对实体类做任何操作度都不会影响数据库的数据(对象不在hibernate                    的缓存中)

自由对象和游离对象的区别:

         自由对象在数据库中没有数据与之对应

         游离对象在数据库中有一条数据与之对应

托管的对象一定是有持久状态转移过来的

调用save(),saveorupdate()可以把临时状态改变为持久状态

       event(),clear(),close()可以持久态变为托管状态

update(),saveorupdate()可以把托管状态变为持久态

delete()可以把持久状态变为临时状态


12.hibernate中的update()和saveorupdate()的区别,session的load()和get()的区别?
 
如果是有update()更新一个对象,那么就会 把所有的属性都更新一遍,如果数据量很大的话,则非常损耗资源,所以这是有hql语句来解决比较好
update()是更新一个对象
saveorupdate()是hibernate自己判断这个对象是否存在,如果存在就更新,如果不存在就添加

Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对

应的实体对象。其区别在于:

1. 对于get方法,hibernate会确认一下该id对应的数据是否存在,首先在session缓存

中查找,然后在二级缓存中查找,还没有就查询数据库,数据库中没有就返回null。 

2. load方法加载实体对象的时候,根据映射文件上类级别的lazy属性的配置(默认为

true),分情况讨论:
 
(1)若为true,则首先在Session缓存中查找,看看该id对应的对象 是否 存在,不存在则

使用延迟加载,返回实体的代理类对象(该代理类为实体类的子类,由CGLIB动态生

成)。等到具体使用该对象(除获取OID以外)的时候, 再查询二级缓存和数据库,若仍没

发现符合条件的记录,则会抛出一个ObjectNotFoundException。

(2)若为false,就跟get方法查找顺序一样,只是最终若没发现符合条件的记录,则会抛出

一个ObjectNotFoundException。
 
这里get和load有两个重要区别: 

如果未能发现符合条件的记录,get方法返回null,而load方法会抛出一个

ObjectNotFoundException。 

(3)load():代表延时加载,当我们使用load()加载一个方法时,并不会立即向数

据库发送sql语句,得到的只是一个包含了实体对象id值得代理对象,只有当使用

具体属 性的时候才会发送sql语句

get():不管后面是否使用 只要调用了此方法,就会发送sql语句查出对象





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值