Hibernate学习总结

-----------------------day01----------------------------------
Hibernate:
持久化java对象


封装了JDBC,实现了or-mapping一个开源的持久层框架
orm:(Object Relation Mapping)


Jdbc特点:
* 操作代码复杂
* JDBC的应用与数据库耦合度强
* JDBC的应用很难做到轻松的数据库移植
* 不能实现对数据的缓存
* 对象 与 关系之间的转换,需要用户实现
* 性能高(数据量非常庞大的情况)


Hibernate特点:
* 封装了JDBC底层的操作
* Hibernate的应用与数据库耦合度低
* 不再需要使用sql语句,直接操作对象
* orm的实现,抵抗不匹配
User{uid,username....}
save(user);
映射(xml)
t_user(uid,username)
* 做不到sql优化
* 缓存的实现
* 不适合对数据量非常庞大的系统


Hibernate的使用: 
* 搭建环境:  
  3.5
  * jar
  hibernate3.5\lib\require\*.jar
  antlr-2.7.6.jar-------------------语言转换工具
commons-collections-3.1.jar-------增强java处理集合的能力
dom4j-1.6.1.jar-------------------解析XML
javassist-3.9.0.GA.jar------------Java类提供扩展功能
jta-1.1.jar-----------------------提供标准Java事务处理接口
slf4j-api-1.5.8.jar---------------日志系统
//3.5源代码中没有如下两个jar
hibernate3.4\lib\test\
log4j.jar-------------------------处理日志
slf4j-log4j12.jar-----------------日志系统

hibernate3.5\
hibernate3.jar--------------------核心Jar

数据库驱动
mysqldriver.jar-------------------数据库驱动

  * 配置文件
  * 映射文件(实现映射)User.hbm.xml
  * 配置文件(底层数据库连接信息,hibernate\project\etc\hibernate.cfg.xml)
   
* 配置数据库的连接信息:
hibernate.cfg.xml中 
hibernate3.5/project/etc
查找hibernate.properties文件

* 实体类(领域模型,po  persistenceobject,pojo)


User
uid
username
password

* 实现o(对象)与r(表)的映射
User.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.tarena.demo.po.User" table="t_user">
<id name="uid" column="uid">
<generator class="identity"></generator>
</id>
<property name="userName"></property>
<property name="userPassword"></property>
</class>
</hibernate-mapping>


注释:该映射文件中,class 中的name属性为对象名,table为对象在数据库中对应的表
一般情况下,这些对象都需要ID生成器自动生成一些ID,以便区分各个对象,即<id></id>,同时id里面的
name为对象中的uid,而column为表中的uid
在<property>中,也有name和column属性,对应的也分别是对象中的属性和表中的字段,一般情况下,如果
想User对象中的name属性和t_user表中的name字段是一样的,那么,可以省略掉column,因为hibernate
会自动根据name中的属性在t_user中查找这个属性的字段

* 使用hibernate api 实现数据CRUD的操作
添加User
* 加载映射文件、解析Hibernate配置文件
 Configuration cfg = new Configuration();
 cfg.configur();
* 实例化session工厂
 SessionFactory factory = cfg.buildSessionFactory();
* 开启session
 Session session = factory.openSession();
* 开启事务
 Transaction tr = session.beginTransaction();
* 执行持久化操作
 session.save(object);
* 提交事务
 tr.commit();
* 关闭session
* 关闭session 工厂
 
核心API:Configuration,SessionFactory,
Session,Transaction,Query
注释:Hibernate中的session和servlet中的session有什么区别
1,Hibernate把jdbc封装成了session,即session就是与
数据库的一次会话,也可以说session存储了数据库连接,可以对数据库进行各种操作
这样每次连接数据库就直接用session就行了,
2,也可以理解hernate中的session是Hibernate中的缓存对象,用此session
操作数据库后会缓存返回的结果在session里面,当你再次操作数据库的时候,
如果session里面有相应的值,就直接返回结果,而不用再去数据库里面获取
servlet中的session也是缓存,其缓存用户于服务器之间对话是的一些信息
总之,所有的session都是缓存的作用,就是把一些信息缓存在内存中,方便取值.


