持久化类 = java类 + 映射文件
编写规则
- 对持久化类提供一个无参数的构造方法,hibernate底层需要反射生成实例。
- 属性私有,对私有属性提供public的get,set方法
- 对持久化类提供一个唯一表示oid和数据库主键关联
- 持久化类中属性尽量使用包装类类型
- 持久化类不要使用final进行修饰,因为如果该类不能被继承,也就无法产生代理对象,延迟加载也会失效。
主键生成策略
<id name="cust_id" column="cust_id">
<!--本地存储-->
<generator class="native"></generator>
</id>
- increment 提供自动增长机制,适用于short,int,long。不要在多线程中使用,会导致主键重复。因为使用的是select max(id)
- identity 使用数据库底层的自动增强机制
- sequence 适用于序列的方式 orcale支持序列
- native 本地策略,可以在identity和sequence之间切换
- Assigned 由程序本身控制
持久化类的三种状态
-
瞬时态
这种对象没有唯一的标识oid,没有被session管理
- 创建 new
- 转为持久 save,saveOrUpdate
- 转为脱管 给创建的对象设置id
-
持久态
有唯一的oid,被session管理,可以自动更新数据库
- 创建 get() load() find() iterate()
- 转为瞬时 delete()
- 转为脱管 session.close() clean() evict(obj)
-
脱管态
有唯一的id,没有被session管理
Customer customer = new Customer(); //瞬时态 customer.setCust_name("dwight"); session.save(customer); //持久胎 transaction.commit(); session.close(); System.out.println(customer.getCust_name()); // 脱管态
- 创建 new.obj.setid
- 转为持久 update , saveOrupdate
- 转为瞬时 new.setid(null)
一级缓存
跟session生命周期一致
指session缓存的java集合,用来存放相互管理的java对象,在使用hibernate查询的时候,首先会使用对象的oid值,在hebernate的一级缓存中进行查找,如果找到匹配oid值的对象,就会从一级缓存中取出使用,不会使用数据库查询,当调用close时会清空。
利用一级缓存作为key,快照区作为value。如果改变了一级缓存,则在commit时比较键值是否相同,如果不相同则会修改数据库。
session.clear(). session.evict(obj)可以清空一级缓存
事务
- 脏读:一个事物读到另一个事物未提交的数据
- 不可重复读:一个事物读到另一个事物已经提交的update数据,导致前一个事物多次查询结果不一致
- 幻读:一个事物读到另一个事物已经提交的insert数据,导致前一次事物多次查询结果不一致
事务的隔离级别
- 读未提交:以上问题都会发生
- 读提交:解决脏读,但是不可重复读和幻读都可能发生 orclae
- 重复读:解决不可重复读和脏读,但是幻读会发生 mysql
- 序列化:解决所有读问题,不能事物的并发
设置隔离级别
在hibernate.cfg.xml中
1 读未提交
-
读提交
-
重复读
-
序列化
<property name='hibernate.connection.isolation'>4</property>
保证serivce层连接
-
向下传递DButils
-
使用ThreadLocal对象
将连接绑定到当前线程中,在dao方法中,通过当前线程获得当前线程连接
在hibernate框架内部绑定好了ThreadLocal
sessionFactory中提供了一个方法getCurrentSession获取当前连接
1. 配置
<!--配置当前线程绑定session-->
<property name="hibernate.current_session_context_class">thread</property>
2. 调用
public static Session getCurrentSession(){
return sf.getCurrentSession();
}
此session不需要close()
Query HQL
String sql = "from Customer";
// 条件查询
String sql1 = "from Customer where cust_name like ?0";
Query query = session.createQuery(sql1);
// 分页查询
query.setFirstResult(0); //从第几页开始
query.setMaxResults(3); //每页数量
query.setParameter(0,"d%");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer.getCust_name());
}
一对多建表
- 在持久化类中通过一的一方的对象和多方的集合来关联,
private string cust_name;
private Man man; man时多的一方
...
private Set<Cust> cust
-
配置文件
// 配置多对一的关系,放置的是一的一方的对象 <many-to-one name="一的一方属性名称" class="一的一方类的全路径" column="在多的一方表的外键名称"></many-to-one> // 配置一对多的映射,放置的是多的一方的集合 在class标签中 <set name="多的一方集合的属性名称" cascade="save-update"> //级联可以在任意一方设置 <key colume=多的一方外键的名称""></key> <one-to-many class="多的一方类的全路径"/> <set>
-
编辑关系
linkman.setCustomer() customer.getLinkMans().add(linkMan) 两边必须都要保存
-
级联操作
cascade=save-update,delete
解决一对多 sql语句多余
在配置文件中,修改一的一方外键维护权,在多的一方配置inverse
<set name="多的一方集合的属性名称" cascade="save-update" inverse="true">
注意:在保存的时候,如果save(一的一方),级联到多的一方也保存, 多的一方可以维护外键,即可成功,反之,如果save(多的一方),级联到一的一方,那么会没有主键。所以保存的时候要保存一的一方。
多对多建表
两个关联的类都应该放置对方的集合
# 比如用户表和角色表
private Set<User> users = new HashSet<User>();
...
private Set<Role> roles = new HashSet<Role>();
-
配置文件
<set name="对方的集合属性名称" table="中间名称"> <key column="当前对象对应中间表的外键的名称"/> <many-to-many class="对方类的全路径" column="对方的对象对应中间表的外键的名称"/> </set>
-
保存操作
创建角色 Role role1 = new Role(); role1.setRole_name("研发部") user1.getRoles().add(role1); // 多对多建立了双向的关系,必须有一方放弃外键维护,一般是被动方放弃,比如角色,所以要在Role表中添加inverse=true session.save(user1)