在软件的开发中,框架中帮我们实现了一部分功能,使用框架的好处是少写代码就能实现想要的功能。
1.hibernate应用在javaee三层中的dao层框架。
2.hibernate底层就是jdbc,对jdbc实现封装,应用hibernate框架不需要写jdbc代码。
3.hibernate框架实现crud操作:
(1)使用jsbc时候,写sql语句实现。
(2)使用hibernate框架的时候,不需要sql语句实现crud。
1.orm:object relational mapping,对象关系映射。
2.文字描述:
(1)之前web阶段有javabean,更正叫法叫做 实体类。
(2)一般来讲,一个实体类对应数据库表
--让实体类和数据库表进行一一对应关系。
--让类名称和表名称对应
--让类里面的属性和表里面的字段对应
--做操作的时候,不需要使用sql语句操作数据库:
--在hibernate中封装Session对象,调用对象里边的方法实现crud操作;
--只需要操作数据库对应的实体类对象就可以了;
例:
User user=new User();
user.setUserName("Lucy");
user.setPassWord(123);
第一步,导入hibernate的相关jar包;
找jar包的路径:找到zip文件(hibernate版本是5.x):
hibernate-release-5.0.7.final.zip
到lib文件夹中找jar包:
将required中的所有的jar包都导入,
还有jpa文件夹中还有一个jar包,
另外还要导入日志需要的jar包,需要额外导入,包括:
log4j-1.2.16.jsr
slf4j-api-1.6.1.jar
slf4j-log4j12-1.7.2.jar
另外不要忘了导入数据库驱动jar包:
mysql-connector-java-6.0.4-bin.jar
第二步,创建实体类
(1)使用hibernate框架数据库表不需要自己创建,底层会自己创建,因为在配置文件中已经做了相关的配置操作。
第三步, 配置实体类和数据库一一对应关系
(1)映射关系通过配置文件实现,一般都是xml格式配置文件;
(2)创建映射配置文件
--名称位置 没有 固定要求:
--建议:起名称 实体类名称.hbm.xml,
--位置:建议放到实体类包里面。
(3)一般来讲,如果配置文件是xml格式,一般在xml文件中首先引入约束
--常用两种:dtd、schema约束,在hibernate阶段引入dtd约束;
(4)配置一一对应关系
第四步 创建hibernat核心配置文件
(0)在hibernate操作中,只会加载hibernate和兴配置文件,其他配置文件不会加载
--hibernate核心配置文件 名称和位置是 固定
--位置:在src目录下
--名称:hibernate.cfg.xml
(1)配置文件相关部分
(2)配置hibernate信息
(3)配置引入映射配置文件
在映射配置文件中的name属性都是实体类中的相关属性;
column属性是可以省略的,建议写出来。
type属性,设置类型转换(知道),一般不会写,因为底层默认实现。
错误问题:
注意空格问题。
一般都是通过Servlet来进行页面的跳转。更能够看出效果。
1.0 有公开的无参数构造(默认)
2.0 属性私有
3.0 私有属性有公开的set和get方法
4.0 实体类必须有一个属性对应表中的主键
5.0 建议:在实体类属性类型中,一般不写基本数据类型,而写包装类
(1)int-Integer char-Character,其他首字母大写 比如 double-Double
(2)举例说明:
比如 表示学生的分数,int score = 10;
- 比如表示学生得了0分,int score = 0;
- 比如表示学生没有参数考试,int score = 0;
如果使用包装类表示分数
- 表示学生得了0分 Integer score= 0;
- 表示学生没有参数考试,Integer score= null;
>class属性中有很多的值,主要使用其中的两个:
(1)native:根据使用的数据库帮选择使用不同的值;
(2)uuid:-自动生成uuid值
-如果使用uuid,实体类中对应的主键类型应当是varchar类型
写添加代码,每次添加之后,自动添加uuid值。
<hibernate-mapping>
<class name="com.itheima.hibernate.domain.User" table="t_user">
<id name="uid" column="uid">
<generator class="native">generator>
id>
<property name="username" column="username">property>
<property name="password" column="password">property>
class>
hibernate-mapping>
实体类的三种状态:
>瞬时态:对象中没有id,与session没有关联;
>持久态:对象中有id,和session有关系;
>托管态:对象中有id,与session没有关系;
session.saveOrUpdate(user);
注:当user是瞬时态的话,这个方法进行的就是添加的操作,即save(user);
当user是持久态,这个方法进行的就是update(),即进行的就是修改的操作。
(1)之前存储数据到数据库里面,数据库本身是文件系统,
操作文件使用流方式操作,如果数据很多,读写速度很慢;
(2) 缓存的物理介质通常是内存。缓存中的数据是数据存储源中数据的拷贝。
Hibernate 的缓存分为一级缓存和二级缓存, Hibernate 的这两级缓存都位于持久化层, 存储的都是数据库数据的备份。
使用范围:
-session范围.从session创建到关闭的过程中可以使用一级缓存。
-hibernate的一级缓存是默认打开的。
-hibernate的一级缓存中的数据,是持久态的数据。
>一级缓存中的数据都是持久态的数据,能够进行自动更新,即Hibernate 就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。
Hibernate 的持久态对象能够自动更新数据库, 其实就是依赖了一级缓存, 那么一级缓存为什么就可以去更新数据库了呢, 其实是因为一级缓存的一块特殊的区域就是快照区。
缓存文字描述分析:
(1)在代码中,创建session对象,
- 在session有一级缓存,一级缓存有对应快照区(副本)
(2)调用get方法查询,首先到一级缓存中找数据,第一次没有数据,查询数据库,查询数据库之后返回user对象(持久态),把持久态对象放到一级缓存中
(3)向返回user对象里面设置值
- 同时修改一级缓存中内容
(4)一级缓存快照区
-查询数据库把持久态对象放到一级缓存中,同时放到对应快照区里面
- 修改一级缓存中内容,不会修改快照区内容
- 提交事务比较做什么操作
Hibernate 向一级缓存放入数据时, 同时复制一份数据放入到 Hibernate 快照中, 当使用 commit()方法提交事务时, 同时会清理 Session 的一级缓存, 这时会使用 OID 判断一级缓存中的对象和快照中的对象是否一致, 如果两个对象中的属性发生变化, 则执行 update 语句, 将缓存的内容同步到数据库, 并更新快照; 如果一致, 则不执行 update 语句。 Hibernate 快照的作用就是确保一级缓存中的数据和数据库中的数据一致。
(1)一组操作,要么都成功,如果有一个失败所有都失败
(1)原子性:要么都成功,如果有一个失败所有都失败
(2)一致性:操作之前和之后,总量不变的
- 转账例子
-- 小王转账1000给小马
-- 小王少1000,小马多1000
(3)隔离性:多个事务之间不互相影响
(4)持久性:提交事务之后,数据库表数据真正生效了
(1)脏读
(2)不可重复读
(3)虚读
1)mysql默认隔离级别
<property name="hibernate.connection.isolation">4property>
(1)类似于jdbc中Connection连接
(2)调用session对象里面的方法实现crud操作
(3)Session特点:单线程对象
- 这个session对象不能被多个人共同使用,只能是一个人使用
在hibernate中通过配置文件,实现了session是单线程。
(1)在hibernate核心配置文件中进行配置
- 含义:打开与本地线程绑定session
<property name="hibernate.current_session_context_class">threadproperty>
(2)调用sessionFactory的方法得到与本地线程绑定session
(3)如果使用的是与本地线程绑定的session,即在配置文件中进行了相关配置后获得的Session,最终不需要关闭
1 一对多建表原则:
(1)在多的那一方创建字段作为外键,指向一的那一方主键 (一般外建都是以对象的形式存在于实体类中)
2 多对多建表原则:
(1)创建第三张表,至少有两个字段,这两个字段作为外键,指向两个表主键
1.第一步:创建客户和联系人的实体类;
在客户实体类中写上它的属性,其中有一个属性要和对应的表中的主键对应;
创建联系人实体类;
2.第二步:在实体类中,让客户和联系人互相表示关系;
>一个客户里面有很多的联系人;用集合表示所有的联系人,在hiabernate中使用set集合(不用list集合)。
private Set<LinkMan> set=new HashSet<LinkMan>();
>一个联系人属于某个客户;使用对象形式表示。
private Customer customer;
3.第三步:配置映射关系;
>一般来讲,一个实体类对应一个映射文件;
>创建客户和联系人映射文件;
>在映射文件中配置一对多关系;
- 在客户映射文件中配置所有的联系人
<set name="setLinkMan" cascade="save-update,delete" inverse="true">
<key column="clid">key>
<one-to-many class="com.itheima.hibernate.entity.LinkMan"/>
set>
- 在联系人映射文件中配置所属客户
<many-to-one name="customer" class="com.itheima.hibernate.entity.Customer" column="clid">many-to-one>
4.第四步:把映射文件引入到核心配置文件中。
<mapping resource="com/itheima/hibernate/entity/Customer.hbm.xml"/>
<mapping resource="com/itheima/hibernate/entity/LinkMan.hbm.xml"/>
1 级联操作:操作多个表有关系数据
(1)级联保存
- 添加一个客户,为这个客户添加多个联系人
(2)级联删除
- 删除一个客户,同时把客户下面所有的联系人也删除
原来添加需要在客户中添加联系人Set集合,在联系人中添加Customer对象。
但是及练操做,只是通过添加客户,系统会将对应联系人添加到数据库。
实现步骤
第一步 在客户映射文件中配置,在set标签中配置
(1)cascade属性值 save-update
<set name="setLinkMan" cascade="save-update" inverse="true">
set>
第二步 在代码中写法简化
(1)创建两个实体类对象
(2)只需要把联系人放到客户里面就可以了
customer.getSetLinkMan().add(linkMan);
session.save(customer);
(3)最终保存客户就可以了
级联删除:
第一步 在客户映射文件中进行配置
(1)在set标签使用属性cascade值delete
<set name="setLinkMan" cascade="save-update" inverse="true">
set>
第二步 在代码中查询调用delete方法删除
Customer customer = session.get(Customer.class, 1);
session.delete(customer);
双方维护外键。
(1)造成有多余语句输出
(1)使用inverse属性配置
<set name="setLinkMan" cascade="save-update,delete" inverse="true">
set>
(1)如果做级联删除操作时候,只把inverse属性设置true,但没有配置cascade属性值delete,删除时候出现异常
(2)结论:如果添加inverse属性是true,做级联删除,cascade属性值必须配置delete
<set name="setLinkMan" cascade="save-update,delete" inverse="true">
set>