1、持久化类的编写规则
1.1 什么是持久化类
1.1.1 持久化:将内存中的一个对象持久化到数据库中过程。Hibernate框架就是用来进行持久化的框架。
1.1.2 持久化类:一个java对象与数据库的表建立了映射关系,那么这个类在Hibernate中成为持久化类。
1.2 持久化类的编写规则
- 对持久化类提供一个无参的构造
- Hibernate的底层需要使用反射来生成实例。
- 属性要私有,对私有属性提供public的set和get方法
- Hibernate中获取,设置对象的值
- 对持久化类提供一个唯一的标识OID与数据库主键对应
- java中通过对象的地址来区分是否是同一个对象,数据库中通过主键来确定是否是同一个记录,在Hibernate中通过持久化类的OID的属性区分是否是同一个对象。
- 持久化类中属性尽量使用包装类类型(Integer,Long,Double等等)
- 因为基本数据类型默认值是0,那么0就会有很多歧义。包装类的默认是null。
- 持久化类不要使用final进行修饰
- 延迟加载本身是Hibernate一个优化的手段。最后返回的是一个代理对象(Javassist可以对没有实现接口的类产生代理-->使用了非常底层的字节码增强技术,继承这个类进行代理)。如果不能被继承,不能产生代理对象,延迟加载也就失效。load方法和get方法一致。
2、主键生成策略
2.1 主键的分类
2.1.1 自然主键
- 主键的本身表中的一个字段(实体中的一个具体的属性)。
- 创建一个人员表,人员都有一个身份证号码(唯一的不可重复的),使用了身份证号码作为主键,这种主键成为自然主键。
2.1.2 代理主键
- 主键本身不是表中必须的字段(不是实体中的某个具体的属性)
- 创建一个人员表,没有使用人员中的身份证号码,用了一个与这个表不相关的字段ID:(PNO).这种主键就成为代理主键。
- 在实际开发中,尽量使用代理主键。
- 一旦自然主键参与到业务逻辑中,后期可能需要修改源代码。
- 好的程序的设计要满足OCP原则:对程序的扩展是open的,对修改源码是close的。
- 一旦自然主键参与到业务逻辑中,后期可能需要修改源代码。
2.1.3 主键的生成策略(主要修改Customer.hbm.xml中generator即可)
- 在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置。在Hibernate中为了减少程序编写,提供了很多种的主键的生成策略。
- increment :Hibernate中提供的自动增长机制,适用short,int,long类型的主键。在单线程程序中适用。
- identity :适用于short,int,long类型的主键,适用的是数据库底层的自动增长机制,适用于有自动增长机智的数据库(MySQL,MSSSQL...注意:Oracle没有自动增长机制)。
- sequence :适用于short,int,long类型的主键,采用的是序列的方式,也是必须得序列的数据库(Oracle等,注意:MySQL不支持序列化,所以无法适用)。
- UUID :适用于字符串类型的主键,使用hibernate中的随机方式生成字符串主键。
- native :本地策略,可以在identity和sequence之间自动切换。
- assigned :hibernate放弃外键的管理,需要通过手动编写程序或者用户自己设置。
3、持久化类的三种状态
3.1 三种状态
Hibernate是持久化层框架,通过持久化类完成ORM操作。Hibernate为了更好的管理持久化类,将持久化类分成了三种状态。
3.1.1 瞬时态
- 这种对象没有唯一的标识OID,没有被Session管理,称为是瞬时态对象。
- 持久化类的持久态的对象,可以自动更新数据库。
3.1.2 持久态
- 这种对象有唯一的标识OID,也被Session管理,称为持久态对象。
3.1.3 脱管态
- 这种对象有唯一的标识OID,但没有被Session管理,称为脱管态对象。
3.2 区分三种状态对象
public void demo01() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer(); //瞬时态对象:没有唯一标识OID,还没有被Session管理
customer.setCust_name("萨拉伊丁");
Serializable id = session.save(customer); //持久态对象:有唯一标识OID,被Session管理
transaction.commit();
session.close();
System.out.println("客户的名称"+customer.getCust_name());//脱管态对象:有唯一的标识OID,但没有被Session管理
}
3.3 持久化类的状态转换
3.3.1 瞬时态对象
- 获得
Customer customer = new Customer();
- 状态转换
- 瞬时态---->持久态
- save(Object obj)
- saveOrUpdate(Object obj)
- 瞬时态---->脱管态
- customer.setCust_id(1l);
- 瞬时态---->持久态
3.3.2 持久态对象
- 获得
- get()
- session.get(Customer.class,1l)
- load()
- find()
- iterate()
- get()
- 状态转换
- 持久态--->瞬时态
- delete()
- 持久态--->脱管态
- close()
- session.close()
- clear()
- close()
- 持久态--->瞬时态
3.3.3 持久态对象
- 获得
Customer customer = new Customer();customer.setCust_id(1l);
- 状态转换
- 脱管态--->持久态
- update(Object obj)
- saveOrUpdate(Object obj)
- 脱管态--->瞬时态
- custom.setCust_id(null);
- 脱管态--->持久态
3.3.4 持久态对象的特性
持久化类持久态对象自动更新数据库。
public void demo02() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//获得持久态对象
Customer customer = session.get(Customer.class, 1l);
customer.setCust_name("musapir"); //如果传入的值跟数据库的一样,就不发update()请求语句,不一样就发update()
//session.update(customer); //不用写也能更新数据库,因为持久态对象有自动更新数据库的特性
transaction.commit();
session.close();
}
4、Hibernate的一级缓存
4.1 什么是缓存
缓存:是一种优化的方式,将数据载入到内存中,使用的时候直接从缓存中获取,不用通过存储源获取。
4.2 Hibernate的缓存
4.2.1 Hibernate的一级缓存
Hibernate框架中提供了优化手段:缓存、抓取策略。Hibernate中提供了两种缓存机制:一级缓存、二级缓存。
Hibernate的一级缓存:称为Session级别的缓存,一级缓存生命周期与Session一致(一级缓存是由Session中的一系列的Java集合构成)。一级缓存是自带的不可卸载的。(Hibernate的二级缓存是SessionFactory级别的缓存,需要配置的缓存)。
4.2.2 证明一级缓存的存在
public void demo01() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
/*
* Customer customer1 = session.get(Customer.class, 1l); //发送SQL语句
* System.out.println(customer1);
*
* Customer customer2 = session.get(Customer.class, 1l); //不发送SQL语句 ,从缓存里面获取
* System.out.println(customer2);
*
* System.out.println(customer1==customer2);
*/
Customer customer = new Customer();
customer.setCust_name("Muhammad");
Serializable id = session.save(customer); //发送SQL语句
Customer customer2 = session.get(Customer.class, id);//不发送SQL语句(在保存操作时就把数据缓存到内存中,再次查询就直接从缓存中获取数据)
System.out.println(customer2);
transaction.commit();
session.close();
}
4.3 Hibernate的一级缓存的结构
4.3.1 一级缓存中特殊区域:快照区
public void demo02() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = session.get(Customer.class, 1l);//发送SQL语句查询,同时将查询结果放入到一级缓存当中,然后把结果进行快照,放到一个map集合中
customer.setCust_name("张三"); //当数据变化的时候,会修改一级缓存中的数据,快照区的数据不会发生变化
transaction.commit(); //当提交事务的时候,会将一级缓存中的数据与快照区的数据进行比较,如果数据相同,则不发送SQL语句,如果有变化,就发送SQL语句更新数据
session.close();
}
持久态对象之所以能自动更新数据库,就是因为有了快照区,能够进行判断数据有没有变化。
5.Hibernate的事务管理
5.1 事务的回顾
5.1.1 什么是事务
事务:指的是逻辑上的一组操作,组成这组操作的各个逻辑但愿要么全都成功,要么全都失败。
5.1.2 事务的特性
- 原子性 :代表事务不可分割
- 一致性 :代报事务执行的前后,数据的完整性保持一致。
- 持久性 :代表事务执行完成后,数据就持久到数据库中。
- 隔离性 :代表一个事务执行的过程中,不应该受到其他事务的干扰。
5.1.3 如果不考虑隔离性,引发安全性问题
- 读问题
- 脏读 :一个事务读到另一个事务为提交的数据
- 不可重复读 :一个事务读到另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致。
- 虚读 :一个事务读到另一个事务提交的insert的数据,导致在前一个事务多次查询结果不一致。
- 写问题
- 引发两类丢失更新
5.1.4 读问题的解决
- 设置事务的隔离级别
- read uncommitted :以上的读问题都会发生
- read committed :可以解决脏读,但是不可重复读和虚读有可能会发生
- repeatable read :解决脏读和不可重复读,但虚读可能会发生
- serializable :解决所有读问题
5.2Hibernate中设置事务的隔离级别
在核心配置文件hibernate.cfg.xml中设置隔离级别
<!-- 设置事务隔离级别 -->
<property name="hibernate.connection.isolation">4</property>
5.3 Service 层事务
5.3.1 Hibernate解决service的事务管理
-
改写工具类
public Session getCurrentSession() { return sf.getCurrentSession(); }
-
改写核心配置文件
<!-- 配置当前线程绑定的Session --> <property name="hibernate.current_session_context_class">thread</property>
-
测试
public void demo01() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Customer customer = session.get(Customer.class, 1l);
customer.setCust_name("李四");
session.save(customer);
System.out.println(customer);
transaction.commit();
//不能关闭session,不然就会报错
}
6、Hibernate的其他API
6.1 Query
-
Query接口用于接收HSQL,查询多个对象。
-
HQL:Hibernate Query Language,Hibernate查询语言,这种语言与SQL的语法及其类似,面向对象的查询语言。
-
public void demo01() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//简单查询
//String hql = "from Customer";
//条件查询
//String hql = "from Customer where cust_name like ?";//低版本中这么写,新版本中找如下写,不然会报错
//String hql = "from Customer where cust_name like ?0";
//分页查询
String hql = "from Customer";
//通过Session 获得Query接口
Query query = session.createQuery(hql);
//query.setParameter(0, "m%");
//设置分页
query.setFirstResult(0); //从第几条开始
query.setMaxResults(2); //每页显示数据条数
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
6.2 Criteria
criteria:QBC(Query By Criteria)
-
更加面向对象的一种查询方法
public void demo02() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//通过Session获得Criteria的对象
/*
* Criteria criteria = session.createCriteria(Customer.class); List<Customer>
* list = criteria.list();
*/
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.like("cust_name", "m",MatchMode.ANYWHERE));//第三个参数是查询类型,也可以不写,第二个参数中直接用%
//分页
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
6.3 SQLQuery
- 用于接收SQL语句,特别复杂情况下使用SQL。