一、Hibernate的第一个程序

    

1、导入jar包

2.domain,以及映射文件User.hbm.xml

      User.hbm.xml的语法格式:

<-- package类的权限定名 -->

<hibernate-mapping package="">

<class name="" table="">

   <id name="" column="">

    <generator>

   </id>

   <property name="" column=""/>

</class>

</hibernate-mapping>

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.fkjava.day01._01_crud.domain">
    <class name="User" table="t_user">
        <id name="id" column="uid">
            <generator class="native"/>
        </id>
        <property name="name"  column="uname"/>
        <property name="salary"  column="usalary"/>
        <property name="hireDate"  column="uhiredate"/>
    </class>
</hibernate-mapping>

3.核心配置文件hibernate.cfg.xml,放到resource中

   

数据库连接配置和引入映射文件

<!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.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <!-- 配置数据库驱动 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- 配置数据库url -->
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatedemo</property>
        <!-- 配置数据库账号 -->
        <property name="hibernate.connection.username">root</property>
        <!-- 配置数据库密码 -->
        <property name="hibernate.connection.password">admin</property>
        <!-- 配置session从当前线程中获取 -->
        <property name="hibernate.current_session_context_class">thread</property>
        
        <!-- 显示SQL语句 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 格式化SQL语句 -->
        <property name="hibernate.format_sql">true</property>
        
        <!-- 自定生成数据库表的方式 -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        
        <!-- 关联映射文件 -->
        <!-- <mapping resource="org/fkjava/day01/_01_crud/domain/User.hbm.xml"/> -->
        <!-- <mapping resource="org/fkjava/day01/_03_/cfg/Student.hbm.xml"/> -->
        <mapping resource="org/fkjava/day01/_04_/oid/Person.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
   Configuration cfg = new Configuration().configure();         
   SessionFactory factory = cfg.buildSessionFactory();
  Session session=  factory.openSession();
  // 5.打开事务        
  session.getTransaction().begin();        
  // 6.DML操作:        
  session.save(u);// 保存操作
  session.delete(u);
  session.update(u);
  User user = session.get(User.class, id);        
  //清空一级缓存所有对象        
  //session.clear();        
  //删除一级缓存指定对象        
  //session.evict(user);
   List<User> list = session.createQuery("select u from User u ").list();
  // 7.提交/回滚事务       
  session.getTransaction().commit();        
  // 8.关闭Session        
  session.close();


二、SessionFactory

 SessionFactory对象:
1.负责创建Session对象
2.数据库的连接信息是配置SessionFactory;
3.SessionFactory是线程安全的,SessionFactory的创建需要很大的系统开销,实际上,在创建sessionFactory的时候才会去连接数据库,一般的,针对一个应用,一个数据库服务器,只需要一个SessionFactory实例就够了.
4.SessionFactory的重要方法:使用银行转账案例,说明openSession和getCurrentSession
  1).openSession:这个方法代表,开启一个全新的Session(测试环境)
    1.全新的连接
    2.全新的事务
    3.全新的一级缓存
  2).getCurrentSession:得到当前上下文中的session,绑定到当前线程.(开发环境)
    1.如果当前上下文中存在session,则使用该session;
    2.如果当前上下文中不存在session,则使用opensession创建一个新的session;
    3.要使用getCurrentSessoin,必须在hibernate.cfg.xml中配置
      <property name="hibernate.current_session_context_class">thread</property>
    4.getCurrentSession得到的session是和事务绑定的(Spring集成Hibernate的方式);
      1,无论是DML还是DQL ,都必须开启事务
      2,当事务提交的时候,session就跟着关闭了.-->此时不需要人为的调用:session.close()



三、OID(就是对象在数据库中对应的主键的属性)


四、session常用方法(一级缓存 类型+OID)

  session.flush();把一级缓存的脏数据同步到数据库中

  session.load(对象,OID);查询数据库中对象(延迟加载,发送sql语句只有真正使用这个对象才会发送,就是使用非主键属性时)

  load实现原理?使用动态代理,为load的domain动态创建了一个子类,在这个子类中,复写所有非主键调用方法,在这些方法中,去发送.

   load原理:

    1).Hibernate框架的中的javassist组件创建了代理类以及对象.

    2).该对象提供了非主键属性的getter方法和toString方法.

    3):该对象存在是否加载完毕的状态,访问属性是先判断对象是否加载完毕,如是直接返回该属性之,否则发送SQL查询该对象.

 

  get方法返回的总是持久化状态的对象;get方法立刻发送一条SELECT语句,结果可以用if - null来判断

load方法并不会立刻发送一条SELECT语句去查询对象,而要到真正在使用(使用一个非主键属性)这个对象的时候,才会去发送SELECT语句,我们把这种方式叫做延迟加载(lazy-load)/懒加载

 


五、持久化对象的状态

   临时状态(没有OID,不在session(即一级缓存)中)

   持久化状态(有OID,在session中)

   游离状态(有OID,不在session中)

   删除状态(就是持久化状态即将从session删掉的状态)