总结完整流程: 
* 配置底层数据库连接信息,即配置文件hibernate.cfg.xml
* 创建实体类
* 实现类与表的映射,即映射文件xxx.hbm.xml
* 使用Hibernate中的api实现CRUD操作


使用junit实现CRUD操作


-----------------------day02----------------------------------------
一、Hibernate对对象的管理


对象的状态(生命周期)


1、瞬时状态(瞬态,临时状态,Transient)
User user = new User();
user.setUid(1001);
user.setName("张三");//T
在此之前该对象都是Transient
session.save(user);//P
session.close();
user.setName("李四");//D

临时创建出的一个对象,session没有对该对象
做任何管理,该对象在数据库中没有与之对应的
记录

2、持久态(Persistent)
session 对该对象做了操作
session.save(user);
此时该对象变成Persistent

该对象被纳入到了session的管理(get,load,save
update....),该对象在数据库中有与之对应的
记录,对象的属性值发生变化,数据库会发生联动(
hibernate会发出update语句
)

3、游离态(托管状态 Detached)
该对象没有被纳入到了session的管理(对象不再与
某个session关联),该对象在数据库中有与之对应的
记录


Hibernate中缓存机制
Session的缓存(一级缓存):
当使用session操作对象(保存或更新),
session会将该对象放到缓存中
当使用非list()方法进行查询,session首先到缓存中
查找,如果没有,则发送查询语句到数据库中查找


SessionFactory的缓存(二级缓存):
缓存中数据的生命周期与SessionFactory相同
即使session关闭,数据依然存在缓存中


使用二级缓存:
在hibernate.cfg.xml中配置
* 打开二级缓存的开关 
<property name="hibernate.cache.use_second_level_cache">
true
</property>
* 使用的缓存的类 
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
选择缓存处理的开发商,依赖第三方技术(OsCache,EhCache)
* 搭建EhCache的环境
拷贝hibernate3.5/project/etc/ehcache.xml到src下
hibernate3.5/lib/optional/ehcache/ehcache-1.5.0.jar
提示缺少common.logging jar文件
提示缺少backport-util-concurrent-2.1.jar文件

* 配置选择使用二级缓存的对象
<class-cache 
usage="read-only" 
class="com.tarena.demo.po.User"/>


问题:为什么要使用二级缓存,直接默认session(一级缓存)不行吗?
一级缓存只对当前的session可见,即session级别的缓存,
而二级缓存可以跨越多个session,可以理解成是sessionFactory级别的缓存
属于进程范围或群集范围的缓存,这一级别的缓存可以进行配置和更改,并可以动态的加载和卸载
当一些数据不常发生变化或允许偶尔的并发的时候,二级缓存可能更有效率,而它的缓存时间更久
不会向一级缓存一样,session销毁就跟着销毁
关键是,hibernate为查询结果提供了一个查询缓存,而这个缓存以来于第二缓存


----------------------day03------------------------------
Struts2+hibernate
Struts2:
* 环境
  jar
  配置文件
  struts.xml
  web.xml
  
hibernate
* 环境:
  *.jar
  配置文件
  hibernate.cfg.xml
  映射文件
    antlr-2.7.6.jar
commons-collections-3.1.jar
commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
commons-logging-1.1.jar
dom4j-1.6.1.jar
freemarker-2.3.16.jar
hibernate3.jar
javassist-3.9.0.GA.jar
jta-1.1.jar
log4j.jar
mysqldriver.jar
ognl-3.0.jar
slf4j-api-1.5.8.jar
slf4j-log4j12.jar
struts2-core-2.2.1.jar
xwork-core-2.2.1.jar
asm.jar
backport-util-concurrent-2.1.jar
cglib-2.1.3.jar
  
* 设计数据表结构()
* 设计PO(Emp)
* 创建映射文件
* 配置hibernate配置文件
* 创建HibernateUtils
* 使用过滤器实现OpenSessionInView
* 设计Dao
* 设计Action
* 设计页面


