hibernate是位于数据层(持久层)的框架。主要用于封装对数据的操作
hibernate 作用是将面向关系型数据库的操作,转换成面向对象的操作
因此,需要有数据库与对象的映射关系,也成ORM元数据
JPA包:
required包:
mysql数据库驱动包:
文件名: ClassName + .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">
<!—dtd约束,从hibernate核心包里的 org.hibernate 包内的hibernate-mapping-3.0.dtd拷贝 -->
<hibernate-mapping>
<!-- key 是配置主键的生成策略 -->
<class name="cn.xiaoge.domain.Student" table="t_student">
<id name="id">
<!-- key 是配置主键的生成策略
#1 increment 主键自增(先查询数据库中最大id,然后再+1)
#2 identity mysql中的主键自增
#3 sequence oracl中的主键自增
#4 hilo hilo算法,也能实现主键自增
#5 native 自动匹配identity sequence hilo这三种
#6 uuid 利用uuid自动生成主键
#7 assigned 手动设置主键
-->
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<!-- 配置一对多 -->
<!--
set元素 表示 一对多 或 多对多的关系
inverse属性 表示是否不维护关联关系(如果不维护关联关系,值应设置为true)
cascade代表级联
#1 save-update(偶尔用) 保存及更新
#2 delete(不用) 删除相关的元素
#3 all(不用) save-update + delete
#4 delete-orphan(不用) 删除孤儿元素(如,外键为空的order会被删除)
#5 all-delete-orphan(不用) 相当于 all + delete-orphan
#6 none 默认值 无关联
-->
<set name="courses" table="t_student_course">
<!—key 是配置自己被引用作外键时的属性 -->
<key column="sid"></key>
<!-- class 一定要写全类名,或者之前配置package column是class对应的外键名 -->
<many-to-many class="cn.xiaoge.domain.Course" column="cid">
</many-to-many>
</set>
</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>
<!-- 配置数据库连接的基本信息(驱动名,url,用户名,密码---合称“四大天王”) -->
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.connection.url">
jdbc:mysql:///myhibernate01
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1234</property>
<!-- 配置是否显示sql语句 -->
<property name="show_sql">true</property>
<!-- 是否将sql语句格式化输出 -->
<property name="format_sql">true</property>
<!--
hbm2ddl.auto 表结构生成策略
create(学习、测试) 每次启动时重新创建表结构
create-drop(学习、测试) 每次启动时重新创建表结构,在关闭时,将表删除
update(学习时用) 操作表时,表不存在就创建表,表存在就在原表操作
validate 验证表,操作表时,表不存在,或表结构不符合,就抛出异常
-->
<property name="hbm2ddl.auto">update</property>
<!-- 设置当前session与 xx 绑定(一般设置与线程绑定) -->
<property name="current_session_context_class">thread</property>
<!-- 设置sql语句的方言(一般选择最短的那个方言) -->
<property name="dialect">
org.hibernate.dialect.MySQL5Dialect
</property>
<!-- 配置映射文件 -->
<mapping resource="cn/xiaoge/domain/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
特点:
无oid && 未与session连接(不在session缓存中)
特点:
有oid && 与session连接
特点:
有oid && 不与session连接
注意:
有id,但是数据库中没有与之相应的id。这种对象不能算作是游离状态,勉强也只能算是瞬时状态
一对多:(如顾客Customer与订单Order的关系)
(1)在Customer的实体类中,引用Order的set集合
private Set<Order> orders = new HashSet<Order>();
(2)在Customer.hbm.xml映射文件中,添加set元素
<set name="orders" cascade="save-update">
<key column="cid"></key> //表示是自己主键被引用的列名
<one-to-many class="cn.xiaoge.domain.Order" /> //注意,class是多的一方的全名
</set>
多对一:
(3)在Order的实体类中,引用Customer的对象
private Customer customer;
(4)在Order.hbm.xml的关系映射文件中,做如下配置
<many-to-one name="customer" column="cid" class="cn.xiaoge.bean.Customer">
</many-to-one>
多对多(如学生Student与课程Course)
(1)在Student的实体类中,引用Course的set集合
private Set<Student> students = new HashSet<Student>();
(2)在Student.hbm.xml配置关系映射
<set name="courses" table="t_student_course"> //多对多的中间表
<key column="sid"></key> //sid 是中间表引用student主键时的外键名
<many-to-many class="cn.xiaoge.bean.Course" column="cid">
</many-to-many> //cid 是中间表引用Course主键时的外键名
</set>
(3)在Course与Course.hbm.xml中,做类似操作,注意,是类似,不是一模一样!!!
一对一关系:如公司与注册登记的公司地点
(1)在Company中引用地址的对象
private Address address;
(2)在Company.hbm.xml中做如下配置:
<one-to-one name="address" class="cn.xiaoge.bean.Address"></one-to-one>
(3)在Address的实体类中引用Company
private Company company;
(4)在Address.hbm.xml中做如下配置:
//方式一
<id name="id">
<generator class="foreign">
<param name="property">company</param>
</generator>
</id>
<one-to-one name="company" class="cn.xiaoge.bean.Company" constrained="true">
</one-to-one>
//方式二
<id name="id">
<generator class="native"></generator>
</id>
<property name="address"></property>
<many-to-one name="company" class="cn.xiaoge.bean.Company"
column="cid" unique="true">
</many-to-one>
涉及的方法: load方法
涉及的属性: class元素上的lazy属性
lazy : true(默认值): 延迟检索 => 不会立即发送sql查询.使用时才查询
lazy : false : 立即检索 => 会立即发送sql查询.
注: get方法永远是立即检索.
结论: 延迟检索用于提高效率.如果不用, 不会检索.使用时才加载.
一对多:
涉及属性:
fetch属性: 决定加载关联数据时使用哪种sql语句
select(默认值): 会使用单表查询select语句加载关联数据.
join: 会使用表链接语句加载关联数据.
subselect:使用子查询加载关联数据
lazy属性: 决定加载关联数据的时机
true: 延迟加载.=> 在使用关联数据时才会加载.
false: 立即加载.=> 无论是否使用关联数据,都会立即加载
extra: 极其懒惰.=> 如果仅仅获得关联数据集合的size.只会发送count聚合函数查询数量.
策略配置:
fetch(默认值) : select
lazy(默认值) : true
//结论: 使用关联数据时,才加载关联数据.加载时使用单表select查询.
---------------------------------------------------------------------
fetch(默认值) : select
lazy(默认值) : false
//结论: 获得客户时,立即加载与客户关联的订单数据.使用单表select查询
---------------------------------------------------------------------
fetch(默认值):select
lazy(默认值): extra
//结论: 加载客户时,不会加载关联的订单.打印订单数量时,
//只发送count查询数量.打印属性时,会发送单表select查询.
---------------------------------------------------------------------
fetch(默认值):join
lazy(默认值): true/false/extra
//结论: fetch使用多表查询,一定会同时加载关联数据. 那么lazy属性失效.
----------------------------------------------------------------------
fetch(默认值) : subselect 子查询 =>
//查询单个客户=>相当于select
//查询多个客户=> 加载多个客户的关联数据时,会使用子查询
lazy(默认值): false
//结论: 加载多个客户数据时,会立即使用子查询加载所有客户的订单数据.
----------------------------------------------------------------------
fetch(默认值):subselect 子查询 => 查询单个客户=>相当于select
//查询多个客户=> 加载多个客户的关联数据时,会使用子查询
lazy(默认值): true
//结论: 查询多个客户时,不会立即查询客户下的订单数据. 使用订单时,会使用子查询加载所有客户的订单数据
-----------------------------------------------------------------------
fetch(默认值):subselect 子查询 => 查询单个客户=>相当于select
//查询多个客户=> 加载多个客户的关联数据时,会使用子查询
lazy(默认值): extra
//结论: 查询多个客户时,不会立即查询客户下的订单数据.打印客户的订单数量时,只会发送count查询数量. 使用订单具体属性时,会使用子查询加载所有客户的订单数据
多对一:
涉及属性:
fetch属性: 使用什么样的sql语句查询
select:单表select查询
join:多表连接
lazy属性: 加载策略
false:立即加载
proxy:我不决定加载策略.由对方类级别加载策略决定
no-proxy: 不做研究.
测试:
fetch(默认值):select
lazy(默认值): false
//结论: 查询订单时,会立即查询订单的客户.会发送多条单表查询select.
--------------------------------------------------------------------
fetch(默认值):select
lazy(默认值): proxy
//true
//false
//结论: 查询订单时,发送多条单表查询select. 至于是否立即加载,要看Customer的类级别加载策略.
--------------------------------------------------------------------
// fetch(默认值):join
// lazy(默认值): proxy/false
//结论: 加载订单时,会使用多表查询,同时加载订单的客户数据. lazy属性失效
关联级别检索策略(一对多) |
|||
Fetch Lazy |
select |
join |
subselect |
true |
使用关联数据时,才加载关联数据.并使用单表select查询 |
立即查询关联数据,多表查询,lazy属性失效 |
延时查询关联数据,在关联数据时,使用子查询 |
false |
查询主对象时,立即加载关联数据,并使用单标select查询 |
立即查询关联数据,多表查询,lazy属性失效 |
立即查询关联数据,并使用子查询 |
extra |
延时查询关联数据时, 查询关联数据数量时,只查询数量,不查询关联对象的具体信息 |
立即查询关联数据,夺标查询,lazy属性失效 |
延时查询关联数据,查询关联数据数量时,只查询数量,不查询关联对象的具体信息 |
关联级别检索策略(多对一) |
||
Fetch Lazy |
select |
join |
false |
例如:查询订单时,立即查询订单的客户.并会发送多条单表查询select |
立即查询关联数据,且是多表查询,lazy属性失效 |
proxy |
例如:查询订单时,会依据顾客的lazy属性值。若顾客的lazy=“false“,立即查询订单的客户.并会发送多条单表查询select。若顾客的lazy=“true”,会延时查询顾客信息 |
立即查询关联数据,且是多表查询,lazy属性失效 |
no-proxy |
不研究 |
不研究 |
1. 根据OID查询.
参考类级别检索策略。可以分为get(Xxx.class,oid)和load(Xxx.class,oid)
2.对象视图导航.
根据对象.属性,或 对象.方法()进行查询
3.SQL查询
类似mysql语句查询,详细信息查看mysql总结:http://my.oschina.net/xiaogezi/blog/631825
4.HQL查询
HQL:Hibernate Query Language
基本查询: Query query = session.createQuery("from Customer");
条件查询: Query query = session.createQuery("from Customer where id = 1");
投影查询: Query query = session.createQuery("select new Customer(c.cid,c.cname) from Customer c");
排序: Query query = session.createQuery("from Customer order by cid desc");
分页:
Query query = session.createQuery("from Customer");
// *** pageNum 当前页(之前的 pageCode)
query.setFirstResult(0);
// * 每页显示个数 , pageSize
query.setMaxResults(2);
绑定参数:
//方式1. 用索引设置参数
Query query = session.createQuery("from Customer where cid = ?");
query.setInteger(0, cid);
//方式2. 用字段名设置参数
Query query = session.createQuery("from Customer where cid = :xxx");
query.setParameter("xxx", cid);
聚合函数&分组:
聚合函数:sum avg max min count
分组: group by
连接查询:
内连接:
显式内连接: session.createQuery(" from Customer c inner join c.orders ");
隐式内连接: session.createQuery(" from Customer c, Order o where c.id = o.cid ");
迫切内连接:session.createQuery(" from Customer c inner join fetch c.orders ");
外连接:
左外连接:session.createQuery(" from Customer c left outer join c.orders ");
左外迫切连接:session.createQuery(" from Customer c left outer join fetch c.orders ");
右外连接:session.createQuery(" from Customer c right outer join c.orders ");
右外迫切连接:session.createQuery(" from Customer c right outer join fetch c.orders ");
连接与迫切连接的区别:
普通外连接,是把结果封装到不同的对象中,最终得到了一个Object[]的list对象
右外迫切连接,自动把一对多中多的对象封装到一的一方,最终得到了一的一方的对象的list集合。
5.Criteria查询(了解内容)
Criteria的离线查询
// #1.获取离线criteria对象
DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);
//#2.拼装参数
dCriteria.add(Restrictions.ge("id", 5));
//#3.获取可以执行的criteria
Criteria criteria = dCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
Criteria的普通查询:session.createCriteria(Customer.class).list();
Criteria的条件查询:
criteria.add(Restrictions.xxx(字段名, 值));
// 模糊查询 like;
/*Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.like("cname", "t%"));
List<Customer> list = criteria.list();*/
// 条件并列查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.like("cname", "t%"));
criteria.add(Restrictions.ge("age", 35));
List<Customer> list = criteria.list();
Criteria的分页查询:
Criteria criteria = session.createCriteria(Order.class);
criteria.setFirstResult(10); //设置索引值
criteria.setMaxResults(10); //设置每页显示的最大数量
Criteria的排序:
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(org.hibernate.criterion.Order.asc("age")); //升序
criteria.addOrder(org.hibernate.criterion.Order.desc("age")); //降序
List<Customer> list = criteria.list();