hibernate深入浅出详细讲解

本博客为博主自己总结

如有错误请留言或私聊

转载请标注地址~


描述类与数据库的关系
映射配置文件
Customer.hbm.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">
     <!--必须和实体在一个文件下  名字类名.hbm.xml -->
     <hibernate-mapping>
     <!-- class是类全名  tablie是表名  catalog是数据库名 -->
     <class name= "cn.itheima.domain.Customer" table= "t_customer" catalog= "hibernateTest">
    <!-- 配置主键  主键是id所以就配置id 第一个id是类的  第二个是对应的数据库的  column如果不写就会取你的字段名称-->
     <id name= "id" column= "id">
    <!-- 主键生成策略 -->
     <generator class= "native"></generator>
     </id>
     <!-- 第一个name是类的 第二个是对应的数据库的  映射类与表中的字段名-->
     <property name= "name" column= "name" length= "20"></property>
     <property name= "address" column= "address"></property>
     </class>
     </hibernate-mapping>

然后配置这个 hibernate.cfg.xml
核心配置文件 在src下
<?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>
         <!-- 配置关于数据库连接的四个项 driverClass url username password -->
         <property name= "hibernate.connection.driver_class">com.mysql.jdbc.Driver </property>
         <property name= "hibernate.connection.url">jdbc:mysql:///hibernateTest </property><!-- 就是我们的数据库名字 -->
         <property name= "hibernate.connection.username">root </property><!-- 用户名 -->
         <property name= "hibernate.connection.password">abc </property><!-- 密码 -->
         <!-- 设置连接提供者 -->
         <property name= "hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider </property>
         <!-- c3p0连接池的配置 -->
         <property name= "hibernate.c3p0.max_size">20 </property>  <!-- 最大连接池 -->
         <property name= "hibernate.c3p0.min_size">5 </property>  <!-- 最小连接数 -->
         <property name= "hibernate.c3p0.timeout">120 </property>  <!-- 超时 -->
         <property name= "hiberna    te.c3p0.idle_test_period">3000 </property>  <!-- 空闲连接 -->
         <!-- 可以将向数据库发送的sql显示出来 -->
         <property name= "hibernate.show_sql">true </property>
         <!-- 会将sql语句进行格式化 -->
         <property name= "hibernate.format_sql">true </property>
         <!-- hibernate的方言           如果是奥瑞口 就改成奥瑞口 -->
         <property name= "hibernate.dialect">org.hibernate.dialect.MySQLDialect </property>
         <!-- 自动创建表 -->
         <property name= "hibernate.hbm2ddl.auto">update </property>
         <!-- 用于设置事务提交方式 -->
         <property name= "hibernate.connection.autocommit">false </property>
         <!--如果想找到配置的Customer.hbm.xml就必须配置这个   配置hibernate的映射文件所在位置  写的就是xml所在的位置-->
         <mapping resource= "cn/itheima/domain/Customer.hbm.xml" />
     </session-factory>
</hibernate-configuration>    

使用hibernate进行对数据库的操作

// 保存一个Customer对象数据
     @Test
     public  void saveCustomerTest1() {
         try {
             // 创建一个Customer对象
            Customer  c =  new Customer();
             // 添加数据
             c.setName( "张三");
             c.setAddress( "上海");
             // 使用hibernate的api 来完成将Customer的信息直接保存到数据库中
             // 创建这个就会直接加载hibernate.cfg.xml
            Configuration  config =  new Configuration().configure();
             // 得到SessionFactory 就相当于得到核心配置文件的信息
            SessionFactory  sessionFactor =  config.buildSessionFactory();
             // 相当于得到一个与数据库的连接
            Session  session =  sessionFactor.openSession();
             // 开启事务
             session.beginTransaction();
             // 保存操作
             session.save( c);
             // 事务提交
             session.getTransaction().commit();
             session.close();
             sessionFactor.close();
        }  catch (HibernateException  e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
        }
    }

我们开发中一般还是使用 hibernate.cfg.xml方式  原因是他的配置更强 修改方便
1每次都会创建一个新的表 用过之后就自动删除 测试时候用
2每次都会创建一个新表 但是不会删除 测试时候用
3 有就不创建 没有就创建 如果映射不匹配就自动更新
4 只会使用已经存在的表  如果映射关系不对 就会报异常
 
 要是使用hibernate必须先配置映射文件 类名加.hbm.xml 放在实体类所对应的包下面
这个映射主要是声明表与类之间的关系

1.1. 映射文件配置

映射配置文件它的名称是”类名”.hbm.xml,它一般放置在实体类所在的包下。

这个配置文件的主要作用是建立表与类的映射关系。

1. 统一声明包名,这样在<class>中就不需要写类的全名.

2. 关于<class>标签配置

name属性:类的全名称

table 表的名称,可以省略,这时表的名称就与类名一致

catalog属性:数据库名称 可以省略.如果省略,则自动参考核心配置文件hibernate.cfg.xmlurl路径中的数据库名称

3. 关于<id>标签