Hibernate映射文件中的type属性
hibernate类型               java类型       数据库类型
integer(java.lang.Integer)  int             int
yes_no                     boolean          char(1)
datetime                   Date             date
timestamp                  Date             timestamp


问题1:mysql不支持事务
修改mysql的默认引擎
mysql/myserver 5.0/my.ini(84行)
default-storage-engine=INNODB 


问题2:运行hibernate应用,提示log4j的警告
拷贝hibernate/project/etc/log4j.properties到项目类路径中
保留该选项log4j.rootLogger=warn, stdout
其它使用"#"注释掉


问题3:框架版本的使用


多表操作:


关系模型中:主外键方式
t_emp
eid name did


t_dept
did name loc
员工1       部门名     工作地点
关联操作
对象与对象之间的关系(对应关系)
一对一   user-----userlogin
一对多
多对多   teacher-----student  
Emp emp = (Emp)load(Emp.class,1);
Dept dept = emp.getDept();
多对一:
* 分析数据之间的对应关系
  员工表Emp与部门表Dept,多个员工对应一个部门,一个部门里有多个员工
* 设计对象模型
Emp{String name,Dept dept}
Dept{int did,String name,Set<Emp> emps}
* 映射文件
Emp.hbm.xml:在Emp的映射文件中,与Dept之间的关系多对一,
<many-to-one name="dept" class="Dept" column="did">


Dept.hbm.xml:在Dept的映射文件中,于Emp之间的关系是一对多
而需要注意的是,Dept的属性中有Emp的set集合emps,所以在创建关系的时候,
需要映射set集合,即这里面利用emps,通过设置inverse="true",
使其维持这种一对多的关系
<set name="emps" cascade="all" inverse="true">
<key column="did" ></key>
<one-to-many class="Emp"/>
</set>
注释:key是表示与Emp关联的对象Dept的键,即可理解为key是t_emp表关联t_dept表的键,

即t_emp表的外键did,所以key可以理解为<one-to-many>中表的外键

       需要解释的是,在这种映射关系之间,集合映射的id要和之前的id保持一致

* 关系(表)模型:
emp(did(fk))
dept(did,name,loc)
-----------------------------day04------------------------------
关联映射:
对象模型
映射方式
关系模型
关联操作:
部门-员工
查询部门,员工信息(最常用)
删除部门,删除员工(不常用)
添加部门,添加员工(可用)
更新部门,更新员工(不常用)
-------------------------------------------
一对一(外键关联)
user-----logininfo
对象模型:
User{uid,name,LoginInfo loginInfo}
LoginInfo{lid,username,password,User user}
Mapping:
主表:
<one-to-one name="loginInfo" class="LoginInfo">
从表:
<many-to-one 
name="user" 
class="User" 
column="uid"
unique="true">


生成关系模型的工具类
Configuration cfg = new Configuration().configure();
SchemaExport export = new SchemaExport(cfg);
export.create(true, true);
---------------------------------------------


一对一(主键关联)
user-----logininfo
对象模型:
User{uid,name,LoginInfo loginInfo}
LoginInfo{lid,username,password,User user}


Mapping:
主表:
<one-to-one name="loginInfo" class="LoginInfo">
从表:
ID生成器:使用foreign,引用其他对象的的主键值,即外键
<id name="lid">
<!--foreign表示依赖外键生成-->
<generator class="foreign">
<!--表示引用user属性对应的表中的主键生成lid-->
<param name="property">
user
</param>
</generator>
</id>
<one-to-one name="user" class="User" constraint="true">
注释:constraint="true" 表示约束,指从表t_logininfo依赖主表t_user
关系模型:
t_user
1001  Jack  
1002  Mike


t_logininfo(lid(pk,fk))
1001  jc   123456
1002  mk   123456


----------------------------------------------


一对多


对象模型
Dept{did,dname,Set<Emp> emps}
Emp{eid,ename,Dept dept}


