目录
2. SessionFactory:(session工厂) 4
hibernate工作在dao层负责和数据库的交互,应用它之前需要先创建表对象,用来封装数据,之后要敬请映射xml的配置,在映射配置里应用class标签配置类和表的映射,name属性配置类的全限定名,table属性配置表的名称,catalog属性是配置数据库,因为在核心文件里已经配置这里可以不配置,应用id标签配置主键name属性配置属性的名称 column配置表中主键属性的名称,id标签中generator标签用来配置主键生成策略,我们常用的class属性值是native(本地的)和uuid(字符串),property标签用来配置普通的属性和字段的映射,name属性名,column字段名,其中还有not-null="true"非空和unique="true"唯一,映射关系配置完后,配置hibernate的核心配置文件,其中配置hibernate的基本环境参数,其中要配置数据库的四个基本参数,数据库方言,显式sql和格式化sql,自动建表,整合c3p0,设置事物隔离级别,开启事物,基本环境搭建成功,下面就是使用,在dao层类中调用api使用,configuration用来初始化hibernate和加载配置文件,获取sessionFactory,它用来管理session,获取session,内置了一个数据源,是一个重量级对象,所以就像连接池一样建立一个工具类,用的时候,调用它就行。session是执行者,他可以进行增删改查的操作,还可以开启事物。为了线程安全,我们需要把当前的session绑定到当前的线程中,所以要在hibernate核心配置文件中,配置隔离级别,开启事物,并在工具类中用sessionFactory返回一个绑定线程的session,之后我们就可以进行操作了,增删改save,delete,update,查有五种方式,看下边,多表的话要在映射文件中配置多表关系,在1的映射文件上配置set标签,在&的映射文件上配置many-to-one标签。。。
Hibernate
Hibernate简介
hibernate是一个工作在dao层的框架,他良好的对JDBC进行了封装,使用了面对对象的思想操作数据库,可以自动生成sql语句,并执行。
Hibernate环境搭建
-
映射配置文件:
- 1.1 简介
作用:解释表和对象类之间关系
基本说明:
名称(理论上可以随便写): 建议类名.hbm.xml
-
1.2 映射配置介绍
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPE hibernate-mappingPUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="hibernate_day1.domain.Customer"table="cst_customer">
<idname="cust_id"column="cust_id">
<generatorclass="native"/>
</id>
<propertyname="cust_name"column=""/>
<propertyname="cust_source"/>
</class>
</hibernate-mapping>
class标签:(建立类和表的映射)
name属性: | 类的全限定名(项目里的相对位置) |
table属性: | 表名(若表名和类名一样的话,可以省略不写)(如果没有表的话可以在核心配置文件中写一个自动创建的属性,自动创建表) |
catalog: | 数据库的名称 (在核心配置文件中已经配置了,这里可以省略,如果两个都写了,以这个为主 ) |
id标签:(class标签中,主键和属性的映射在)
name属性: | 对象里属性的名称 |
column属性: | 数据库里的字段名称 (主键名) |
lenth属性: | 字段的长度,如使用hibetnate生成表的时候lenth就要起做用了 (不写会有默认值) |
type属性: | 字段的类型,如使用hibetnate生成表的时候type就要起做用了 ;支持java类型,数据库类型,hibernate类型(默认),不写的话会根据class标签绑定的类的字段类型生成hibernate类型 |
generator标签:(id标签中,主键生成策略)
主键的分类: | ☆代理主键:使用对象的一个毫无业务意义的属性作为主键。(以后用这个) 自然主键:使用对象的一个有业务意义的属性作为主键。(不常用)(如身份证) |
class属性: | 策略值 1.increment:使用的hibernate的自增策略,类型必须为整数,只适合在单线程用,因为他执行时是先查询id的最大值,将该条最大值加一设置为新的id 如果两条同时插入,会重复,线程不安全 2.identity:hibernate使用的是数据库的自增策略,类型必须为整数。代表:mysql 3.sequence:hibernate使用的是数据库的序列策略,类型必须是整数。代表:oracle 4.☆☆native:hibernate会检查我们使用的数据库支持什么策略就使用什么策略,对于我们来说不是identity就是sequence。(native单词的意思是 本地) 5.☆uuid:hibernate使用随机的字符串作为id 6.assigned:放弃hibernate的主键维护,自己手动的set进id |
property标签:(class标签中,普通字段和属性的映射)
name属性: | 对象里普通属性名称 |
column属性: | 数据库里的普通字段名称 |
lenth属性: | 字段的长度,如使用hibetnate生成表的时候lenth就要起做用了 (不写会有默认值) |
type属性: | 字段的类型,如使用hibetnate生成表的时候type就要起做用了 ;支持java类型,数据库类型,hibernate类型(默认),不写的话会根据class标签绑定的类的字段类型生成hibernate类型 |
not-null属性: | true false 是否非空 |
unique属性: | 是否唯一 |
-
核心配置文件
- 1.1 简介
作用:配置hibernate的环境的参数,基本信息,属性配置,加载映射文件(用mapping标签里的resource属性加载)
基本说明:
2.格式1;hibernate.properties(不能加载映射文件)
3.格式2:hibernate.cfg.xml (主要使用这个)
-
1.2 映射配置介绍
-
1. 导入约束文件
位置在:Web App Libraries下的hibernate-core- /org.hibernate/hibernate-configuration-3.0.dtd
-
-
进行数据库的4个基本属性配置( 驱动,数据库地址,用户名,密码 )
位置在:在解压出来的 hibernate-release-5.0.7.Final\project\etc\hibernate.properties里面找
-
设置hibernate的属性配置( 数据库方言,显式sql,格式化sql,有hibernate自动生成语句,整合c3p0,设置事物 )
位置在:在解压出来的 hibernate-release-5.0.7.Final\project\etc\hibernate.properties里面找
-
加载映射文件
<?xmlversion="1.0"encoding="UTF-8"?>
<!--导入约束条件
位置在:Web App Libraries下的hibernate-core- /org.hibernate/hibernate-configuration-3.0.dtd
-->
<!DOCTYPE hibernate-configurationPUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 要进行三个配置
配置内容:
4个基本参数
hibernate的属性配置
映射文件加载
-->
<!-- 第一个:四个基本参数 驱动,数据库地址,用户名,密码-->
<!-- 在解压出来的 hibernate-release-5.0.7.Final\project\etc\hibernate.properties里面找 -->
<propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<propertyname="hibernate.connection.url">jdbc:mysql:///hibernate_day1</property>
<propertyname="hibernate.connection.username">root</property>
<propertyname="hibernate.connection.password">liqichen</property>
<!-- 第二个:hibernate的属性配置-->
<!-- 必须得有的属性 数据库方言-->
<propertyname="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!--是否显示sql语句 -->
<propertyname="hibernate.show_sql">true</property>
<!-- 是否格式化sql语句 -->
<propertyname="hibernate.format_sql">true</property>
<!-- 是否由hibernate生成建表语句(ddl语句),及如何生成
常见值:
create 由hibernate生成建表语句,若之前表存在,先删除表,在创建表 (一般测试用)
create-drop 由hibernate生成建表语句,若之前表存在,先删除表,在创建表,若彻底使用完后删
除表 (测试使用)
update 若之前表存在,直接更新使用;若之前没有该表,先创建在使用
validate 使用的时候先校验映射文件和表是否对应,若对应直接使用,若对应不上就会抛异常
-->
<propertyname="hibernate.hbm2ddl.auto">update</property>
<!-- 配置C3P0连接池 -->
<propertyname="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<propertyname="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<propertyname="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位,
如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<propertyname="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
<propertyname="c3p0.idle_test_period">3000</property>
<!-- 设置事务的隔离级别 -->
<propertyname="hibernate.connection.isolation">4</property>
<!-- 开启与线程绑定的session -->
<propertyname="hibernate.current_session_context_class">thread</property>
<!-- 第三个:映射文件的加载 -->
<mappingresource="hibernate_day1/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Api内置对象
-
Configuration:配置对象
作用:
1.加载核心配置文件
new Configuration() 默认加载的是src目录下的hibernate.Properties
new Configuration().configure(); 默认加载的是src目录下的hibernate.cfg.xml
new Configuration().configure(path); 如果不在src下使用
2.创建sessionFactory
configuration.buildSessionFactory();
3加载映射文件
若配置文件为properties或者在xml文件中没有加载映射文件,可以通过addResource方法加载映射文件
-
SessionFactory:(session工厂)
作用:
注意:这是一个重量级的对象:创建和销毁时特别消耗时间,一般一个项目只有一个SessionFactory对象
4抽取一个工具类:(sessionfactoy 只需要创建一次获取session)
4.1普通工具类 (utils)
public class HibernateUtils {
private static final Configuration config;
private static final SessionFactory factory;
static{
config=new Configuration().configure();
factory = config.buildSessionFactory();
}
public static Session openSession(){
return factory.openSession();
}
}
4.2事物工具类 (utils)
在核心配置文件配置后
publicclass HibernateUtils {
privatestaticfinal Configuration config;
privatestaticfinal SessionFactory factory;
static{
config=new Configuration().configure();
factory =config.buildSessionFactory();
}
publicstatic Session getCurrentSession(){
returnfactory.getCurrentSession();
}
}
-
Session
作用:
1.开启事物
session.beginTransaction();
-
和数据库交互
增删改查
Hibernate的五种检索方式
1. 对象图导航检索
对象图导航检索就是,在一对多的情况下,每一个&对象都对应一个1,可以通过session获取指定的&对象,再通过&对象获取包含的那个唯一的1
例:LinkMan linkMan = (LinkMan)session.get(LinkMan.class,1L);
Customer customer = linkMan.getCustomer(); -
-
OID 检索方式
就是知道了对象的id,直接用session的get(),load()方法来找到对象
例:Customer customer = (Customer )session.get(Customer.class,1);
Customer customer = (Customer )session.load(Customer.class,1); -
HQL 检索方式
HQL是面向对象的查询语言,和sql有些相似,但是HQL中的概念是操作类,对象,对象和属性,Hibernate提供了Query接口,是专门的HQL查询接口,完整的HQL语句结构如下
select…from…where…group by…having…order by…asc/desc
在检索所有的记录时,可以省略select,要注意的是这里检索的是类名,类名是要区分大小写的,关键字不区分
检索方式:
基本查询:
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();别名查询:
Query query = session.createQuery("from Customer c");
Query query = session.createQuery("select c from Customer c");排序查询:
Query query = session.createQuery("from Customer order by cust_id desc");
条件查询:
按位置绑定参数 :Query query = session.createQuery("from Customer where cust_name = ?");
query.setParameter(0, "小军军");按名称绑定参数 :Query query= session.createQuery("from Customer where cust_name = :name");
query.setParameter("name", "小添添");分页查询:
Query query = session.createQuery("from LinkMan order by lkm_id desc");
query.setFirstResult(5);
query.setMaxResults(5);统计查询:
Query query = session.createQuery("select count(*) from Customer");
Long num = (Long) query.uniqueResult();投影查询:
查询一列(一个字段)
List<String> list = session.createQuery("select cust_name from
Customer").list();查询多列 (多个字段)
List<Object[]> list = session.createQuery("select cust_id,cust_name from
Customer").list();构造方式查询(查询并封装对象)
//封装函数要有对应的构造函数 而且参数顺序不可乱
List<Customer> list = session.createQuery("select new
Customer(cust_id,cust_name) from Customer").list(); -
QBC 检索方式
检索方式:
基本查询:
Criteria criteria=session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
条件查询:
//创建查询容器
Criteria criteria=session.createCriteria(Customer.class);
//创建查询条件
Criterion criterion=Restrictions.eq("cust_name", "慢慢");
//添加查询条件进入到容器
criteria.add(criterion);
List<Customer> list=criteria.list();
分页查询:
criterion.setFirstResult(1);
criterion.setMaxResults(5);
排序查询:
criteria.addOrder(Order.desc("cust_id"));
统计查询:
criteria.setProjection(Projections.rowCount());
long count=(long)criteria.uniqueResult();
离线条件检索:
//离线查询DetachedCriteria类是一个脱离session的查询容器
//可以再其他的层对条件进行过滤封装
//最后到了dao层在与session绑定
创建DetachedCriteria类
DetachedCriteria detachedCriteria=DetachedCriteria.forClass(Customer.class);
绑定条件这里可以判断非空
detachedCriteria.add(Restrictions.eq("cust_name", "慢慢"));
添加session关联
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
-
SQL 检索方式
SQLQuery sqlQuery=session.createSQLQuery("select c.cust_id from cst_customer c");
Hibernate的多表关系
1. 简介
多表的关系在数据库中是表与表之间的关联,而在hibernate中,用对象的思想对其进行了描述,在hibernate中的关系,主要靠实体类的包含,和,映射文件的描述
2. 一对多(1里放集合)(&里放对象)
- 2.1 实体类中关系的实现:
1—>&(一对多的一方)
在(一)的一方的实体类中放入(多)的一方的对象集合 以表示(一)的一方有多个(多)的对象
&—>1(多对一的一方)
在(多)的一方的实体类中放入(一)的一方的一个对象 以表示(多)的一方只对应一个(一)的一方
- 2.2 映射文件中关系的描述
1—>&
<setname=""><!-- 因为一的一方包含多的一方的集合 所有配置文件以集合作标签 name表示集合的名字 -->
<keycolumn=""/><!--key标签的 column表示外键的名称 -->
<one-to-manyclass=""/><!--一对多 class 表示多的一方的实体类的全限定名-->
</set>
&—>1
因为在多的一方包含一个多的对象,直接用关系标签,再用三个属性指定,对象名、外键和位置
<many-to-onename=""class=""column=""/>
-
2.3 入门测试
//创建一的对象
Customer customer1=new Customer("李总");
//创建多的对象
Linkmanl1=new Linkman("李密");
Linkmanl2=new Linkman("王密");
//往一的一方添加多的对象 创建关系
customer1.getLinkmans().add(l1);
customer1.getLinkmans().add(l2);
//往多的一方添加一的对象 创建关系
l1.setCustomer(customer1);
l2.setCustomer(customer1);
//保存
session.save(customer1);
session.save(l1);
session.save(l2);
3. 多对多(彼此往里放集合)
- 3.1 实体类中关系的实现
在彼此的实体类中加入包含彼此对象的集合
-
3.2 映射文件中关系的描述
<!-- 配置关联映射
name属性:对方的集合的属性名称
table属性:中间表表名
-->
<setname=""table="">
<!-- column:自己在中间表中的外键名称-->
<keycolumn="role_no"/>
<!--
class属性:对方的全限定名
column属性:对方在中间表中的外键名称
-->
<many-to-manyclass=""column=""/>
</set>
注意:
开发中让被动方放弃外键维护权
在角色的set标签上配置inverse="true"
-
3.3 入门测试
//创建两个用户
User u1 = new User();
u1.setUser_name("曼曼");
Useru2 = new User();
u2.setUser_name("小小");
//创建3个角色
Roler1 = new Role();
r1.setRole_name("员工");
Roler2 = new Role();
r2.setRole_name("助教");
Roler3 = new Role();
r3.setRole_name("讲师");
//双向关联
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r1);
u2.getRoles().add(r3);
r1.getUsers().add(u1);
r1.getUsers().add(u2);
r2.getUsers().add(u1);
r3.getUsers().add(u2);
//保存
session.save(u1);
session.save(u2);
session.save(r1);
session.save(r2);
session.save(r3);
4. 级联:(牵一发而动全身)
级联是有方向性的,也就是你动谁,谁就是主体,在主体的映射文件中配置对象关系的标签最外层加cascade=""属性 里边的值是你要做什么操作,多个操作中间用,隔开
例:
保存或更新(值save-update)
☆级联保存或更新
保存客户的同时,也保存关联的联系人
客户是主体,在主体的映射文件中配置级联保存更新 set标签配置 cascade=
"save-update"
保存联系人的同时,也保存关联的联系人
联系人是主体,在主体的映射文件中配置级联保存更新 many-to-one标签配置cascade="save-update"
删除(值delete)
级联删除:(删一个全删)
☆删除客户的同时,也删除他的联系人(先查询)
客户是主体,需要在客户的映射文件中配置级联删除cascade="delete"
删除联系人时也删除对应的客户
联系人是主体,在联系人的映射配置文件中配置级联删除
☆默认删除:(删除1的时候置&为null)
删除一的一方的记录时:会先把多表中关联的记录的外键置为null,在删除
一表中的数据,商品(多)一方 无分类 , 分类(一)一方 删除
在多表中,谁是主体配置谁,操作谁,谁就是主体
5. 冗余sql(多余sql)
解决方法:
方案1:单向关联
方案2:让其中一方放弃外键维护权 (让一的一方放弃外键维护权) 在set标签上配置 inverse="true"
Hibernate中的多表查询
内连接、
隐式内连接:
显式内连接:
☆迫切内连接:
迫切就是将每一条记录都封装成一个对象
使用:在jion后边加上fetch
* 迫切内连接就是把查询到的所有客户的信息都封存到了每个对应的Customer对象中 联系人的信息封存到了Customer的集合中
* 内连接是每用到一个客户的信息 发送一次sql 迫切内链接 是一次全查了
*
* 迫切内连接要去重查询 distinct
外链接
左外连接
右外链接
迫切左外连接
Hibernate的优化
- 1. 延迟加载
* 他决定什么时候发送sql语句
* 1.1类级别的延迟加载
* 获取一个对象的时候是否采用延迟加载
* 关闭类级别的延迟加载
* 1.在持久化类上使用final修饰
* 2.在配置文件中修改 class标签上 lazy=false
* 1.2关联级别的延迟加载
* 通过一个对象获取其关联对象的时候是否采用延迟加载
* 通过lazy属性配
* 在set标签上配置
* true:使用延迟加载 默认值
* false:不使用延迟加载
* extra:及其懒惰的
* 在many-to-one上配置
* false:不使用延迟加载
* proxy:代理 默认值 (决定于1的一方)
-
2. 抓取策略(查询关联对象的时候,用什么sql格式)
决定的是 sql的格式
通过fetch属性配置
2.1在set标签上配置
值
Select:发送普通的查询语句
Join:发送一条迫切左外连接语句 lazy失效了
Subselect:发送一条子查询语句
2.2在many-to-one
值
Select:发送普通的查询语句
Join:发送一条迫切左外连接语句 lazy失效了
- 3. 批量抓取
作用: (一次查询几个)
查询多个对象的多个关联对象产生的n+1问题
查询所有客户及其联系人的名称
在set标签上配置 batch-size=int
一次查询几个客户的联系人
查询联系人名称及其客户的名称
在一的一方的class标签上配置batch-size=int
一次查询几个客户
持久化类
-
简介
一个类可以持久化到数据库中就是持久化类,就是一个javabean有了映射文件(就是javaBean)
持久化类编写规范:
1.必须是一个公共的具体的类
2.字段必须私有,必须提供公共的访问方法
3.必须有一个无参构造器
4.必须有一个属性(OID)和主键字段对应
5.尽量使用包装类修饰字段(包装类有null,基本类型为0)
6.尽量不要使用final修饰类 因为不能继承 许多功能就失效了
-
持久化对象的三种状态
1.瞬时态:没有oid且没有与session关联 (刚创建对象)
2.持久态:有oid且和session关联 (session加入缓存操作的过程)
3.托管态:有oid且和session失去关联,与数据库产生关联 (保存之后)
☆注意:
持久化对象可以自动更新数据库 (依赖于一级缓存)
例如 session.get 获取之后 通过set修改
一级缓存
缓存:介于程序和硬件之间的一种介质
作用:减少对硬件的访问
☆一级缓存:是hibernate自带的,不能卸载的。Session的生命周期和一级缓存的生命周期一样,所以也称之为是session级别的的缓存
二级缓存:不是hibernate自带的,用的时候(chcache),需要导入jar包,还需要配置文件等等一系列操作,一般使用redis代替
一级缓存依赖的或者说本质就是一系列集合
一级缓存可以分为两部分(缓存区和快照区)
放入一级缓存的时候,会将数据放入缓存区一份,也会放入快照区一份,快照区就是方放入缓存区的状态
操作的过程中只操作缓存区
当事物提交的时候对比缓存区和快照区是否一致
一致:啥也不操作
不一致:马上发送update语句