Hibernate框架常用知识点总结

来源:互联网 发布:mac彻底卸载软件数据 编辑:程序博客网 时间:2024/05/18 02:28

Hibernate

概念

  • 用于操作数据库
  • hibernate可以用面向对象的方式操作数据库
  • ORM框架-将对象与表的关系使用配置文件映射

框架搭建

  1. 导包
    导入lib下的required下的包
  2. 准备实体&映射文件
    在实体所在包下新建映射文件(名称:类名.hbm.xml),导入dtd约束(在hibernate-mapping-3.0.dtd)

    <hibernate-mapping>    <class name="类名" table="表名">        <!--配置主键-->        <id name="主键对应的属性名" column="表的主键名" >            <!--配置id生成策略-->            <generator class="native"></generator>        </id>        <!--配置其他属性-->        <property name="属性名" column="表的字段"></property>    </class></hibernate-mapping>
  3. 准备主配置文件
    在src目录下,新建hibernate.cfg.xml主配置文件,导入dtd约束(在hibernate-configuration-3.0.dtd)

    <session-factory>    <!--5个必选项-->    <proprrty name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>    <proprrty name="hibernate.connection.url">jdbc:mysql:///test</property>    <proprrty name="hibernate.connection.username">root</property>    <proprrty name="hibernate.connection.password">123</property>    <!--mysql方言,选择最短的选项-->    <proprrty name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>    <!--3个可选项-->    <!--选择标准的sql打印在控制台-->    <property name="hibernate.show_sql" >true</property>    <property name="hibernate.format_sql" >true</property>    <!--自动建表-->    <property name="hibernate.hbm2ddl.auto">update</property>    <!--引入映射文件-->    <mapping resource="cn/it/domain/User.hbm.xml" /></session-factory>
  4. 书写代码

配置详解

映射文件

hibernate-mapping

package属性:填写一个包名,后续配置中默认类所在包即为package属性填写的包

class属性

映射表与类的对应
name属性:类名
table属性:表名

id属性(映射主键)

name属性:类中主键属性名
column属性:表中主键名,默认列名为属性名
length属性:当前列的长度,默认数据库对于类型最大长度
type属性:当前列的类型,默认自动检测属性

generator属性:主键生成策略

代理主键:
increment:先查询表中主键最大值,加1作为新的主键值.
identity:依赖于数据库的主键自增
sequence:使用数据库中的序列
hilo:hibernate自己用高低位算法完成主键自增
uuid:生成随机字符串作为主键(长度应大于32位)
native(常用):自动根据数据库 三选一.(identity|sequence|hilo)

自然主键:
assigned:hibernate不生成主键.由开发人员自己设置主键值.

property属性(映射普通列)

name属性:类中主键属性名
column属性:表中主键名,默认列名为属性名
length属性:当前列的长度,默认数据库对于类型最大长度
type属性:当前列的类型,默认自动检测属性

主配置文件

整体结构在框架搭建的主配置文件中。

自动建表(hibernate.hbm2ddl.auto)
create:自动建表,每次启动hibernate都会自动建表,即使表已经存在,仍然会删除重新建。
create-drop:自动建表,每次启动hibernate都会自动建表,每次运行完成后会将表删除。
update:自动建表,如果有表,就不在重新创建,如果配置改变,自动更改表结构。
validate:不会自动创建表结构,只负责在启动时检验表结构,检出问题后会抛出异常。

API详解

configuration

config,读取配置文件buildSessionFactory,创建sessionFactoryConfiguration conf = new Configuration().config;SessionFactory sf = conf.buildSessionFactory;

SessionFactory

根据配置信息创建session对象。
1. SessionFactory创建需要消耗较多的内存资源。
2. SessionFactory是线程安全的设计。
结论:在一个web项目中确保只有一个SessionFactory存在。

//获得一个全新的sessionSession session = sf.openSession();//获得与线程绑定的session,使用需要两个条件:1.在主配置文件中配置2.不需手动关闭sessionSession session = getCurrentSession

Session