Mapping:
One方:
<set name="emps">
<key column="did"></key>
<one-to-many class="Emp"/>
</set>
set:映射set集合
key:外键
one-to-many:指定一对多关系
Many方:
<many-to-one name="dept" column="did" 
class="Dept">
</many-to-one>
关系模型:
t_dept(did,dname)
t_emp(eid,ename,did)


---------------------------------------------


多对多
对象模型
Order{Set<Goods> goods}
Goods{Set<Order> orders}
Mapping:


Order.hbm.xml
注释:多对多关联,映射集合的时候,需要一张中间表
<set name="goodses" table="t_order_goods">
注释:key表示与Good关联的对象Order的键,即t_good的外键
<key column="oid"></key>
<many-to-many class="Goods" column="gid">
</many-to-many>
</set>
Goods.hbm.xml 内容同理可知.


table属性:中间表
key:关联对象的键
many-to-many:映射多对多


关系模型:
订单表(t_order)
oid title
1001    电子产品  


t_order_goods
oid  gid
1001 101
1001 102
1002 102


商品表(t_goods)
gid name
101  Ipad          
102  联想笔记本


一对一(Fk,PK)
一对多
多对多
cascade:级联 all,delete,save-update(不用)
fetch:抓取, 取值:select/join
   <many-to-one fetch="select">
   <many-to-one fetch="join">
inverse:一对多中,<set inverse="true">
lazy:
可以在<class><one-to-one><many-to-one><set>元素中出现
<class>:lazy取值false/true
<one-to-one>
<many-to-one>:lazy取值false/proxy/no-proxy proxy:代理对象
<set>:lazy取值true/false/extra
extra:可以发出智能的SQL语句,当获取集合对象的数量,
发出count查询语句,当获取集合对象的属性值,
发出select查询语句
------------------------day05------------------------------
继承映射:
 目的:解决程序中代码的冗余


 两种方案:
  方案一、为每一个对象创建单独的表来实现
  * 对象模型:使用继承的方式,解决代码重复
  * 映射方式:
  <joined-subclass name="子类对象名" table="子类对应表名">
<key column="当前子类的外键(相当于是父类的主键)"></key>
<property name="子类属性1"/>
<property name="子类属性2"/>
</joined-subclass>
 
Product(父类:产品)(父类中包含的是公共的属性)
pid(产品编号)
name(产品名称)
price(产品价格)


Book(子类:书) extends Product
author(作者)
publisher(出版社)


Computer(子类:电脑) extends Product
cpu(处理器)
memory(内存条)


显然,书和电脑是产品的子类,而产品编号,产品名称,产品价格显然是子类的共同属性,
所以设计子类的时候,只需要一些特有的属性,公共属性直接继承父类的就可以了
因此,hibernate中只配置父类的映射文件,子类的映射是用<joined-subclass>属性导入
Product.hbm.xml代码如下:
<hibernate-mapping package="com.tarena.demo.po">
<class name="Product" table="t_product">
<id name="pid" column="pid">
<generator class="identity"></generator>
</id>
<property name="name"/>
<property name="price"/>
<joined-subclass name="Book" table="t_book">
<key column="pid"></key>
<property name="author"/>
<property name="publisher"/>
</joined-subclass>
<joined-subclass name="Computer" table="t_computer">
<key column="pid"></key>
<property name="cpu"/>
<property name="memory"/>
</joined-subclass>
</class>
</hibernate-mapping>




方案二、为所有对象创建一个表
* 对象模型:使用继承的方式,解决代码重复
  * 映射方式:
  <subclass name="子类对象名" discriminator-value="子类的产品类型">
<property name="子类属性1"/>
<property name="子类属性2"/>
</subclass>




Product(只要一个产品表,通过p-type区分不同的产品类型)


pid(产品编号)
name(产品名称)
price(产品价格)
author(作者)
publisher(出版社)
cpu(处理器)
memory(内存条)