session负责改变状态,事务负责同步数据

save操作的时候,需要拿到OID(有些主键生成策略是通过发送sql语句拿到OID,有些不用发送SQL语句就可以拿到OID)

脏的持久化对象同步到数据库.(session快照)

1: save方法只需要把对象从临时变成持久化状态,只需要找到OID即可.不同的ID生成策略,

    有的必须发生INSERT才能得到ID,有的不需要发生INSERT就可以得到ID,所以此时,不需要发送INSERT语句.

2: 因为delete方法仅仅只是把游离对象或持久化对象变成删除状态,并不负责发生SQL.

3: 持久化对象的属性真正发生改变时,才会发生UPDAE语句.

 

六、集合映射

 1.映射文件配置

<!-- 映射Set集合 -->

<set name="emailSet" table="user_emails_set">

<key column="user_id" />

<element column="address" type="string" />

</set>

 <!-- 映射Collection/List集合 -->

<bag name="emailBag" table="user_emails_bag">

<key column="user_id" />

<element column="address" type="string" />

</bag>

 

2.对象之间的关系(进行关联的时候get方法都是使用延迟加载,所以不会发送sql查找关联的对象,只有使用该对象才会发送sql语句)(先保存没有关联的数据,在保存有外键关联的数据,就不会有脏数据)(维护外键和放弃外键的维护)(单向多对一用的最多)

       1)单向多对一(这个外键关联对象)

      <many-to-one name="dept"  column="dept_id"/>

      2)单向一对多

        <set name="emps" table="t_employee">

            <key column="dept_id"/>

           <one-to-many/>

        </set>

      3)双向一对多,多对一

          inverse:放弃外键维护

          cascade:级联操作

     4)双向的多对多

       <set name="teachers" table="students_teachers">

        <key column="student_id"/>

        <many-to-many column="teacher_id"/>

      </set>

 

七、hibernate常用的两种查询方式

     session.createNativeQuery(sql,返回的对象类型的字节码,如果是数组不用写);

   session.createQuery(hql,返回的对象类型的字节码,如果是数组不用写);


八、分页查询

     setFirstResult/setMaxResult

九、位置占位符和命名占位符

     就是hql中? 变为:变量名(随意起)   

十、投影查询

      查询持久化类的一个或多个属性

    List<Object[]> list = session.createQuery(hql).list();


十一、封装查询结果

HQ封装:

     new list

     new map

    new EmployeeVO(值对象)    

 

List<List<object>> list=session.createQuery(hql).list();

List<Map<objiect,object>> list=session.createQuery(hql).list();

List<EmployeeVO> list=session.createQuery(hql).list();


十二、hql中的集合操作(对集合的操作(size属性或size函数获取集合元素数量 ) is empty)

    select p from Project p where p.employees.size>0


十三、连接查询

    select e.name,d.name from Employee e inner/left join  e.dept d;


十四、聚焦函数和子查询

     AVG()

     MAX()

     COUNT()



十五、事务并发访问问题和事务隔离级别

1.事务并发5大问题

       第一类丢失更新(一个提交,另一个回滚,提交的也回滚)

       脏读(读到未提交的另一个事务的数据)

       虚读(读取到已经提交的数据)

       不可重复读(读到已经修改的数据)

      第二类丢失更新(两个都提交,后一个覆盖前一个)

2.4个隔离级别(3个不能处理第一类丢失更新和第二类丢失更新,通过hibernate的锁机制来处理)


十六、悲观锁、乐观锁

     悲观所就是给数据上锁

     乐观锁不会上锁,但是在更新的时候会判断


十七、JPA(使用注解或者xml配置文件进行描述对象-关系表的映射关系 加载方式 抓取策略)

   1.注解  @Entity

          @Table

         @id

         @GeneratedValue

         @Column

         @Temporal

         @Transients

  2.配置文件persistence.xml放在classpath/mata-inf

       配置文件中的persistence-unit持久化单元相当于session-factory,name必须要写,用来创建持久化管理对象工厂用

       持久化对象管理工厂EntityManagerFactory相当于SessionFactory

       持久化管理的对象EntityManager相当于Session

EntityManger方法

 

1,persist;把对象从临时对象转成持久化对象——save;

2,find;直接查询一个持久化对象——get;

3,merge:把游离对象变成持久化对象——update;

4,getReference;相当于load,延迟加载;加载一个持久化对象——load;

5,createQuery;创建查询对象;

6,createNativeQuery;创建SQL查询对象;

7,remove;把持久化对象/游离对象转化为临时对象——delete;

8,detach;把持久化对象转化成游离对象——evict;

9,close:关闭EntityManager;

 

3. 放弃维护外键

   @ManyToMany(mappedBy="teachers")   teachers自己在另一方集合属性名称

4.自定义第三方表

   @joinTable(name="",

              joinColumns=@joinColumn(name="" ,referencedColumnName=""),

             inverseJoinColuns=@joinColumn(name="" ,referemcedColumnName="")

              )