hibernate中操作数据库的核心对象。
1. 操作增删改查
2. 获得事务操作对象

beginTransaction|getTransaction 获得事务对象,第一个还具有开启事务的功能。get|load   根据给定标识和实体类返回持久化对象的实例save    增delete  删update  改saveOrUpdate 根据给定的实例的标识属性的值来决定执行增或改的操作。createQuery 根据给定的HQL查询条件创建一个新的Query实例。createCriteria  根据给定的实体的名称,创建一个新的Criteria实例。createSQLQuery 根据给定的SQL查询条件创建一个新的SQLQuery实例。get方法不会应用类级别加载策略,立即加载。load方法会应用类级别加载策略,load方法调用时,不会发送任何sql语句,返回一个代理对象,使用对象时才执行查询加载数据。

Transaction

用于操作事务的对象

tx.tx.begin();//开启事务tx.commit();//提交事务tx.rollBack();//回滚事务

创建实体对象规则

  1. public的空参构造
  2. 准备属性,public的set/get方法
  3. 提供oid,映射主键字段
  4. 标识属性尽量使用基本数据类型的包装类
  5. 类不能被final修饰

对象的三种状态

瞬时 没id,没关联

持久 有id,有关联

游离 有id,没关联

持久化状态:持久化状态对象会在事务提交时会持久化到数据库,我们需要将对象持久化到数据库,就需要把对象转换为持久化状态。

一级缓存

一级缓存:也称为session缓存.属于线程级别缓存. 该缓存本质其实就是一个集合.该集合被放置到了session对象中.所以也叫session缓存.因为session是线程级别的.所以该缓存属于线程级别缓存.
缓存的作用:提高查询、修改效率。

查询:
1. 根据id查询对象
2. ResultSet会被封装成对象,放入缓存以及返回程序。如果缓存中存在要查id的对象,返回缓存中的对象。

修改:
1. 根据id查询对象
2. ResultSet会被封装成对象,一式两份,分别放入session缓存以及缓存快照中
3. 事务在提交时,会比对session缓存中的以及快照中的对象是否发生变化。如果发生变化执行修改。

hibernate中的事务管理

设置事务隔离级别

<!--数值可设置为1、2、4、8--><property name="hibernate.connection.isolation">4</property>

hibernate中事务的应用

  1. 事务在service层管理。
  2. 确保service层和dao层使用的时同一个Connection,调用getCurrentSession方法是从ThreadLocal中获得与线程绑定的session。
  3. getCurrentSession必须配置才能使用

    <!--指定getCurrent获得session与当前线程绑定--><property name="hibernate.current_session_context_class">thread</property>
  4. getCurrentSession方法获得的session对象,会在事务提交时自动关闭,不用手动关闭。

一对多|多对一关系

ORM

ORM:对象关系映射

  • o:一的一方使用集合,多的一方直接引用一的属性
  • r:多的一方使用外键引用一的一方
  • m:一对多关系映射,多对一关系映射

    <!--配置一对多关系--><set name="集合属性名">    <key column="外键名"></key>    <one-to-many class="多的一方对应的类名" /></set><!--配置多对一关系--><many-to-one name="引用一的属性名" column="外键名" class="一的一方对应的类名"><many-to-one>

应用

Cascase属性:级联操作

  • none:默认值,不级联
  • save-update:级联保存或级联更新
  • delete:级联删除
  • all:save-update+delete

结论:Cascase属性的性质属于减少开发时书写代码量的配置,可以不用靠写代码代替,级联操作尤其级联删除配置使用风险大,不建议使用。

inverse属性:是否放弃维护关系

inverse属性:
- true:放弃
- false(默认):维护

一对多中可以使用Inverse属性放弃维护关系,多对一中不能放弃维护关系。

<set name="linkMen" inverse="true">    <key column="lkm_cust_id"></key>    <one-to-many class="LinkMan"></one-to-many></set>

结论:为了避免维护关系SQL打印冗余,可以在一的一方放弃维护。配置后注意,表达关系只能通过多的一方来维护。

多对多关系