类如:下列两个产品,C代表电脑,B代表书籍
pid, name,  price, author, publisher, cpu, memory, p-type
1  联想电脑  4888   null     null      酷睿  二代4g     C
2  莫言文集   88.5  莫言  中国人民出版社  null  null      B
Product.hbm.xml代码如下:
<hibernate-mapping package="com.tarena.demo.po">
<class name="Product" table="t_product">
<id name="id" column="pid">
<generator class="identity"></generator>
</id>
<!-- 生成类型区分字段 -->
<discriminator column="p_type"></discriminator>
<property name="name"/>
<property name="price"/>

<!-- 设置该类型在区分字段中的值 -->
<subclass name="Book" discriminator-value="B">
<property name="author"/>
<property name="publisher"/>
</subclass>
<subclass name="Computer" discriminator-value="C">
<property name="cpu"/>
<property name="memory"/>
</subclass>
</class>
</hibernate-mapping>


One-to-Many中List映射:
映射方式:
<list name="emps" cascade="all">
<key column="did"></key>
<list-index column="t_index" base="0"/>
<one-to-many class="Emp"/>
</list>
注释:<list-index>该属性表示设置标识字段,实现集合排序,
其中column为表中字段,base=0表示从零开始
使用list映射,不支持控制反转依赖关系,即不能由many方维持一对多关系
所以不加inverse=true


组件映射:
减少代码的重复,提高面向对象,因为应用到对象之间的聚合,所以也叫聚合映射
Person类(姓名name)
Address类(城市city,街道street)


在这里,将Address类聚合到Person类中,即Person类(姓名name,地址address)
Person.hbm.xml代码如下:
<hibernate-mapping package="com.tarena.demo.po">
<class name="Person" table="t_person">
<id name="id" column="pid">
<generator class="identity"></generator>
</id>
<property name="name"></property>
<!-- 组件映射 -->
<component name="address">
<property name="street"/>
<property name="city"/>
</component>
</class>
</hibernate-mapping>


表间关联汇总


1、一对一主键关联
主表从表,
从表中:
<id>
<generator class="foreign">
<param name="proerty">user</param>
</generator>
</id>
<one-to-one>
2、一对一外键关联
主表:<one-to-one>
从表:<many-to-one unique="true">
3、一对多双向(必会)
one方:
<set cascade="" lazy="true/false/extra" inverse="">
//关联对象的外键
<key cloumn="lid">
<one-to-many>
</set>
many方:
<many-to-one name="" class="" column="did">
4、多对多双向(必会)
<set name="teachers" table="中间关系表">
 <key column="stuid"></key>
 <many-to-many column="teaid">
</set>
5、继承映射(使用多表)(必会)
父类映射文件中:
<joined-subclass name="Book" table="t_book">
//外键
<key column="pid"></key>
//基本属性
<perperty/>
</joined-subclass>
6、继承映射(使用单表)(必会)
<!-- 生成区分字段 -->
<discriminator column="p_type"></discriminator>
<subclass name="Book" discriminator-value="B">
</subclass>
7、一对多中使用list集合映射
<list>
<key>
//hibernate使用该字段值参考对象在list中的顺序
<list-index column="t_index">
<one-to-many>
</list>
8、组件映射
<component name="">
<property/>
</component>


hibernate中各类查询汇总


