Hibernate框架入门(二)
第一章 hibernate中的实体规则
1.1 实体类创建的注意事项
1.持久化类需要提供无参的构造方法,因为hibernate底层需要使用反射生成类的实例。
2.成员变量私有,且要提供共有的get/set方法(类中的属性必须要有get/set方法,不管get/set方法是否有意义,如果没有的话那仅仅是成员变量)。
3.持久化类的属性尽量使用包装类型,不要用八大基本类型,比如int与integer,long与Long。包装类型能表达成null,数据库中很多字段不是必填的,很多是null,hibernate往基本数据类型放的时候会出问题。】
4.持久化类需要提供oid,与数据库中的主键列对应。
5.不要用final修饰class,hibernate使用的cglib代理生成代理对象,代理对象是继承被代理对象,如果被final修饰,将无法生成代理。
1.2 主键类型
自然主键:表的业务列中,有某列业务符合,必须有,并且不重复的特征时,该列可以作为主键。
代理主键:表的业务列中,没有某列业务符合,必须有,并且不重复的特征时,创建一个没有业务意义的列作为主键。
1.3 主键生成策略
每条记录录入时,主键的生成规则。
identity:主键自增,由数据库来维护主键的值,录入时不需要指定主键。
sequence:Oracle中的主键生成策略。
increment(了解):主键自增,由hibernate来维护,每次插入前会先查询表中id最大值。+1作为新主键值。
hilo(了解):高低位算法,主键自增,由hibernate来维护。
native:hilo+sequence+identity 自动三选一 策略
uuid:产生一个随机字符串,理论上不会重复,注意主键类型必须为uid。
assigned:自然主键生成策略。hibernate不会管理主键值,由开发人员自己指定。
第二章 hibernate中的对象状态
对象分为三种状态,瞬时态,持久化状态,游离/托管状态
瞬时态:没有id,没有与session关联
持久化状态:有id,与session有关联
游离/托管状态:有id,没有与session关联
其实与session有关联实际上就是放入了session缓存中。
save方法其实不能理解为保存,理解成将瞬时状态转换为持久化状态。
主键自增:执行save方法时,为了将对象转换为持久化状态,必须生成id值,所以需要执行insert语句交由数据库来生成id值。
increment:执行save方法,为了生成id,会执行查询id最大值的sql语句。
三种状态的转换图:
学习对象三种状态结论:将我们希望同步到数据库的数据,对应的对象转换为持久化状态,
第三章 hibernate一级缓存
缓存:提高效率,hibernate中的一级缓存也是为了提高操作数据库的效率。
当我们对同一个对象查询五次后,我们发现只用了一条语句。
缓存原理:以对象为单位进行缓存。
当我们对某对象进行修改时,修改两次却发现只发送了一条update语句,这是快照技术。
实例:
当用update时,将c1放入缓存中,不打印sql语句,当get时,因为缓存中存在c1,所以也不打印sql语句,最后事务提交时,根据上面的快照原理,因为缓存中存在c1,而快照中不存在对象,所以打印sql语句。
第四章 hibernate中的事务
4.1 事务的概念
a:原子性 事务所包括的操作时最小且不可分割的,要么全成功,要么全失败。
c:一致性 数据的总量不发生变化,一致性是原子性的衍生物。
i:隔离性 多个事务在并发中可能会出现一系列问题,如脏读,幻读等等,隔离性提供了一定的隔离级别,来解决并发产生的问题。
事物的并发问题: 脏读 不可重复读 幻读
脏读:读未提交的数据
不可重复读:两次读取的数据不一致,比如第一次读取完后有人进行了修改等等。
幻|虚读:在一个事务进行过程中,另一个事务进行一些操作,使第一个事务没有达到预期效果,让人感觉产生了幻觉。如:一个进行全部修改的操作,在快要修改结束时插入了另一个条数据,结果显示修改成功时,数据里仍存在未修改的数据。
通过设置隔离级别可以解决并发中的问题
读未提交:三种问题都有
读已提交:解决脏读
可重复读:解决不可重复读的问题,就是在事务执行期间会锁定该事务以任何方式引用的所有行,所以多次读取的数据就一样了(mysql的默认隔离级别)。
串行化:对数据的访问只允许串行,不允许并发,可解决所有问题,但是效率很低。
d:持久性 保证在事务提交后所涉及到的数据必须被写入到硬盘中。
4.2 在hibernate中设置数据库的隔离级别
在主配置文件中,对隔离级别进行设置。
4.3 在项目中如何管理事务
之前是在service层中管理事务,即在业务开始之前打开事务,业务执行之后提交事务,执行过程中出现异常,回滚事务。
所以下面的代码就有问题,我们要在service层中对事务进行控制。
在dao层操作数据库需要使用session对象,在service层中也需要使用session对象完成,我们要确保dao层和service层使用的是同一个session对象,类似于以前的connection对象,在service层中要使用connection对象,在dao层中也要使用connection对象,所以应用了一个线程本地化的threadlocal类,将connection绑定在了线程上,来确保在同一个线程内用的都是同一个connection,所以我们在这里还是采用这种方法,我们将session绑定在线程上。
在hibernate中,确保使用同一个session的问题,hibernate已经帮我们解决了,我们开发人员只需调用sf.getCurrentSession()方法,即可获得与当前线程绑定的session对象。
注意:1.调用getCurrentSession()方法必须配合主配置中的一段配置。
2.通过getCurrentSession()方法获得的session对象,当事务提交时,session会自动关闭,不要手动调用close关闭。否则会抛出异常。
实例代码:
dao层:
service层:
第五章 hibernate中的批量查询
5.1 HQL查询
全称hibernate Query language,是hibernate独家查询语言,属于面向对象的查询语言。
下图是查询所有,因为是查询所有所以select * 可以省略,其次要全类名,如果类是唯一的,可以只填写类名。
查询id为1的customer,注意要填类中的属性名,一般来说HQL语句中只会不会出现数据的表名和列名。
问号占位符的使用
set后面的类型,取决于查询标识的类型,比如id为long,那么查询要用long型。同时在hibernate中第一个?是从零开始的。若搞不清楚类型或者图省事可以用setParameter,
命名占位符的使用,冒号后跟一个字符串即可。
分页查询
setFirstResult是从第几页开始抓,setMaxResult是每页抓多少个。第一页是从零开始查。
5.2 Criteria查询
hibernate自创的无语句面对对象查询
一般都先要创建查询对象Criteria
查询所有
条件查询
在HQL语句中,不可能出现任何数据库的相关的信息,在Criteria对象中,利用add方法添加限制Restrictions来进行查询。
一般的条件有
分页:和上面的HQL有相似之处
查询总记录数:用setProjection来设置查询的聚合函数。
5.3 原生SQL查询
首先书写sql语句,创建查询对象传入sql语句,然后用List<Object[]>数组来接收查询结果。
要是想放到对象中,那么要先指定放到哪里
条件查询
分页查询