首先它必须存在。<id>是用于建立类中的属性与表中的主键映射。

name 类中的属性名称

column 表中的主键名称  column它也可以省略,这时列名就与类中属性名称一致

length 字段长度

type属性 指定类型

<generator>它主要是描述主键生成策略.

4. 关于<property>标签

它是描述类中属性与表中非主键的映射关系

 

5.关于hibernate的映射文件中类型问题

对于type属性它的取值,可以有三种:

1. java中的数据类型

2. hibernate中的数据类型

3. SQL的数据类型

 

默认是hibernate中数据类型

 

1. Hibernate常用API介绍

1.1.  Configuration

1.它主要是用于加载hibernate配置.

Configuration config=new Configuration().config ure(); 主要加载src下的hibernate.cfg.xml

Configuration config=new Configuration();主要加载的src下的hibernate.properties

Configuration config=new Configuration().config ure ure不知道该不该加自己百度(核心配置文件名称);加载指定的名称的配置文

修改hibernate.cfg.xml名称为my.xml,单元测试的时候发现报错,修改Configuration加载即可

     // 手动加载映射  
         configure.addResource( "cn/itheima/domain/Customer.hbr.xml");
        //第二种加载映射文件 直接在实体类查找
         configure.addClass(Customer. class);

1.1. sessionFactory

1.首先SessionFactory它的获取是通过Configuration得到。

SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory

2.通过SessionFactory可以得到Session.

是从连接池中获取一个连接。

获取一个与线程绑定的Session.

SessionFactory它不是轻量级的,不要频繁创建关闭它。在一个项目中有一个SessionFactory就可以,通过SessionFactory来获取Session进行操作。



SQLQuery

要想执行本地sql

SQLQuery sqlQuery=session.createSqlQuery(String sql);

使用addEntity方法来将结果封装到指定的对象中,如果不封装,得到的是List<Object[]>

如果sql中有参数,我们使用setParameter方法完成参数传递。

如果结果就是一个可以使用uniqueResult()来得到一个单独对象。
1. 查询全部数据

 

2. 条件查询

 

 

1.1. Criteria

Criteria接口与Query接口非常类似,允许创建并执行面向对象的标准化查询。值得注意的是Criteria接口也是轻量级的,它不能在Session之外使用。

 

首先我想使用Criteria,必须得到Criteria

Criteria criteria=Session.createCriteria()

 

 

查询所有操作

Session.createCriteria(实体类.class)得到一个Criteria对象,调用list查询所有

分页操作与query的方法一样

setFirstResult()    setMaxResults()

条件查询

criteria.add(Restrictions.eq(“name”,”xxxx”));

criteria.add(Restrictions.or(Restricitons.eq(),Restrictions.list()…..))

我们使用Criteria可以更加面向对象去操作,它非常适合进行多条件组合查询。


 hibernate 2

Hibernate持久化类与主键生成策略

Hibernate持久化类

什么是持久化类?

Persistent Object  PO

PO=POJO+hbm映射配置

对于hibernate中的PO编写规则:

1. 必须提供一个无参数的public构造方法

2. 所有属性要private ,对外提供public get/set方法

3. PO类必须提供一个标识属性,让它与数据库中的主键对应,我们管这个属性叫OID

4. PO类中的属性尽量使用基本数据类型的包装类.

Int-àInteger  double--àDouble  float-àFloat

5. PO类它不能使用final修饰符

OID作用:

OID指的是与数据库中表的主键对应的属性。

Hibernate框架它是通过OID来区分不同的PO对象,如果在内存中有两个相同的OID对象,那么hibernate认为它们是同一个对象。

为什么PO类属性它要使用包装类型?

使用基本数据类型是没有办法去描述不存在概念,如果使用包装类型,它就是一个对象,对于对象它的默认值是null.

PO类不可以使用final修饰?(hibernate中的get/load方法的区别)

Get/load方法它们都是根据id去查询对象。

1. get直接得到了一个持久化类型对象,它就是立即查询操作

load它得到的是持久化类开的代理类型对象(子类对象)。它采用了一种延迟策略来查询数据。

2. get方法在查询时,如果不存在返回null

load方法在查询时,如果 不存在,会产生异常

ObjectNotFoundException.

Hibernate主键生成策略

Hibernate中定义的主键类型包括:自然主键和代理主键: 

自然主键:具有业务含义 字段 作为主键,比如:学号、身份证号

代理主键:不具有业务含义 字段作为主键(例如 自增id),比如:mysql自增主键,oracle序列生成的主键、uuid()方法生成的唯一序列串

建议:企业开发中使用代理主键!

Hibernate持久化对象状态

