hibernate 2
持久化类
-
持久化:将内存中的数据永久存储到关系型数据库
-
编写规则
- 提供无参构造方法:因为底层需要使用反射生成类的实例
- 属性私有,对私有属性提供公有的get和set方法:因为底层会将查询到的数据进行封装
- 属性尽量使用包装类的类型:因为包装类默认值与基本数据类型默认值不同
- 持久化类要有一个唯一标识符OID与表的主键对应:因为hibernate通过OID区分内存中是否是同一个持久化类
- 尽量不要使用final进行修饰:hibernate有延迟加载机制,这个机制会产生代理对象,hibernate产生代理对象使用的是字节码的增强技术完成的,其实也就是产生了当前类的一个子类对象实现,如果使用final修饰持久化类,就不能产生子类,也就不能产生代理对象,那么延迟加载机制(一种优化手段)也就失效
-
主键生成策略
- 自然主键:具有业务含有的字段如name
- 代理主键:不具备业务含义
- 策略
名称 描述 increment 用于long、short、int型,以递增的方式生成唯一标识符,每次加一,只有当没有其他进程向同一张表中插入数据时才能使用,不能在集群环境中使用,适用于代理主键 identity 采用底层数据库本身提供的主键生成标识符,条件是数据库支持自动增长数据类型,适用于代理主键 sequence 根据底层数据库序列生成标识符,条件是数据库支持序列,适用于代理主键 uuid 128位uuid算法生成标识符,能够在网络环境中生成唯一标识符,其uuid被编码为长度为32位的16进制字符串,不流行,因为占空间,适用于代理主键 assigned 由程序员负责生成标识符,如果不知道id元素的generator属性,默认使用该主键生成策略,适用于自然主键 native 根据底层数据库来选择identity、sequence、hile三种生成器中的一种 -
持久化对象三种状态
- 瞬时态(transient):也称临时态或者自由态
- 由new命令创建、开辟内存空间的对象,不存在持久化标志OID,尚未与hibernate session关联,在数据库中没有记录,失去引用后被JVM回收,仅是一个信息携带的载体
- 持久态(persistent)
- 存在持久化标志OID,加入到session缓存中,并且相关联是session没有关闭,在数据库中有相对应的记录
- 脱管态(detached)
- 存在持久化标志,仍然与数据库中的数据存在关联,只是失去了与当前session的关联,发生改变时hibernate不能检测到
- 区分:实体类new后即为瞬时态,session执行save等方法后进入持久态,session提交后即为脱管态(没有被session管理);另外,如果new后设置属性值,此时因为没有被session管理则进入脱管态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dwrIVBKw-1583938722055)(:storage\f491f6cf-8f76-41a9-b9c7-230f4aaf0e0c\3930d6ea.png)]
- 瞬时态(transient):也称临时态或者自由态
-
持久化对象能够自动更新数据库
Customer c = session.get(Customer.class, 1l);//持久化对象 c.setName("xiao"); //session.update(c); 不用手动调用 ...
缓存
一级缓存
- 一级缓存即session缓存,用来存放相互管理的java对象
- 使用Hibernate查询对象时,首先使用对象属性的OID值在一级缓存中进行查找,如果找到则直接从一级缓存中取出使用,不会再查询数据库;没有则去数据库中查找相应数据
- 可以减少对数据库的访问次数
- 特点
- 调用save()、update()、saveOrUpdate时,缓存中没有相应的对象,则自动从数据库中查询相应对象信息加入到一级缓存中
- 调用session的load()、get()、以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库
- 一级缓存的内部结构(快照区)
- hibernate向一级缓存放入数据时,同时复制一份数据到快照中,当使用commit提交事务时,会清理session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则会执行update方法,将缓存的内容同步到数据库并更新快照
事务控制
- 特性
- 原子性
- 一致性
- 隔离性
- 持久性
- 并发问题
- 脏读:读取到未提交的数据
- 不可重复读:数据更新导致多次查询不一致
- 虚读\幻读:读取到已经提交的insert数据,导致多次查询结果不一致
- 隔离级别
- 读未提交(read uncommitted 1级)
- 已提交读(Read committed, 2级)
- 可重复读(repeatable read, 4级)
- 序列化/串行化(Serializable,8级)
- 配置文件中设置事务隔离级别
<property name="hibernate.connection.isolation">隔离级别,用数字表示</property>
- 保证service开启的事务使用的session对象和DAO中多个操作使用的是同一个session对象
- 业务层获取session并将session作为参数传递到DAO
- 使用ThreadLocal将业务层获取的Sessio绑定到当前线程,然后在DAO中获取Session时,都从当前线程中获取(最优)
- Hibernate提供的三种管理Session对象的方法
- Session对象的生命周期与本地线程绑定
- Session对象的生命周期与JTA事务绑定
- Hibernate委托程序管理Session对象的生命周期
- 配置文件中,hibernate.current_session_context_class属性用于指定Session管理方式
- thread
- jta
- managed
其他API
Query
- 代表面向对象的查询操作,通常使用session.createQuery()方法接收HQL语句,然后调用Query的list()或uniqueResult()方法执行查询
//select all Query query = session.createQuery("from Customer"); List<Customer> list = query.list(); //条件查询 Query query = session.createQuery("from Customer where name = ?"); query.setString(0,"xiao"); List<Customer> list = query.list(); Query query = session.createQuery("from Customer where name = :aaa and age=:bbb"); query.setString("aaa","xiao"); query.setString("bbb",12); query.setFirstResult(3); query.setMaxResults(3); List<Customer> list = query.list();
Criteria
//查询所有记录
Criteria c = session.createCriteria(Customer.class);
List<Customer> list = c.list();
//条件查询
Criteria c = session.createCriteria(Customer.class);
criteria.add(Restrictings.eq("name","xiao"));
...
List<Customer> list = c.list();
//条件查询
Criteria c = session.createCriteria(Customer.class);
criteria.setFirstResult(3);
criteria.setMaxResults(3);
...
List<Customer> list = c.list();
SQLQuery
SQLQuery s = session.createSQLQuery("sql语句");
s.addEntity(customer.class);
List<Object[]> list = s.list();
for(Object[] o:list){
...
}