文章目录
概述
JavaEE三层结构
客户端层 JavaApplet,Html,CSS,JS
web层 Servlet,JSP Struts2,SpringMVC,WebWork
业务逻辑层 EJB Spring
持久层 JDBC Hiberate,Mybatis,DBUtils,JdbcTemplate
以上过于底层,故企业中使用SSH(Struts+Spring+Hiberate)、SSM(SpringMVC+Spring+Mybatis)
Hibernate概述
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。
Hibernate是一个持久层的ORM框架
什么是ORM
Object Relational Mapping对象关系映射,指的是将java中的对象与关系型数据库中的表建立一种映射关系,对而操作对象就可以操作数据库中的表
入门
开发环境
Hibernate3,Hibernate4.x(兼容性不好),Hibernate5.x
lib目录 Hibernate开发包
required 必须的依赖包
optional 可选的jar包
创建项目,引入jar包
- 数据库驱动包 mysql
- Hibernate开发的必须jar包 Hibernater
- Hibernate引入日志记录包 log4j
创建表
创建实体类
创建映射
通过XML,可任意命名。
Hibernate命名规范:类名.hbm.xml
在xml中增加约束:在org.hibernate的hibernate-mapping.dtd中找到并拷贝过来
//建立映射
<class name=“全路径类” table=“表名“>
//表示主键本地生成
<property name=成员变量” column=“字段”/>
创建Hibernate核心配置文件
hibernate.cfg.xml
在src目录下新建
同样添加约束(在hibernate-configuration.dtd中找)
<mapping resource="hbm.xml的全路径">//这里全路径用/,不用.
</session-factory>
上述property有4个,driver_class、url、username、password,属性名和类名在hibernate.property中找
编写测试类
1.加载Hibernate的核心配置文件
Configuration configuration = new Configuration().configure();
2.创建一个SessionFactory对象,相当于JDBC中的连接池
SessionFactory sessionFactory = configuration.buildsessionFactory();
3.通过SessionFactory获取到Session对象,相当于JDBC中的Connection
Session session = sessionFactory.openSession();
4.手动开启事务
Transaction transaction = session.beginTransaction();
5.编写代码
Customer = customer = new Customer();
customer.setCust_name(“eee”);
session.save(customer);
6.事务提交
transaction.commit();
7.资源释放
session.close();
sessionFactory.close();
Hibernate常见配置
XML的提示配置
Hibernate映射的配置
class标签的配置:
用来建立类与表的映射关系
属性name:表示类的全路径
table:表示表名(表名与类名一致时,table可以省略)
catalog:数据库名
id标签的配置:
用来建立类中的属性与表中的主键的对应关系
name:类中的属性名
column:表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)
length:长度
type:类型(可不写,会自动转换)
property标签的配置
用来建立类中的普通属性与表的字段的对应关系
name
column
length
type
not-null
unique
Hibernate的核心配置
必须的配置:
连接数据库的基本参数:驱动类、url路径名、用户名、密码
方言
可选的配置:
显示sql:hibernate.show_sql
格式化sql:hibernate.format_sql
自动建表:hibernate.hbm2ddl.auto
none:不使用hibernate自动建表
create:如果数据库中已有表,删除原有类,重新创建,如果没有则新建表
create-drop:如果数据库中已有表,删除原有表,执行操作,再删除这个表;如果没有,新建表,使用完了删除该表
update:如果数据库中有表,使用原表,如果没有表,创建新表(更新表结构)
validate:如果没有表,不会创建表,只会使用数据库中原有的类(校验映射和表结构是否一致)
映射文件的引入:
引入映射文件的位置
两种方式:
1.属性文件的方式
属性文件方式不能引入映射文件(手头编写代码加载)
2.XML文件的方式
hibernate.cfg.xml
核心API
Configuration
Hibernate配置对象,对Hibernate进行配置和启动。
作用:
1.加载核心配置文件
hibernate.properties
Configuration cfg = new Configuration();
hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
手动加载映射
cfg.addResource("");
2.加载映射文件
SessionFactory
负责初始化Hibernate,是数据存储源的代理,负责创建Session对象
内部维护了Hibernate的连接池和二级缓存。线程安全
一个项目只需要创建一个
可抽取工具类
HiberateUtils
Session
负责执行被持久化对象的CRUD操作,与数据库交流,内部维护一级缓存,非线程安全
保存
Serializable save(Object obj);
查询
T get(Class c, Serializable id);
get和load的区别:
get采用的是立即加载,会马上发送SQL语句去查询,查询找不到的对象时返回null
load采用的是延迟加载,当真正使用这个对象的时候才会发送SQL语句,当时返回的是代理对象。javassist.jar利用javassist技术产生的代理,查询找不到的对象,返回ObjectNotFoundException
修改
update(Object obj);
推荐的是先get,再update,确保避免把其他属性覆盖掉
删除
delete(Object obj);
如果是作级联删除,需要先get,再delete
保存或更新
saveOrUpdate()
查询所有
接收HQL:Hibernate Query Language,面向对象查询语言
Query query = session.createQuery(“from Customer”);
List list = query.list();
接收SQL
SQLQuery query = session.createSQLQuery(“select * from customer”);
List<Object[]> list = query.list();
Transaction
Hibernate中管理事务的对象
Commit();
Rollback();
持久化类的编写规则
持久化:将内存中的对象持久化到数据库中的过程
持久化类:java类+映射文件
编写规则:
1.无参数的构造方法
Hibernate底层通过反射生成实例
2.属性需要私有,同时提供public的get和set方法
3.提供一个唯一标识OID与数据库主键对应
4.属性尽量使用包装类类型
5.不要使用final修饰,与延迟加载有关,如果定义为final,load与get就没有区别
主键的生成策略
主键的分类
自然主键
主键的本身就是表中的一个字段(实体中的一个具体属性)
代理主键
不是表中的必须字段
尽量使用代理主键
一旦自然主键参与到业务逻辑中,后期有可能需要修改源代码
生成策略
一般不允许用户手动设置主键,一般将主键交给数据库
increment:hibernate中提供的自动增长机制,适用于short、ing、long类型的主键。在集群中不要使用,在单线程程序中使用
首先先发送一条语句:select max(id) from 表; 然后让id+1作为下一条记录的主键
identity:适用于short、ing、long类型的主键。使用的是数据库底层的自动增长机制,适用于有自动增长机制数据库(MySQL,MSSQL),但Oracle没有自动增长机制
sequenc:适用于short、ing、long类型的主键,采用的是序列的方式。Oracle支持序列,MySQL不支持
uuid:适用字符串类型主键,使用hibernate中的随机方式生成字符串主键
native:本地策略,可以在identity和sequence之间进行自动切换,不用管底层是mysql还是oracle
assigned:hibernate放弃处理的管理,需要通过手动编写程序或用户自己设置
foreign:外部的。一对一的一种 关联映射的情况下使用。
持久化类的三种状态
瞬时态transient
这种对象没有唯一的标识OID,没有被session管理
持久态persistent
这种对象有唯一的标识OID,被session管理
可以自动更新数据库
脱管态detached
这种对象有唯一的标识OID,没有被session管理
状态转换
瞬时态对象
获得: Customer customer = new Customer();
瞬时 到 持久:save() saveOrUpdate()
瞬时 到 脱管:customer.setCust_id(1);
持久态对象
获得:get() load() find() iterate()
持久 到 瞬时:delete();
持久 到 脱管:close() clear() evict(obj)
脱管态对象
获得:Customer customer = new Customer();customer.setCust_id(1);
脱管 到 持久:update() saveOrUpdate()
脱管 到 瞬时:customer.setCust_id(null);
Hibernate的一级缓存
一级缓存:称为是session级别的缓存。一级缓存的生命周期与session一致,由session中的一系列java集合构成,是自带的,不可卸载
二级缓存:是sessionfactory级别的缓存,是需要配置的缓存,企业开发中一般不用
一级缓存的结构
快照区
设置事务隔离级别
在核心配置文件中
4
session的事务管理
确保事务中连接对象是同一个
1.向下传递,如DBUtils
2.使用ThreadLocal对象
将这个连接绑定到当前线程中
在DAO的方法中,通过当前线程获得连接对象
Hibernate框架内部已经绑定好了ThreadLocal
在sessionfactory中提供了一个方法getCurrentSession(),但是默认不能用,需要通过一个配置完成
thread
其他API
Query
接收HQL,查询多个对象
// 简单查询
String hql = “from Customer”;
// 条件查询
String hql = “from Customer where cust_name like ?”;
Query query = session.createQuery(hql);
query.setParameter(0, “吴”);
// 设置分页,可进行分布查询
query.setFirstResult(0);
query.setMaxResults(3);
query.list();
Criteria
Query By Criteria
Criteria query = sessioin.createCriteria(Customer.class);
query.list();
// 条件查询
query.add(Restrictions.like(“cust_name”, “吴%”));
query.add(Restrictions.like(“cust_name”, “吴”, MatchMode.END));
SQLQuery
Hibernate的一对多关联映射
数据库表与表的关系
1.一对多关系
一个部门对于多个员工,一个员工只能属于某一个部门
一个客户对应多个联系人,一个联系人只能属于某一个客户
一对多建表原则:
在多的一方创建外键指向一的一方的主键
2.多对多关系
一个学生可以选择多门课程,一门课程也可以被多个学生选择
一个用户可以选择多个角色,一个角色也可以被多个用户选择
多对多建表原则:
创建中间表,至少有两个字段,分别作为外键指向多对多双向的主键
3.一对一关系
一个公司只能有一个注册地址,一个注册地址只能被一个公司注册
一对一建表原则:
1.唯一外键对应
2.主键对应
2.多对多关系
Hibernate的一对多关系配置
1.创建一个项目,引入相应jar包
2.创建数据库和表
3.创建实体
在一的一方实体,放置多的一方的集合,Hibernate默认使用Set集合
在多的一方实体,放置一的一方的对象
4.创建映射文件
配置多对一的映射
name:一的一方的对象的属性名称
class:一的一方的类的全路径
column:在多的一方的表的外键名称
配置一对多的映射
name:多的一方的对象集合的属性名称
column:多的一方的外键名称
class:多的一方的类的全路径
<set name="">
<key column=""></key>
<one-to-many class=""/>
</set>
5.创建核心配置文件
6.引入工具类
7.编写测试类
一对多的级联操作
为了解决session保存时必须对所有对象都显示调用save方法
要操作哪个对象的保存,就在那个对象类的配置文件中进行级联配置
<many-to-one name=“customer” cascade=“save-update”…
级联删除
在没有设置级联删除时,默认情况下,修改外键为null,删除本方对象
需要级联删除,则做以下配置
<many-to-one name=“customer” cascade=“save-update, delete”…
一对多设置了双向关联时,会产生多余的SQL语句
解决多余的SQL语句:
单向维护:使一方放弃外键维护权:一的一方放弃
cascade和inverse,inverse的设置不会影响级联创建,只是影响外键的设置结果
Hibernate的多对多关系映射
两边实体类放置的都是对方的集合
name:对方的集合的属性名称
table:中间表的名称
key的column:当前的对象对应的中间表的外键的名称
class:对方的类的全路径
many-to-mnay的column:对方的对象在中间表的外键的名称
如果多对多建立了双向的关系,必须有一方放弃外键维护,通常是让被动方放弃
需要级联保存时与一对多的级联配置相同
多对多的级联删除(基本用不到)
ThreadLocal管理连接
ThreadLocal tl = new ThreadLocal<>();
conn = tl.get();
Hibernate的查询方式
五种查询方式
OID查询
根据对象的OID(主键)进行检索
使用get和load方法
session.get(Class, oid);
session.load(Class, oid);
对象导航检索
根据一个已经查询到的对象,获得其关联对象的查询方式
HQL检索
简单查询
session.createQuery(“from Customer").list();// Customer实际是类名,只是省略了全路径,不是表名
sql支持*号,hql不支持
"from Customer c" // 别名查询
"select c from Customer c" // 别名查询
排序查询
“from Customer order by 属性”
“from Customer order by 属性 desc” // 降序查询 asc:升序
条件查询
1.按位置绑定:根据参数的位置进行绑定
“from Customer where 属性 = ?”)
query.setParameter(0, “”)
2.按名称绑定:给参数变量取名字,如aaa
“from Customer where 属性 = :aaa”
query.setParameter(“aaa”,"")
投影查询
查询对象的某个或某些属性
“select c.属性 from Customer c” // 返回list
“select c.属性1, c.属性2 from Customer c” // 返回list<Object[]>
"select new Customer(属性1, 属性2) from Customer" // 返回list<Customer>
分页查询
query.setFirstResult(0);
query.setMaxResults(3);
分组统计查询
1.聚合函数:count() max() min() avg() sum()
“select count() from Customer" // list.get(0)或uniqueResult()
2.分组统计
"select 属性, count() from Customer group by 属性 having count(*) >= 2” // 返回list<Object[]>
QBC检索
简单查询
Criteria criteria = session.createCriteria(Class);
criteria.list();
排序查询
criteria.addOrder(Order.asc(“属性”));
分页查询
criteria.setFirstResult(0);
criteria.setMaxResults(10);
条件查询
criteria.add(Restrictions.eq(“属性”, “”));
Restrictions.gt Restrictions.ge Restrictions.lt Restrictions.le
Restrictions.ne Restrictions.like Restrictions.in Restrictions.and
Restrictions.or
统计查询
// add:where后面的条件
// addOrder:order by
// setProjection:聚合函数和group by having
criteria.setProjection(Projections.rowCount());
criteria.uniqueResult();
离线条件查询
DetachedCriteria对象,可以脱离session使用
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
dc.add(Restriptions.eq());
Criteria criteria = DetachedCriteria.getExecutableCriteria(session);
criteria.list();
HQL的多表查询
sql的多表查询:
连接查询:
交叉连接:笛卡尔
select * from 表1,表2;
内连接:inner join inner可以省略,两个表的交集
隐式内连接
select * A,B where A.id = B.aid;
显示内连接
select * from A inner join B on A.id = B.aid;
外连接:outer join outer可以省略
左外连接:左表的所有和两个表的共同
select * from A left outer join B on A.id = B.aid;
右外连接
select * from A right outer join B on A.id = B.aid;
HQL的多表查询
连接查询
交叉连接
内连接
显示内连接
from Customer c inner join c.linkMans // 返回list<Object[]>
隐式内连接
迫切内连接:加了一个fetch,生成sql与普通显示内连接一致,fetch是为了通知Hibernate,将后面表的信息与前面表查询的对象放到一起,增加distinct则是将后面的对象添加到前面对象的属性集合中(相当于去除重复的对象)
from Customer c inner join fetch c.linkMans
select distinct c from Customer c inner join fetch c.linkMans
外连接
左外连接
右外连接
迫切左外连接
SQL检索
sqlQuery.addEntity(Customer.class); // 之后调用sqlQuery.list()可以返回list<Customer>
Hibernate的检索策略
优化手段
延迟加载
lazy懒加载
执行到该代码时,不会发送语句去查询,直到真正使用这个对角的属性时才会发送SQL语句进行查询
类级别的延迟加载
通过load方法查询某个对象时,是否采用延迟
session.load(Customer.class, 1);
配置:在中增加属性lazy=“true”
让lazy失效:
1.将lazy置为false
2.将持久化类使用final修饰
3.Hibernate.initialize();
关联级别的延迟加载
指的是在查询到某个对象时,查询其关联对象时,是否采用延迟加载
session.get(Customer.class, 1);
customer.getLinkMans(); // 通过客户获得联系人时,联系人对象是否采用了延迟加载,称为关联级别的延迟
配置:在或中增加属性lazy=“true”
抓取策略往往会和关联级别的延迟加载一起使用,优化语句
抓取策略
通过一个对象抓取到关联对象需要发送SQL语句,如何发送,发送成什么样格式,通过策略进行配置
通过或进行设置,fetch属性
fetch和lazy共同设置来优化发送的SQL语句
上的fetch和lazy
fetch:抓取策略,控制SQL语句格式
select:默认值,发送普通的select,查询关联对象
join:发送一条迫切左外连接查询关联对象(lazy不起作用,不需要设置)
subselect:发送一条子查询查询其关联对象
lazy:延迟加载,控制查询关联对象时是否采用延迟
true:默认值,查询关联对易用时采用延迟加载
false:查询关联对象时,不采用延迟加载
extra:极其懒惰
上的fech和lazy
fetch:抓取策略,控制SQL语句格式
select:默认值,发送普通的select,查询关联对象
join:发送一条迫切左外连接查询关联对象(lazy不起作用,不需要设置)
lazy:延迟加载,控制查询关联对象时是否采用延迟
proxy:默认值,具体的取值取决于另一端上的lazy的值
false:查询关联对象时,不采用延迟加载
no-proxy:(不会使用)
批量抓取
一批关联对象一起抓取 batch-size
在或上设置 batch-size=“4”