hibernate学习笔记day2
1.相关基础概念
-
持久化:将内存的一个对象持久化到数据库中的过程,hibernate框架就是用来进行持久化的框架
-
持久化类: 一个Java对象与数据库的表建立映射关系,这个类在hibernate中就可以称为持久化类。
持久化类=Java类+映射文件
2.持久化类的编写规则
- 对持久化类提供一个无参数的构造方法–>hibernate底层需要使用反射生成实例。
- 属性需要私有,对私有属性提供public的get和set方法–>hibernate中获取和设置对象的值
- 对持久化类提供唯一的标识OID与数据库主键对应–>Java中通过对象的地址区分是否是同一个对象,在数据库中通过主键确定是否是同一个记录,在hibernate中通过持久化类的OID的属性确定是否是同一个对象。
- 持久化类中的属性尽量使用包装类的类型–>因为基本数据类型默认为0,那么0就会产生很多歧义。包装类类型的默认值是null。
- 持久化类不要使用final进行修饰–>延迟加载本身是hibernate一个优化的手段,返回的是一个代理对象(javassit可以对没有实现借口的类产生代理–使用非常底层的字节码增强技术,继承这个类进行代理。如果不能继承,就不能产生代理对象,延迟加载也久失效。load()和get()方法就变成一样效果了。
3. 主键生成策略
- 1.主键的分类
-
1.自然主键
主键本身就是数据库表中的一个字段(实体中的一个具体属性)
就是使用实际表中的主键,就是自然主键 -
2.代理主键
主键本身不是表中的必须的一个字段(不是实体中某个具体的属性)
使用了一个与表完全不相关的字段就叫做代理主键 -
3.在实际开发中,尽量使用代理主键
如果自然主键参与到业务逻辑中,后期有可能需要修改源代码
好的程序设计满足OCP原则,对程序是open可扩展的,对修改源代码是close的。
-
- 2.主键生成策略
在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置,在hibernate中为了减少程序编写,提供了很多主键的生成策略。-
increment : hibernate中提供的自动增长机制,适用于short、int、long类型的主键,在单线程程序中使用。
首先发送一条语句,select max(id) from 表,然后让id+1作为下一条记录的主键。
-
identity : 适用于short、int、long类型的主键,使用的是数据库底层的自动增长机制,适用于有自动增长机制的数据库(mysql、mssql),但oracle没有自动增长。
-
sequence : 使用与short、int、 long类型的主键,采用序列的方法(oracle支持序列)。但mysql就不能使用sequence。
-
uuid : 适用于字符串类型的主键,使用hibernate中的随机方式生成字符串主键。
-
native : 本地策略,在identity和sequence之间进行自动切换。
-
assigned : hibernate放弃外键的管理,需要通过手动编写程序或用户自己设置。
-
foreign : 外部的,一对一的一种关联映射的情况下使用。
-
4.持久化类的三种状态
-
1.持久化类的三种状态
-
1.瞬时态
瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建,开辟内存空间的对象,不存在持久化类标识OID(相当于主键),尚未与hibernate Session关联,在数据库中也没有记录。
-
2.持久态
持久态的对象有标识OID,加入到了Session对象中,与Session关联并且被Session管理,在数据库中有对应的记录,持久态对象是在事务还未提交前变成持久态的。
- 3.脱管态
也称离线态或者游离态,当某个持久化状态的实例与session的关联状态关闭时就变成脱管态,脱管态对象存在对应的持久化标识OID,并且与数据库数据存在关联,只是失去了与当前Session的关联,托管状态对象发生改变时Hibernate不能检测到。
-
-
2.区分对象的三种状态
public void demo1() {
Session session=HibernateUtils.openSession();
Transaction tx=session.beginTransaction();
//瞬时对象,没有唯一的OID,没有被session管理
Customer customer=new Customer();
customer.setCust_name("李佳");
//被session管理,变成持久态对象,有唯一标识OID
Serializable id=session.save(customer);
tx.commit();
//关闭session,这个对象变成脱管态对象,有唯一的OID没有被session管理
session.close();
}
- 3.三种状态的转换
-
瞬时对象
1.获得
Customer customer=new Customer();
2.状态转换
瞬时————>持久
save(Object obj)、 saveOrUpdate(Object obj);
瞬时–>托管
customer.setCust_id(1); -
持久态对象
1.获得
get(),load(),find(),iterate()
Customer customer=session.get(Customer.class,1);
2.状态转换
持久态–>瞬时态
delete()
持久态–>脱管态
close(),clear(),evict(Object obj) -
脱管态对象
1.获得
Customer customer=new Customer();
customer.setCust_id(1);
2.状态转换
脱管态–>持久态
update(),saveOrUpdate()
脱管态–>瞬时态
customer.setCust_id(null);
-
5. 缓存的概述
- 1.什么是缓存?
缓存是一种优化的方式,将数据存入到内存中,使用的时候直接从缓存中获取,不用通过存储源。
- 2.Hibernate的一级缓存
Hibernate框架中提供了优化手段,缓存,抓取策略,Hibernate中提供了二种缓存机制:一级缓存和二级缓存。Hibernate的一级缓存是session级别的缓存,一级缓存的生命周期与session一致(一级缓存是由session中的一系列的Java集合构成),一级缓存是自带的不可卸载的(Hibernate的二级缓存是SessionFactory级别的缓存,需要配置的缓存)。 - 3.证明一级缓存的存在
@Test
public void demo1() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*
Customer customer1 = session.get(Customer.class, 1);
System.out.println(customer1);
Customer customer2 = session.get(Customer.class, 1);
System.out.println(customer2);
System.out.println(customer1 == customer2);
*/
Customer customer=new Customer();
customer.setCust_name("老满天");
Serializable id= session.save(customer);
//不发送SQL语句
Customer customer2=session.get(Customer.class, id);
System.out.println(customer2);
tx.commit();
session.close();
}
6.事务的回顾
-
1.什么是事务?
事务是指逻辑上的一组操作,组成这组操作的各个逻辑单元要么全部成功,要么全部失败。 -
2.事务的特性
- 1.原子性 : 代表事务不可分割
- 2.一致性 : 代表事务执行的前后,数据的完整性保持一致
- 3.隔离性 : 代表一个事务执行的过程中,不应该收到其他事务的干扰。
- 4.持久性 : 代表事务执行完成后,数据持久到数据库中。
-
3.如果事务不考虑隔离性,引发安全性问题
- 1.读问题
** 脏读 :一个事务读到另一个事务未提交的数据
** 不可重复读 :一个事务读到另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致。
** 幻读(虚读):一个事务读到另一个事务已经提交的insert数据,导致在前一个事务多次查询结果不一致。 - 2.写问题
** 引发两类丢失更新
- 1.读问题
-
4.读问题的解决
- 设置事务的隔离级别
read uncommitted :以上读问题都可能产生
read committed :解决脏读,但可能产生不可重复读和幻读
repeatable read :解决脏读和不可重复读,但可能产生幻读
serializable : 解决所有读问题
- 5.在hibernate配置文件中设置事务的隔离级别
<!--设置事务的隔离级别-->
<property name="hibernate.connection.isolation">4</property>
- 6.设置线程绑定Session
public class HibernateUtils {
//抽取工具类
public static final Configuration cfg;
public static final SessionFactory sf;
static {
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
public static Session openSession() {
return sf.openSession();
}
public static Session getCurrentSession() {
return sf.getCurrentSession();
}
//在配置文件中配置
<property name="hibernate.current_session_context_class">thread</property>
@Test
public void demo1() {
Session session=HibernateUtils.getCurrentSession();
Transaction tx=session.beginTransaction();
Customer customer =new Customer();
customer.setCust_name("lijia");
session.save(customer);
tx.commit();
}
7. Hibernate中其他的API
- HQL
- Hibernate查询语言(HQL)与SQL(结构化查询语言)相同,但不依赖于数据库表。 我们在HQL中使用类名,而不是表名。 所以是数据库独立的查询语言。
- HQL的优点
- 数据库独立
- 支持多态查询
查询接口 Query对象
public int executeUpdate() : 用于执行更新或删除查询。
public List list() : 将关系的结果作为列表返回。
public Query setFirstResult(int rowno) : 指定从哪里检索记录的行号。
public Query setMaxResult(int rowno) : 指定从关系(表)中检索记录的行号。
public Query setParameter(int position, Object value)将该值设置为JDBC样式查询参数。
public Query setParameter(String name, Object value)将该值设置为命名查询参数。
- 查询实例
@Test
public void demo1() {
Session session=HibernateUtils.getCurrentSession();
Transaction tx=session.beginTransaction();
//简单查询
//String hql="from Customer";
//条件查询
String hql="from Customer where cust_name like ?";
//设置条件
//query.setParameter(0,"王%");
//通过session获得Query接口
Query query=session.createQuery(hql);
//分页查询
query.setFirstResult(0);//第一个参数角标是0
query.setMaxResults(3);
List<Customer> list=query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
- 总结
- 获取所有表中记录
1. 获取所有表中记录
Query query=session.createQuery("from tableName");
List list=query.list();
2.删除实例
Query query=session.createQuery("delete from tableName where id=100");
query.executeUpdate();
3. 获取分页记录
Query query=session.createQuery("from tableName");
query.setFirstResult(5);
query.setMaxResult(10);
List list=query.list();
查询接口Criteria对象
-
- Criteria接口
Criteria接口提供了许多方法来指定条件。 可以通过调用Session接口的createCriteria()方法获得Criteria对象。
- Criteria接口
-
- Criteria接口常用的方法
* public Criteria add(Criterion c) : 用于添加限制(条件)。
* public Criteria addOrder(Order o) : 指定排序顺序。
* public Criteria setFirstResult(int firstResult) : 指定要检索的第一个记录数。
* public Criteria setMaxResult(int totalResult) : 指定要检索的记录总数。
* public List list() : 返回包含对象的列表。
* public Criteria setProjection(Projection projection) : 指定投影。
- 通过session接口的createCriteria()方法获得Criteria的对象
Criteria criteria=session.createCriteria(Customer.class);
List<Customer> list=criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
- 获取所有记录的HCQL示例
Criteria criteria=session.createCriteria(Customer.class);
List list=criteria.list();
- HCQL获得第10到20个记录的例子
Criteria c =session.createCriteria(类名.class);
c.setFirstResult(10);
c.setMaxResult(20);
List list=c.list();
- HCQL获取薪资大于10000的记录示例
Criteria c =session.createCriteria(类名.class);
c.add(Restrictions.gt("salary",10000));
List list=c.list();
- 以薪酬(Salary)为基础升序排序记录的HCQL示例
Criteria c =session.createCriteria(类名.class);
c.addOrder(Order.asc("salary"));
List list=c.list();
- HCQL及投影
Criteria c =session.createCriteria(Emp.class);
c.setProjection(Projections.property("name"));
List list=c.list();
Restrictions类
- Restrictions类提供可用作标准的方法。 常用的Restrictions类方法如下:
public static SimpleExpression lt(String propertyName,Object value)
-->将给定属性的约束设置为小于约束。
public static SimpleExpression le(String propertyName,Object value)
-->设置给定属性的小于或等于约束。
public static SimpleExpression gt(String propertyName,Object value)
-->设置给定属性的大于约束。
public static SimpleExpression ge(String propertyName,Object value)
-->设置给定属性的大于或等于约束。
public static SimpleExpression ne(String propertyName,Object value)
-->对给定的属性设置不相于约束。
public static SimpleExpression eq(String propertyName,Object value)
-->设置约束与给定属性相等。
public static Criterion between(String propertyName, Object low, Object high)
-->设置约束之间范围。
public static SimpleExpression like(String propertyName, Object value)
-->将类似的约束设置为给定的属性。
Order类
- Order类代表排序顺序。常用的 Restrictions 类方法如下:
public static Order asc(String propertyName) 适用于给定属性的基础上,按升序排列。
public static Order desc(String propertyName) 适用于给定属性的基础上,按降序排列。