一:初衷
个人理解Hibernate出现的初衷是解决应用、程序与数据库交互的过程。最初人们都是用jdbc直连数据库来实现,不同的业务场景下要不数据库连接实现的代码重复性太高,虽然后来抽出一个单独的工具类来处理连接,但是操作不同的对象持久化到库,耦合性比较高,而且不符合我们面向对象设计的原则,你存储一个object到数据库,不同的业务场景存储最好能抽象出一个具体的Object来交互,也就是后来说的 POJO或javaBean。这个优化也使用了很多设计模式,比如代理模式,即用一个代理类来封装不同业务场景的dao,再比如工厂模式,通过工厂输入不同业务场景类的.class,得到这个业务场景的dao操作实现类,具体工厂通过入参可以匹配到配置文件中对应的实现类。 由于数据库连接的最高效率利用,引入了连接池的概念。当然我们可以使用一些已经成熟的数据库连接池组件,比如apache的Dbcp连接,proxool,c3p0等。多说一句,C3P0是一个开源的jdbc连接池,它实现了数据源和JNDI的绑定,支持JDBC3规范和JDBC2的标准扩展。目前开源项目Hibernate和Spring等都使用它了。C3P0和dbcp相比,配置功能更丰富,有自动回收空闲连接的功能,dbcp没有自动回收空闲连接的功能。
其中数据库交互过程中有个重要的概念,即 statement,
JDBC是由一系列连接(Connection)、SQL语句(Statement)和结果集(ResultSet)构成的,其主要作用概括起来有如下3个方面: 建立与数据库的连接。 向数据库发起查询请求。 处理数据库返回结果。
Statement用于在已经建立的连接的基础上向数据库发送SQL语句的对象。它只是一个接口的定义,其中包括了执行SQL语句和获取返回结果的方法。实际上有3种 Statement 对象:Statement、
PreparedStatement(继承自Statement )和 CallableStatement(继承自PreparedStatement)。它们都作为在给定连接上执行 SQL 语句的容器,每个都专用于发送特定类型的 SQL 语句: Statement 对象用于执行不带参数的简单 SQL 语句;PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;CallableStatement 对象用于执行对数据库已存储过程的调用。Statement 接口提供了执行语句和获取结果的基本方法;PreparedStatement 接口添加了处理 IN 参数的方法;而 CallableStatement 添加了处理 OUT 参数的方法
二:ORM
ORM即Object/Relational Mapper,对象-关系型数据映射组件。
Hibernate很好的实现了所描述的数据库封装以及ORM实现,更高效,便捷,可拓展的让应用去操作数据库。
三:Hibernate模块化
Hibernate会自动从当前classPath搜寻Hibernate.cfg.xml文件,并将其加载至内存中,作为后继操作基础配置。
除了默认的这个配置文件,我们当然也可以指定其他配置文件作为加载的基础配置文件。Configuration类一般只有在获取SessionFactory涉及,SessionFactory实例创建后Configuration就加载了配置信息,包括数据库url,用户,密码,驱动类,数据库适配器等。SessionFactory创建实例的时候,需要Configuration作为参数来进行构造。
Hibernate Session:
Session是Hibernate持久化操作的基础,这里的session和传统web层的HttpSession概念不同,也没任何关系。
Hibernate Session之与Hibernate,相当于JDBC Connection与JDBC。Session提供了增删改查四个方法操作数据库。
Hibernate事务处理:
Hibernate将低层的JDBCTransaction或JTATransaction进行了封装,在外面套上Transaction和Session的外壳,其实是通过委托低层的JDBC或JTA来实现事务的处理功能的。Hibernate的事务工厂类可以设置成JDBCTransactionFactory或者JTATransactionFactory。如果不进行配置,Hibernate就会认为系统使用的事务是JDBC事务。
Hibernate O-R映射:
Hibernate基础数据类型映射,比如以java为例,java中的int对应数据库的字段类型Integer,每个java中的数据类型,数据库中都有对应数据类型与之对应,再次不再赘述。
Hibernate 实体映射,类表映射:
表名到类名映射,主键映射,字段映射。主键的生成方式有 native方式,即依赖不同的后台数据库采用不放的方式,mysql-自增主键,oracle的sequence主键等。
Hibernate高级映射技术:
自定义类型概念,复合主键概念,复合主键在xml文件中定义的格式。BLob和Clob字段映射,Blob适合存储二进制数据比如图片,Clob适合存储大文本数据。因为Blob用单字节存储,Clob采用多字节存储。
Hibernate数据关联:
一对一关联:级联关系设置为all,代表当主控方执行操作时,关联对象是否同步执行同一操作。
一对多关联:
Hibernate 中常会用到set,bag等集合表示1 对多的关系, 在获取实体的时候就能根据关系将关联的对象或者对象集取出, 还可以设定cacade进行关联更新和删除。这不得部说hibernate 的orm做得很好,很贴近oo的使用习惯了。
但是对数据库访问还是必须考虑性能问题的, 在设定了1 对多这种关系之后, 查询就会出现传说中的n +1 问题。
1 )1 对多,在1 方,查找得到了n 个对象, 那么又需要将n 个对象关联的集合取出,于是本来的一条sql查询变成了n +1 条
2)多对1 ,在多方,查询得到了m个对象,那么也会将m个对象对应的1 方的对象取出, 也变成了m+1
怎么解决n +1 问题?
1 )lazy=true, hibernate3开始已经默认是lazy=true了;lazy=true时不会立刻查询关联对象,只有当需要关联对象(访问其属性,非id字段)时才会发生查询动作。
2)二级缓存, 在对象更新,删除,添加相对于查询要少得多时, 二级缓存的应用将不怕n +1 问题,因为即使第一次查询很慢,之后直接缓存命中也是很快的。
不同解决方法,不同的思路,第二条却刚好又利用了n +1 。
3) 当然你也可以设定fetch=join
多对多关联:由于多对多的性能不佳(引入中间映射表,一次读取操作需要反复数次查询),因此在设计时应该避免大量使用。
四: Hibernate 数据检索
Criteria Query:
Criteria查询表达式:
有个专门的表达式对应表,这里只列举一部分:
复合查询,在一对多的时候,多也有条件查询,后台自动组件join语句,critera提供表达式实现。
DetachedCriteria
HQL查询:
HQL相比Criteria提供了更丰富灵活的特性,所以使用起来更广泛:
实体查询,属性查询,实体更新与删除,分组与排序,参数绑定,引用查询,联合查询,子查询,SQL查询,数据加载方式。