有三种
1 瞬时态 (临时态  自由态)一般就是指我们new出来的对象 无oid 与数据库中的信息无关联  不在session的管理范围内
2 持久态  有oid 由session管理在数据库中 在数据库中有可能有 也有可能没有
3 托管态  (游离态  离线态)失去了与session的关联 存在oid  在数据库中有可能有 也有可能没有
     @Test
     public  void test2(){
        Session  session = HibernateUtils.openSession();
         session.beginTransaction();
         //瞬时态  因为是刚创建对象  无id  没有session关联
        Customer  c= new Customer();
        c.setName( "zhangsan");
         c.setAddress( "河南");
         //当执行save保存的方法时  就建立了与session关系(他就是持久态)(有oid)
         session.save( c);
         //事务开启 
         session.getTenantIdentifier(); 
         session.close();
         //断开了与session的关联 就是(托管态)(有oid)
        System. out.println( c.getId());
    }
}
三种持久化的切换

判断持久化类对象三种状态:

1. 是否有OID

2. 判断是否与session关联

1. 瞬时态(new 出来的)

瞬时------à持久  save   saveOrUpdate

瞬时-----à脱管(游离)  手动设置oid

2. .持久态   它是由session管理

持久-------à瞬时   delete() 被删除后持久化对象不在建议使用

持久-----à脱管  注意:session它的缓存就是所说的一级缓存

evict(清除一级缓存 中指定的一个对象)

clear(清空一级缓存)

close(关闭,也是清空一级缓存)

3. .脱管态   (它是无法直接获取)

脱管-----à瞬时    直接将oid删除

脱管----à持久  update  saveOrUpdate lock(过时)

Hibernate常用API-Session补充

Update

udpate操作它主要是针对于脱管对象,持久对象具有自动更新能力。

问题1:如果我们直接操作的对象是一个脱管对象,执行update会出现什么情况?

Update操作时,如果对象是一个脱管对象,可以操作,它会将脱管对象转换成持久对象在操作

如果在session中出现相同的oid两个对象,会产生异常

问题2脱管对象的oid如果在数据表中不存在,会报异常?

 

所以:在操作中,建议我们通过持久化对象来直接修改其操作。

示例:在单元测试类HibernateTest中创建单元测试方法test6测试update操作

 

saveOrUpdate

 如果对象是一个瞬时对象 --------执行save操作

如果对象是一个脱管对象---------执行update

如果是一个持久对象-------直接返回

delete

删除一个脱管对象,与session关联,在删除

注意:如果执行delete操作,先删除一级缓存,在删除数据库中的数据。

Hibernate关联映射--一对多(多对一)

级联就是保存一个对象  另一个被附带着带走
cascade="save-update"

关联就是你保存我我保存你
要想一个执行就是主要配置inverse="true"
 只能打一的一方配置
双向关联
外键在哪个表就让哪一方来维护这个外键
 
需要在xml里面配置

我们以客户(Customer)与订单(Order)为例


1.实体类创建

创建项目Hibernate-demo3,进行相关的配置

1.1.订单

创建Order类,并实现字段的setget方法

1.2.客户

创建Customer类,实现字段的setget方法

2.Hbm映射文件编写

2.1.Order.hbm.xml

2.2.Customer.hbm.xml

3.测试保存

创建一个单元测试类OneToManyTest,创建单元测试方法test1

上面操作是一种双向关联

问题:我们可不可以只保存订单或只保存客户完成保存操作?

4.测试单向关联保存

4.1.在单元测试类OneToManyTest中创建test2单元测试方法

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: cn.itheima.oneToMany.Customer

…………..

这个异常代表提一个持久化对象关联了一个瞬时对象。

 

4.2.我们可以使用级联操作来解决上述的问题.

4.2.1.我们现在要做的是保存订单时保存客户,需要在订单的hbm配置文件中修改

设置cascade=save-update 那么在保存订单时就可以自动将客户保存。

4.2.2.如果我们要完成保存客户时,保存订单

4.2.2.1.在单元测试类OneToManyTest中创建test3单元测试方法

4.2.2.2.Customer.hbm.xml

5.双向关联维护

我们在开发中要配置双向关联配置。---------可以通过任意一方来操作对方

在操作代码,尽量来要进行单向关联。------可以尽量资源浪费。

在双向关联中,会存在多余的update语句。

我们可以使用inverse属性来设置,双向关联时由哪一方来维护表与表之间的关系。

Customer.hbm.xml

Inverse它的值如果为true代表,由对方来维护外键。

Inverse它的值如果为false代表,由本方来维护外键。

关于inverse的取值:

外键在哪一个表中,我们就让哪一方来维护外键。


cascade总结

使用cascade可以完成级联操作

它可常用取值:

none这是一个默认值

save-update,当我们配置它时,底层使用save updatesave-update完成操作,级联保存临时对象,如果是游离对象,会执行update.

delete 级联删除

delete-ophan 删除与当前对象解除关系的对象。 删除孤儿

all 它包含了save-update  delete操作

all-delete-orphan 它包含了delete-orphanall操作

 

hibername常见笔试题:cascadeinverse有什么区别?

cascade它是完成级联操作

Inverse它只有在双向关联情况下有作用,它来指定由哪一方维护外键。


 
 




 
 
 

猜你喜欢

转载自blog.csdn.net/weixin_39592397/article/details/80857737