ORM

ORM:对象关系映射

  • r:使用第三张表,该表至少两列,两列都是外键
  • o:两方都用集合来表达引用多个对方
  • m: 多对多映射文件




应用

Cascade属性:级联操作

与一对多|多对一关系中相同的操作

不推荐使用delete

inverse属性:是否放弃维护关系

inverse属性:

  • true:放弃
  • false(默认):维护

结论:为了避免维护关系重复造成异常抛出,根据业务需要由一方放弃维护。放弃的规则:谁不依赖,谁放弃。例如:订单和商品,商品不依赖订单的存在,商品放弃维护。

Hibernate中的查询

  • 根据OID查询
  • 对象属性导航
  • HQL查询
  • Criteria查询
  • 原生SQL查询

HQL

Hibernate Query Language:hibernate查询语言
该查询语言是面向对象的查询语言.
HQL语句中绝对不可能出现与数据库相关的信息.
该语言是Hibernate独有的语言.只能在Hibernate中使用

语法

一. 基础语法

    //1.书写sql    //String hql = "select c from cn.it.domain.Customer c";//完整写法    String hql = "from Customer";//简写    //2.创建查询对象    Query query = session.createQuery(hql);    //3.执行查询    List<Customer> list = query.list();

二. 投影查询

查询一个属性

    String hql = "select c.id from Customer c";    Query query = session.createQuery(hql);    List<String> list = query.list();

查询两个属性

    String hql = "select c.id,c.name from Customer c";    Query query = session.createQuery(hql);    List<Object[]> list = query.list();

查询多个对象,并封装到对象中

    String hql = "select new Customer(c.id,c.name,c.password) from Customer c";    Query query = session.createQuery(hql);    List<Customer> list = query.list();

三. 条件查询

问号占位符

String hql = "from Customer c where c.name=?";Query query = session.createQuery(hql);query.setParameter(0,"张%");//从0开始List<Customer> list = query.list();

命名占位符

String hql = "from Customer c where c.id between :low and :high";Query query = session.createQuery(hql);query.setParameter("low",2);query.setParameter("high",5);List<Customer> list = query.list();

四. 分页查询

String hql = "from Customer";Query query = session.CreateQuery(hql);query.setFirstResult(2);//startIndexquery.setMaxResults(2);//pageSizeList<Customer> list = query.list();

五. 排序
desc降序,asc升序

String hql = "from Customer c order by c.id desc ";Query query = session.createQuery(hql);List<Customer> list = query.list();

六. 聚合函数查询
Count、Max、Min、Sum、Avg

String hql = "select count(c) from Customer c";Query query = session.createQuery(hql);Long count = (Long)query.uniqueResult();

七. 多表查询

内连接

String hql = "from Customer c inner join c.linkMen";Query query = session.createQuery(hql);List<Object[]> list = query.list();

迫切内连接

String hql = "from Customer c inner join fetch c.linkMen";Query query = session.createQuery(hql);List<Customer> list = query.list();

左外连接

String hql = "from Customer c left join c.linkMen";Query query = session.createQuery(hql);List<Object[]> list = query.list();

左外迫切连接

String hql = "from Customer c left fetch c.linkMen";Query query = session.createQuery(hql);List<Customer> list = query.list();

右外连接、右外迫切连接在左的基础上把left换为right即可。

结论:HQL适用于单表或简单多表,业务逻辑较为复杂的多表仍然需要使用原生SQL书写.

Criteria查询

hibernate框架中独有的查询方式.
Criteria是无语句面向对象查询.
Criteria一般用于单表查询.

语法

一、基础查询

//1.创建查询对象Criteria c = session.createCriteria(Customer.class);//2.执行查询List<Customer> list = c.list();

二、条件查询

Criteria c = session.createCriteria(Customer.class);//设置查询参数c.add(Restrictions.and(Restrictions.between("id",2,5),Restrictions.like("name","李%")));//查询List<Customer> list = c.list();

三、分页查询

Criteria c = session.createCriteria(Customer.class);c.setFirstResult(2);c.setMaxResults(2);List<Customer> list = c.list();

