学习地图
持久化类
主键生成策略
持久化对象的三种状态(★持久态)
一级缓存(快照机制)
事务
查询的api★★★
持久化类:
概述:javabean + 映射文件
编写规范:
必须是一个公共的具体的类(public class)
必须有一个无参构造器
字段私有,必须提供公共的访问字段的方法(get和set)
必须有一个oid属性和主键对应
字段尽量使用包装类修饰
类尽量不要使用final修饰(若使用final修饰,load方法和get一样了)
因为load的加强方法是 javassist或者cglib 动态代理
使用的继承方法
主键生成策略
主键类型分类
自然主键:使用实体中一个有具体业务意义的字段作为主键
例如:身份证号
★代理主键:使用实体中一个毫无任何具体业务意义的字段作为主键
例如 user_id product_id
hibernate中主键生成策略:
常见值:
(了解)increment:使用hibernate的自增策略(我们不用),类型整数,插入记录的时候,先去数据库中查询一下id的最大值,然后将最大值+1作为这条记录的id,我们一般不会用,因为多线程会出问题
★identity:hiberante使用数据库的自增策略,类型整数 代表:mysql
★sequence:hiberante使用数据库的序列策略,类型整数 代表:oracle
★★native:hiberante使用数据库的本地策略,类型整数 判断数据库的支持什么策略 我们可以简单的认为不是identity就是sequence
(理解)uuid:hibernate使用随机字符串
(了解)assigned:放弃hibernate维护主键.自己手动指定
我们一般选用uuid或者native
持久化对象的三种状态(★持久态)
(了解)瞬时态:对象没有oid,且没有和session关联
(★★)持久态:对象有oid,且和session关联
特点:持久态对象可以自动更新数据库(依赖于一级缓存)
(了解)脱管态:对象有oid,但没有和session关联
持久态验证
持久化三种对象
public void t1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//先创建一个对象
Customer c = new Customer("二毛");
c.setCust_source("网络营销");//瞬时态对象
// 保存
Serializable id = session.save(c);//持久态对象
tx.commit();
session.close();
System.out.println(c.getCust_id()+"::"+c.getCust_name());//脱管态对象
}
持久态对象可以自动更新数据库
public void t2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer c = session.get(Customer.class, 1L);
c.setCust_name("二毛二");
//之前就该调用update 因为c是持久态对象,可以自动更新数据库,现在不需要调用update
tx.commit();
session.close();
}
一级缓存(快照机制)
缓存:
介于硬件和程序之间的一种介质.提供程序的执行效率.减轻数据库的负载(访问次数)
查询数据的时候先从缓存中,若缓存没有再去mysql中查询,查询完成之后,还需要将记录放入缓存中一份.
hibernate封装了jdbc的操作.效率肯定没有jdbc高.hibernate为了提高他的执行效率,从而提供了一些优化手段(缓存和延迟加载)
在缓存中提供了一级缓存和二级缓存
一级缓存:
hibernate自带的,不能卸载,必须使用的.生命周期和Session的生命周期一样.所以有人把他也称之为Session级别的缓存
(了解)二级缓存:
不是hibernate自带的(ehcache),要想使用必须先导入jar包,然后配置才能使用.一般使用redis替代.
生命周期和SessionFactory的生命周期一样.所以有人把他也称之为SessionFactory级别的缓存
一级缓存:
就是一些java集合组成的.
分成了缓存区和快照区两部分.
放入数据的时候,放缓存区放入一份,往快照区放入一份.我们操作的时候,只操作缓存区.
当事务提交的时候,判断缓存区和快照区的数据有无改变
若改变:马上发送sql语句,更新数据库
若不改变:啥也不做
这个就是session级别的缓存
验证一级缓存是否存在:
1.查询一个对象两次
2.先保存一个对象,然后再查询
请看下面代码
@Test
//查询一个对象两次
public void t(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer c1 = session.get(Customer.class, 1L);
Customer c2 = session.get(Customer.class, 1L);
System.out.println(c1 == c2);//输入为true
tx.commit();
session.close();
}
@Test
//先保存 再查询
public void t2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//先保存
Customer c1 = new Customer("大毛");
session.save(c1);
//在查询,查询的时候就先查缓存,如果缓存没有再去数据库拿
Customer c2 = session.get(Customer.class, 1L);
System.out.println(c1 == c2);
tx.commit();
session.close();
}
事务
javase中的事务
事务概念
事务特性: ACID
A:automicity 原子性:强调事务的不可分割.多条语句要么都成功,要么都失败。
C:consistency 一致性:强调的是事务的执行的前后,数据要保持一致.(例如 A转账B,两个人的钱数应该各有加减)
I:isolation 隔离性:一个事务不能收到其他事务的影响,
D:durability 持久性:事务一旦结束(提交/回滚)数据就持久保持到了数据库.
若不考虑隔离性会产生的读问题
脏读
不可重复读
虚读
通过设置数据库的隔离级别就可以解决以上问题:
代表号码 | 状态 | 状态 | 二进制表示 |
---|---|---|---|
1 | read uncommitted | 读未提交 | 0001 |
2 | read committed | 读已提交(oracle) | 0010 |
4 | repeatable read | 可重复读(mysql) | 0100 |
8 | serializable | 串行化 | 1000 |
hibernate如何设置隔离级别?
在核心配置文件中配置
<property name="hibernate.connenction.isolation">4</..>
事务加在哪一层?service
如何保证service层和dao层使用的同一个事务啊?
只需要保证service层和dao层使用同一个连接即可
若何保证service层和dao层使用同一个连接呢?
方式1:传递参数
方式2:使用线程绑定的方式(ThreadLocal)
hibernate如何使用事务,底层封装好了ThreadLocal
步骤:
1.在核心配置文件中配置 将session绑定到当前线程中
<!-- 开启与线程绑定的session -->
<property name="hibernate.current_session_context_class">thread</property>
2.factory.getCurrentSession();获取和当前线程绑定的session
注意:
此时的session不需要手动关闭
/**
* 获取和当前线程绑定的session对象
* @return
*/
public static Session getCurrentSession(){
return factory.getCurrentSession();
}
//获取和当前线程绑定的session
public class Demo4Thread {
@Test
public void t(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
tx.commit();
//session.close();//不需要手动关闭
}
查询的api★★★
5中检索方式
oid检索
get和load
对象导航检索(明天说)
sql检索(发送sql语句)
hql检索
qbc检索
hql检索★★
面向对象的查询语言.
获取查询对象Query
session.createQuery(String hql语句);
hql语句和sql类似,简单的写法 可以将sql中的表名和字段名用类名和属性名替代
查询所有
list()
uniqueResult() 唯一值
public class HQLDemo {
@Test
//查询所有
public void t1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//1.获取query对象
Query qq = session.createQuery("from Customer");//正确
//Query qq = session.createQuery("select c from Customer c");//正确
//Query qq = session.createQuery("select * from Customer");//错误
//2.查询
List<Customer> list = qq.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
排序查询
hql : from Customer order by cust_id desc
@Test
//排序查询
public void t2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取query对象
Query qq = session.createQuery("from Customer order by cust_id desc");//正确
//查询
List<Customer> list = qq.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
分页查询
setFirstResult(int 开始索引)
setMaxResults(int 每页显示的条数)
@Test
//分页查询
public void t4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取query对象
Query qq = session.createQuery("from Customer");
//设置分页参数 limit m,n; limit 0,3 等价于 limit 3;
qq.setFirstResult(3);
qq.setMaxResults(3);
//查询
List<Customer> list = qq.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
统计查询
hql : select count(*) from Customer
@Test
//统计查询
public void t3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取query对象
Query qq = session.createQuery("select count(*) from Customer");//正确
//查询
/*List<Long> list = qq.list();
System.out.println(list);*/
Long obj = (Long) qq.uniqueResult();
System.out.println(obj);
tx.commit();
}
条件查询
★方式1:按照位置设置参数 ? 占位符
hql:from Customer where cust_name like ? and cust_source = ?
setParameter(int 问号的索引,Object 参数值)
@Test
//条件查询:1 按照位置设置参数 ?
public void t5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取query对象
Query qq = session.createQuery("from Customer where cust_name like ? and cust_source = ?");
//设置参数
qq.setParameter(0, "%大毛%");
qq.setParameter(1, "网络营销");
//查询
List<Customer> list = qq.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
(扩展)方式2:按照名称设置参数 :名称 占位符
hql:from Customer where cust_name like :name and cust_source = :ss
setParameter(String 参数的名称,Object 参数值)
例如:
setParameter(“name”,”%大毛%”)
@Test
//条件查询:2 按照名称设置参数 :参数名称
public void t6(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取query对象
Query qq = session.createQuery("from Customer where cust_name like :name and cust_source = :ss");
//设置参数
qq.setParameter("name", "%大毛%");
qq.setParameter("ss", "网络营销");
//查询
List<Customer> list = qq.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
投影查询(查询部分属性)
//投影查询 部分属性 默认将每条记录封装成object数组
//投影查询 部分属性封装成对象
/**
* 1.在持久化类提供相应的构造器
* 2.hql: select new 类名(属性1,属性2) from 类名;
*/
@Test
//投影查询 部分属性
public void t7(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取query对象
Query qq = session.createQuery("select cust_name, cust_id from Customer");
//查询
List<Object[]> list = qq.list();//ArrayListHandler
for (Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}
tx.commit();
}
@Test
//投影查询 部分属性封装成对象
/**
* 1.在持久化类提供相应的构造器
* 2.hql: select new 类名(属性1,属性2) from 类名;
*/
public void t8(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取query对象
Query qq = session.createQuery("select new Customer(cust_name, cust_id) from Customer");
//查询
List<Customer> list = qq.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
qbc检索
query by criteria
更加面向对象的查询语言.全是api
获取Criteria对象
session.createCriteria(Class 持久化类的字节码对象)
查询所有
list()
uniqueResult()
@Test
//查询所有
public void t1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取criteria对象
Criteria cc = session.createCriteria(Customer.class);
//查询
List<Customer> list = cc.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
排序查询
addOrder(Order.asc|desc(属性名称))
@Test
//排序查询
public void t2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取criteria对象
Criteria cc = session.createCriteria(Customer.class);
//条件排序条件
cc.addOrder(Order.desc("cust_id"));
//查询
List<Customer> list = cc.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
分页查询
setFirstResult
setMaxResults
@Test
//分页查询
public void t3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取criteria对象
Criteria cc = session.createCriteria(Customer.class);
//设置分页参数
cc.setFirstResult(0);
cc.setMaxResults(3);
//条件排序条件
cc.addOrder(Order.desc("cust_id"));
//查询
List<Customer> list = cc.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
统计查询
setProjection(Projections.count|avg|sum|min|max(属性名));
setProjection(Projections.rowCount());
@Test
//统计查询
public void t4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取criteria对象
Criteria cc = session.createCriteria(Customer.class);
//cc.setProjection(Projections.count("cust_id"));//select count(cust_id) ..
cc.setProjection(Projections.rowCount());//select count(*) ..
Object obj = cc.uniqueResult();
System.out.println(obj);
tx.commit();
}
条件查询
add(Restrictions.like|eq|gt|lt(String 属性名,Object 值));
@Test
//条件查询
public void t5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取criteria对象
Criteria cc = session.createCriteria(Customer.class);
//设置条件
cc.add(Restrictions.like("cust_name", "%大毛%"));
cc.add(Restrictions.eq("cust_source", "网络营销"));
//查询
List<Customer> list = cc.list();
for (Customer c : list) {
System.out.println(c);
}
tx.commit();
}
离线查询:(多条件查询)
脱离session使用的对象. DetachedCriteria
在web层脱离session使用,封装条件,api几乎和Criteria一样
创建一个离线对象
DetachedCriteria dc = DetachedCriteria.forClass(Class 持久化类的字节码对象);
在dao层获取可以执行的对象 操作
Criteria cc = dc.getExecutableCriteria(session)
下面程序模拟三层
@Test
public void t(){
//web层
String cust_name = null;
String cust_source = null;
/**
* 之前的写法:接受条件
* cust_name = request.getParameter("cust_name");
* cust_source = request.getParameter("cust_source");
*/
cust_name = "大毛";
//添加条件
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
//判断条件是否为空
if(cust_name!=null && cust_name.trim().length()>0){
dc.add(Restrictions.like("cust_name", "%"+cust_name+"%"));
}
if(cust_source!=null && cust_source.trim().length()>0){
dc.add(Restrictions.eq("cust_source", cust_source));
}
//service层
//dao层
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取一个可执行的对象
Criteria cc = dc.getExecutableCriteria(session);
List list = cc.list();
tx.commit();
}
扩展:sql检索:
获取SqlQuery对象
session.createSqlQuery(String sql语句);
条件和分页还可以使用
setFirstResult
setParameter
查询所有
list方法返回值 List