/**
* 查询属性
* 查询一个属性,集合中数据的类型为String

*/
@Test
public void test02(){
Session session = HibernateUtils.getSession();
String hql = "select dname from Dept";
Query query = session.createQuery(hql);
List<String> dnames = query.list();
for(String dname:dnames){
System.out.println(dname);
}
HibernateUtils.close(session);
}
/**
* 查询多个属性,集合中数据的类型为Object[]
*/
@Test
public void test03(){
Session session = HibernateUtils.getSession();
String hql = "select did,dname from Dept";
Query query = session.createQuery(hql);
List<Object[]> dnames = query.list();
for(Object[] o:dnames){
System.out.println(o[0]+":"+o[1]);
}
HibernateUtils.close(session);
}
/**
* 查询多个属性,动态构建一个对象
*/
@Test
public void test04(){
Session session = HibernateUtils.getSession();
String hql = "select new Dept(dname) from Dept";
Query query = session.createQuery(hql);
List<Dept> depts = query.list();
for(Dept dept:depts){
System.out.println(dept.getDname());
}
HibernateUtils.close(session);
}
/**
* 简单对象查询
*/
@Test
public void test05(){
Session session = HibernateUtils.getSession();
String hql = "select d from Dept d";
Query query = session.createQuery(hql);
List<Dept> depts = query.list();
for(Dept dept:depts){
System.out.println(dept.getDname());
}
HibernateUtils.close(session);
}
/**
* 对象查询,条件查询
* 参数的顺序从0开始
*/
@Test
public void test06(){
Session session = HibernateUtils.getSession();
String hql = "select d from Dept d where dname=?";
Query query = session.createQuery(hql);
query.setString(0, "部门1");
List<Dept> depts = query.list();
for(Dept dept:depts){
System.out.println(dept.getDname());
}
HibernateUtils.close(session);
}
/**
* 对象查询,条件查询
* 支持方法链编程
*/
@Test
public void test07(){
Session session = HibernateUtils.getSession();
String hql = "select d from Dept d where dname=? and did=?";
//Query query = session.createQuery(hql);
//query.setString(0, "部门1");
//query.list();
List<Dept> depts = 
session.createQuery(hql).
setString(0, "部门1").setInteger(1, 1).list();
for(Dept dept:depts){
System.out.println(dept.getDname());
}
HibernateUtils.close(session);
}
/**
* 查询所有员工信息
* 分页查询
* setFirstResult();确定查询的起点
* setMaxResult();确定查询的条数
*/
@Test
public void test08(){
Session session = HibernateUtils.getSession();
String hql = "from Emp";
int currentPage = 4;
int pageSize = 5;
List<Emp> emps = 
session.createQuery(hql).
setFirstResult((currentPage-1)*pageSize).//起始点
setMaxResults(5).//查询的条数
list();
for(Emp emp:emps){
System.out.println(emp.getEid()+":"+emp.getEname());
}
HibernateUtils.close(session);
}
/**
* 查询所有员工信息
* 查询最大页数
* 首先查询所有记录数
*/
@Test
public void test09(){
Session session = HibernateUtils.getSession();
String hql = "select count(*) from Emp";
List<Long> records = 
session.createQuery(hql).list();
int rec = records.get(0).intValue();
int pageSize = 7;
System.out.println("最大页数是:");
System.out.println(rec%7==0?rec/7:rec/7+1);
System.out.println(rec);
HibernateUtils.close(session);
}
/**
* 使用命名查询
* 将hql语句写在映射文件中
* 查询ID号小于20的员工信息
* from Emp where eid<20
* <query name="findEmpByEid">
<![CDATA[
from Emp where eid<?
]]>
</query>

getNamedQuery(),获取Query对象
*/
@Test
public void test10(){
Session session = HibernateUtils.getSession();
Query query = session.getNamedQuery("findEmpByEid");
query.setInteger(0, 20);
List<Emp> emps = query.list();
for(Emp emp:emps){
System.out.println(emp.getEid()+":"+emp.getEname());
}
HibernateUtils.close(session);
}
/**
* 在hibernate 中使用sql查询
* select * from t_emp;
*/
@Test
public void test11(){
Session session = HibernateUtils.getSession();
SQLQuery query = session.createSQLQuery("select * from t_emp");
List<Object[]> emps = query.list();
for(Object[] obj:emps){
System.out.println(obj[0]+":"+obj[1]);
}
HibernateUtils.close(session);
}

/**
* 实现DML操作
* 删除员工名为员工3的员工信息
*/
@Test
public void test12(){
Session session = HibernateUtils.getSession();
String hql = "delete from Emp where ename=?";
Query query = session.createQuery(hql);
query.setString(0, "员工_1_3");
query.executeUpdate();
session.beginTransaction().commit();
HibernateUtils.close(session);
}
----------------------------END-------------------2013.02.26------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值