四、排序查询

Criteria c = session.createCriteria(Customer.class);c.addOrder(Order.asc("age"));List<Customer> list = c.list();

五、聚合查询

Criteria c = session.createCriteria(Customer.class);c.setProjection(Projections.Count("id"));Long count = (Long)c.uniqueResult();

离线Criteria查询对象

离线Criteria:不需要session就可直接创建

//获得离线查询对象DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);//设置条件dc.add(Restrictions.like("name","王%"));//将离线查询对象与session关联Criteria c = dc.getExecutableCriteria(session);//执行操作List<Customer> list = c.list(); 

结论:适合单表

原生SQL

语法

一、基本查询

String sql = "select * from t_customer";//创建查询对象Query query = session.createSQLQuery(sql);List<Object[]> list = query.list();

将指定结果封装到对象中

String sql = "select * from t_customer";Query query = session.createSQLQuery(sql);//指定将结果封装到对象中query.addEntity(Customer.class);List<Customer> list = query.list();

二、条件查询

参数查询:可以用问号|命名占位符

String sql = "select * from t_customer where name like ?";Query query = session.createSQLQuery(sql);query.setParameter(0,"陈%");query.addEntity(Customer.class);List<Cutomer> list = query.list();

三、分页查询

String sql = "select * from t_customer limit ?,?";Query query = session.createSQLQuery(sql);query.setParameter(0,2);//设置起始页query.setParameter(1,3);//设置每页封装数量query.addEntity(Customer.class);List<Customer> list = query.list();

用于复杂业务查询

查询策略

类级别查询策略

lazy属性:是否懒加载|延迟加载

  • true(默认值):懒加载|延迟加载
  • false:立即加载

    <!--配置类级别查询策略--><class name="User" table="cn.it.domain.User" lazy="true"></class>

原理:懒加载时,load方法不会立即查询,会返回要查询的对象的代理对象,这个代理对象对当前操作的session进行封装,在获得对象的属性时,能够根据关联的session加载数据。

注意事项:返回对象的初始化操作一定要在session关闭之前完成,否则会抛出no-session异常。

关联级别查询策略

集合加载策略(一对多|多对多)

lazy属性:决定集合加载策略

  • true(默认值):懒加载|延迟加载
  • false:立即加载
  • extra:极其懒惰,在查询数量时,只查询数量,不查询内容。

fetch属性:指定集合的加载方式

  • select(默认值):加载集合时使用单表查询加载
  • join:加载集合时使用左外连接查询(使用改属性,lazy属性会失效)
  • subselect:使用子查询加载多个集合,如果只加载一个,效果和select相同。

    <set name="linkMen"  inverse="true" lazy="true" fetch="subselect" >    <key column="lkm_cust_id"></key>    <one-to-many class="LinkMan"></one-to-many></set>

属性加载策略(多对一)

lazy属性:决定属性加载策略

  • proxy(默认值):由对方类级别策略代我决定
  • false:立即加载

fetch属性:指定属性的加载方式

  • select(默认值):单表查询加载数据
  • join:使用多表查询同时加载数据(使用改属性,lazy属性会失效)

    <many-to-one name="customer" column="lkm_cust_id" class="Customer" lazy="proxy" fetch="select"></many-to-one>

查询策略结论:查询策略中涉及的所有属性都使用默认值

两个问题

问题一:sql语句打印n+1问题

batch-size属性:一次加载几个客户的集合,默认值为1.使用该属性选择一次加载几个客户的集合来缓解n+1问题

<set name="linkMen" batch-size="5" >    <key column="lkm_cust_id"></key>    <one-to-many class="LinkMan"></one-to-many></set>  

问题二:dao返回的代理对象,service中关闭了session。在web层使用代理对象时,session已经关闭。会抛出no-session异常。

解决方案:
1. 不使用getCurrentSession,自己将session与现程绑定。
2. 使用过滤器,由过滤器中后处理代码将session关闭。

上述操作,交由spring管理。

1 0