Hibernate课程
1. JDBC的优点和缺点
JDBC的优点
直接底层操作,提供了很简单、便捷的访问数据库的方法,跨平台性比较强。灵活性比较强,可以写很复杂的SQL语句。
JDBC的缺点
因为JAVA是面向对象的,JDBC没有做到使数据能够面向对象的编程,使程序员的思考仍停留在SQL语句上。
操作比较繁琐,很多代码需要重复写很多次。
如果遇到批量操作,频繁与数据库进行交互,容易造成效率的下降。
JDBC的程序操作可以封装一些什么内容?又不可以封装哪些内容?
2. Hibernate
为什么要用Hibernate
Hibernate实现了面向对象的数据库编程
Hibernate比起JDBC来,在代码的书写上比较简单化了。
Hibernate提出了缓存机制,这样可以使访问数据的效率提高很大。
第一个Hibernate程序
例子包括的内容:
项目所需要的LIB包
配置文件hibernate.cfg.xml
持久化类 Customer.java
映射文件 Customer.hbm.xml
结论:通过这个例子可以看到利用面向对象的技术也可以操作数据库。Hibernate就是一个面向对象操作数据库的框架,是基于JDBC开发的。
例子解析
配置文件:
Hibernate.connection.url 表示要链接的数据库地址
Hibernate.connection.driver_class 表示要链接的数据库的驱动类
Hibernate.connection.username 要连接的数据库的用户名
Hibernate.connection.password 要连接的数据库的密码
Hibernate.dialect 表示要使用的数据库的类型
org.hibernate.dialect.MySQL5Dialect mysql数据库
org.hibernate.dialect.Oracle9Dialect oracle数据库
org.hibernate.dialect.SQLServerDialect SQLServer数据库
hibernate.hbm2ddl.auto
validate:加载hibernate时验证创建表结构
update:加载hibernate时自动更新数据库结构,如果表存在不用创建,如果不存在就创建。
create:每一次加载hibernate时都创建表结构
create-drop:加载hibernate时创建,退出时删除
持久化类:
映射文件:
客户端:
查询例子:
删除例子:
更新例子:
保存例子:
l Cnfiguration 类负责管理 Hibernate 的配置信息。包括如下内容:
• Hibernate运行的底层信息:数据库的URL、用户名、密码、JDBC驱动类,数据库Dialect,数据库连接池等(对应 hibernate.cfg.xml 文件)。
• 持久化类与数据表的映射关系(*.hbm.xml 文件)
l 创建 Configuration 的两种方式
• 属性文件(hibernate.properties):
Configuration cfg = new Configuration();
• Xml文件(hibernate.cfg.xml)
Configuration cfg = new Configuration().configure();
第二种创建方式较为常见。Hibernate.cfg.xml文件默认的目录为系统的根目录。
(展示源代码以得到证实)
也可以利用config.config方法来指定配置文件所在的目录。
l Configuration对象根据当前的配置信息生成 SessionFactory 对象。SessionFactory 对象一旦构造完毕,即被赋予特定的配置信息(SessionFactory 对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。同时,SessionFactory还负责维护Hibernate的二级缓存)。
Configuration cfg = new Configuration().configure();
SessionFactory sf = cfg.buildSessionFactory();
l 是线程安全的。
l SessionFactory是生成Session的工厂:
Session session = sf.openSession();
l 构造 SessionFactory 很消耗资源,一般情况下一个应用中只初始化一个 SessionFactory 对象。
l 在Hibernate中,Transaction tx = session.beginTransaction()相当于给数据库操作起事务。Session.commit()则为提交事务。
l Hibernate的整个运行过程如下:
1、应用程序先调用Configuration类,该类读取Hibernate配置文件及映射文件中的信息,
2、并用这些信息生成一个SessionFactory对象,
3、然后从SessionFactory对象生成一个Session对象,
4、并用Session对象生成Transaction对象;
A、可通过Session对象的get(),load(),save(),update(),delete()和saveOrUpdate()等方法对PO进行加载、保存、更新、删除、等操作;
B、在查询的情况下,可通过Session对象生成一个Query对象,然后利用Query对象执行查询操作;如果没有异常,Transaction对象将提交这些操作到数据库中。
ORM框架 ------hibernate
1.开源的持久层框架.
2.ORM(Object/Relational Mapping)映射工具,建立面向对象的域模型和关系数据模型之间的映射.
3.连接java应用和数据库的中间件.
4.对JDBC进行封装,负责java对象的持久化.
5.在分层结构中处于持久化层,封装对数据库的访问细节,
使业务逻辑层更专注于实现业务逻辑
Hibernate的优点:
1、Hibernate对JDBC访问数据库的代码做了封装,大大简化
了数据访问层繁琐的重复性代码。
2、Hibernate是一个基于jdbc的主流持久化框架,是一个优秀
的orm实现,它很大程度的简化了dao层编码工作。
3、Hibernate使用java的反射机制,而不是字节码增强程序类实现
透明性
4、Hibernate的性能非常好,因为它是一个轻量级框架。映射的灵
活性很出色。它支持很多关系型数据库,从一对一到多对多的各
种复杂关系。
5、Hibernate使数据库的操作完全面向对象。而不是从前的面向关系进行操作。
建立ORM思想
应用Hibernate意味着程序员将不直接操作SQL语句,也就是说以前对SQL的直接操作现在要用面向对象实现。实际上ORM到JDBC是紧密相连的。于此带来了一些问题:
主键是怎么样产生的
一对多、多对一的关系在面向对象中是怎么样去实现的
面向对象是怎么样由面向对象的操作映射到对SQL的操作
3. 主键生成机制
表示符生成器 | 描述 |
Increment | 由hibernate自动以递增的方式生成表识符,每次增量为1 |
Identity | 由底层数据库生成表识符。条件是数据库支持自动增长数据类型。 |
Sequence | Hibernate根据底层数据库序列生成标识符。条件是数据库支持序列。 |
Native | 根据底层数据库对自动生成表示符的能力来选择identity、sequence、hilo |
Uuid.hex | Hibernate采用128位的UUID算法来生成标识符。该算法 能够在网络环境中生成唯一的字符串标识符,这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间。 |
assigned | 适用于自然主键。由java程序负责生成标识符。不能把setID()方法声明为 Private的。尽量避免使用自然主键。 |
increment 标识符生成器
l increment 标识符生成器由 Hibernate 以递增的方式为代理主键赋值
l Hibernate 会先读取 NEWS 表中的主键的最大值, 而接下来向 NEWS 表中插入记录时, 就在 max(id) 的基础上递增, 增量为 1.(带走+1)
l 适用范围:
• 由于 increment 生存标识符机制不依赖于底层数据库系统, 因此它适合所有的数据库系统
• 适用于只有单个 Hibernate 应用进程访问同一个数据库的场合
• OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常
identity 标识符生成器
l identity 标识符生成器由底层数据库来负责生成标识符, 它要求底层数据库把主键定义为自动增长字段类型(加1带走)
l 适用范围:
• 由于 identity 生成标识符的机制依赖于底层数据库系统, 因此, 要求底层数据库系统必须支持自动增长字段类型. 支持自动增长字段类型的数据库包括: DB2, Mysql, MSSQLServer, Sybase 等
• OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常
sequence 标识符生成器
l sequence 标识符生成器利用底层数据库提供的序列来生成标识符.
l Hibernate 在持久化一个 News 对象时, 先从底层数据库的 news_seq 序列中获得一个唯一的标识号, 再把它作为主键值
l 适用范围:
• 由于 sequence 生成标识符的机制依赖于底层数据库系统的序列, 因此, 要求底层数据库系统必须支持序列. 支持序列的数据库包括: DB2 Oracle 等
• OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常
native 标识符生成器
l native 标识符生成器依据底层数据库对自动生成标识符的支持能力, 来选择使用 identity, sequence 或 hilo 标识符生成器.
l 适用范围:
• 由于 native 能根据底层数据库系统的类型, 自动选择合适的标识符生成器, 因此很适合于跨数据库平台开发
• OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常
assigned 标识符生成器
l hibernate和底层数据库都不帮助你生成主键,也就是说得自己在程序中手动的设置主键的值。
l 适用范围:
主键有一定的含义,需要根据业务产生的情况。
Uuid标识符生成器
l Hibernate采用128位的UUID算法来生成标识符。该算法能够在网络环境中生成唯一的字符串标识符,这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间
l 使用范围:
主键是字符串,而且必须是唯一
4. Myeclipse开发hibernate
开发步骤
1、 新建一个JavaProject工程 myeclipsehibernate
2、 添加Hibernate到myeclipsehibernate.
3、 生成以后的结构如图所示:
4、 利用hibernate自带的工具自动生成持久化类和映射文件。
具体方法在课堂上进行演示。
5、 建立客户端进行编辑
HibernateSessionFactory类
利用ThreadLocal类保证了Session的线程安全。具体内容看代码是怎么样形成的。
5. 映射一对多关联关系
单向关联
仅仅建立从Order到Customer的多对一关联,即仅仅在Order类中定义customer属性。或者仅仅建立从Customer到Order的一对多关联,即仅仅Customer类中定义orders集合。
单向 n-1 关联只需从 n 的一端可以访问 1 的一端
域模型: 从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中无需定义存放 Order 对象的集合属性
关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
Hibernate 使用 <many-to-one> 元素来映射多对一关联关系
先保存订单,再保存客户
从这里可以看出执行了两条insert语句,一条update语句
先保存客户,再保存订单
可以看出这种情况程序是执行了两条insert语句,而没有执行update语句。
查询订单
先保存客户,再保存订单,在下面的代码中注释掉session.save(c),会有什么后果
级联保存和更新
当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,会抛出TransientObjectException.如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。
双向关联
双向 1-n 与 双向 n-1 是完全相同的两种情形
双向 1-n 需要在 1 的一端可以访问 n 的一端, 反之依然.
域模型:
从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性
关系数据模型:
ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
建立一对多的双向关联关系
Hibernate使用set元素来映射一对多关联关系
保存客户和订单(客户和订单建立双向关联)
保存客户和不保存订单
在下面的代码中注释掉session.save(order1),会有什么后果
级联保存和更新
当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,会抛出TransientObjectException.如果设定set元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。
查询客户和订单
查询客户和订单(图)
保存客户或订单的区别
保存订单时会发出两条insert语句。
Hibernate: select max(id) from customers
Hibernate: insert into customers (name, id) values (?, ?)
Hibernate: insert into orders (order_number, price, customer_id) values (?, ?, ?)
而保存客户时会发出两条insert语句和一条update语句
Hibernate: select max(id) from customers
Hibernate: insert into customers (name, id) values (?, ?)
Hibernate: insert into orders (order_number, price, customer_id) values (?, ?, ?)
Hibernate: update orders set customer_id=? where id=?
因为订单是多的一方,而客户是一的一方,所以在多对一的关系中,应该使用一的一方进行操作,这样效率更高。
订单变更客户
上述例子产生了两条update语句:
Hibernate: update orders set order_number=?, price=?, customer_id=? where id=?
Hibernate: update orders set customer_id=? where id=?
原因为:
Hibernate会自动清理缓存中的所有持久化对象,按照持久化对象的改变来同步更新数据库,因此执行了上述的两条更新语句所以会产生两条update语句
c4.getOrders().add(o6)执行了一条update语句
o6.setCustomer(c4)执行了一条update语句
级联删除
inverse属性
Inverse来源
在hibernate中通过对 inverse 属性的值决定是由双向关联的哪一方来维护表和表之间的关系. inverse=false 的为主动方,inverse=true 的为被动方, 由主动方负责维护关联关系
Inverse设值
在没有设置 inverse=true 的情况下,父子两边都维护父子关系
Inverse设值原则
在 1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)
在 1-N 关系中,若将 1 方设为主控方 会额外多出 update 语句
在一的一方设值inverse为TRUE表明一的一方不维护其关系,这样就会发出一条update语句,这样效率也就提高了。
Inverse结论
1.在映射一对多的双向关联关系时,应该在one方把inverse属性设为true,
这可以提高性能。
2.在建立两个对象的关联时,应该同时修改关联两端的相应属性:
customer.getOrders().add(order);
order.setCustomer(customer);
这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码
不受Hibernate实现类的影响。同理,当删除双向关联的关系时,也应该修改
关联两端的对象的相应属性:
Customer.getOrders().remove(order);
Order.setCustomer(null);
解除关联关系
解除某个订单与某个客户的关系
这样在order表中,ID为6的相应的外键为3的那行的外键会置为null;
级联删除
cascade属性
在数据库中对集合进行排序
<set> 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序
6. 深入Session
session概述
Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载Java 对象的方法.
理解session的缓存
l 在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期
l 当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图load()对象时,会判断缓存中是否存在该对象,有则返回。没有在查询数据库
清理session的缓存
l Session 具有一个缓存, 位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为清理缓存(flush)
l 默认情况下 Session 在以下时间点清理缓存:
• 当应用程序调用 Transaction 的 commit()方法的时, 该方法先清理缓存(session.flush()),然后在向数据库提交事务(tx.commit())
• 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先清理缓存,以保证查询结果能够反映持久化对象的最新状态
• 显式调用 Session 的 flush() 方法.
l 区别:
flush: 进行清理缓存(此时缓存中的数据并不丢失)的操作,让缓存和数据库同步 执行一些列sql语句,但不提交事务,;
commit:先调用flush() 方法,然后提交事务. 则意味着提交事务意味着对数据库操作永久保存下来。
reresh:刷新,让session和数据库同步,执行查询,把数据库的最新信息显示出来,更新本地缓存的对象状态.
clear:清空缓存,等价于list.removeAll();
利用Session缓存读取持久化对象的数据
1 Customer c = new Customer(“TOM”,new HashSet());
2 session.save(c); //customer对象被持久化,并且加入到session的缓存中
3 Long id = c.getId();
4 c = null; //c变量不再引用customer对象
5 //从session缓存中读取customer对象,使c2变量引用customer对象
6 Customer c2 = (Customer)session.load(Customer.class,id);
7 tx.commit(); //缓存中的对象和数据库同步
8 session.close(); //关闭session 清空缓存
9 System.out.println(c2.getName()); //访问customer对象
10 C2 = null; //C2对象不再引用customer对象,customer对象结束生命周期
---------------------------------------------------------------------------------------------
缓存的作用:
1。减少访问数据库的频率。
2。保证缓存中的对象与数据库中的相关记录保持同步。
Session执行批量操作
可以写一个for循环,Session可以批量插入上万条数据。如下面的代码:
For(int i=0;i<10000;i++){
Session.save(object);
}
这样写的代码会产生一个什么问题?会使一万个对象的缓存全部存在于内存中,这样做加大了内存的压力。所以应该定期清理session的缓存,也就是flush一下,这样内存才能保证足够的空间。
7. 持久化对象的状态
持久化对象有3种状态:
持久化状态
临时状态
游离状态
Session 的特定方法能使对象从一个状态转换到另一个状态
临时对象(transient)
• 在使用代理主键的情况下, OID 通常为 null
• 不处于 Session 的缓存中
• 在数据库中没有对应的记录
持久化对象(也叫”托管”)(Persist)
• OID 不为 null
• 位于 Session 缓存中
• 持久化对象和数据库中的相关记录对应
• Session 在清理缓存时, 会根据持久化对象的属性变化, 来同步更新数据库
• 在同一个 Session 实例的缓存中, 数据库表中的每条记录只对应唯一的持久化对象
游离对象(也叫”脱管”)(Detached)
• OID 不为 null
• 不再处于 Session 的缓存中
• 一般情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录
Session使用以下方法可以使持久化对象转变成游离对象:
测试hibernate中对象变化的状态:
程序代码 | 生命周期 | 状态 |
tx = session.beginTransaction(); Customer c = new Customer); | 开始生命周期 | 临时状态 |
Session.save(c) | 处于生命周期中 | 转变为持久化状态 |
Long id=c.getId(); c = null; Customer c2 = (Customer)session.load(Customer.class,id); tx.commit(); | 处于生命周期中 | 处于持久化状态 |
session.close(); | 处于生命周期中 | 转变为游离态 |
c2.getName(); | 处于生命周期中 | 处于游离态 |
c2 = null; | 结束生命周期 | 结束生命周期 |
对象状态转化图
对象状态的总结
操纵持久化对象-save()
l Session 的 save() 方法使一个临时对象转变为持久化对象
l Session 的 save() 方法完成以下操作:
l 把 News 对象加入到 Session 缓存中, 使它进入持久化状态
l 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID. 在使用代理主键的情况下, setId() 方法为 News 对象设置 OID 使无效的.
l 计划执行一条 insert 语句,把Customer对象当前的属性值组装到insert语句中
l Hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的对应关系. 当 News 对象处于持久化状态时, 不允许程序随意修改它的 ID
操纵持久化对象-update()
l Session 的 update() 方法使一个游离对象转变为持久化对象, 并且计划执行一条 update 语句.
操纵持久化对象-saveOrupdate()
saveOrUpdate:
该方法同时包含save和update方法,如果参数是临时对象就用save方
法,如果是游离对象就用update方法,如果是持久化对象就直接返回。
如果参数是临时对象就用save方法
如果是游离对象就用update方法
如果是持久化对象就直接返回,不执行操作
8. Session.load与session.get方法
不同场合的不同解决方案
场合一:当用户要取数据库的一张表的一个字段,这个字段很可能就是一个字符,总而言之长度是比较短的。
场合二:当用户要取数据库的一张表的一个字段的值,而这个值很可能是blob类型,也许存取的是一个很大的视频文件。
两种场合的取数据的方法一样吗?是用load还是用get方法?
延迟加载
类的延迟加载
lazy 为true或者为false
集合的延迟加载
True false extra
extra为更进一步的延迟加载策略。
当调用getStudents()时不会加载hql语句,当加载student的属性的时候才会发出SQL语句
调用getStudents().size()方法的时候,会触发类似于:Hibernate: select count(id) from T_Student where classid =? 这样的SQL查询语句(这是一种很聪明的做法,如果lazy=”true”,getStudents().size()将会使得hibernate加载所有集合的数据到内存中)。
调用getStudents().contains()方法的时候(即判断是否包含某个对象),会触发类似于:select 1 from T_Student where classid =? and id =? 这样的SQL查询语句。
单端关联
False proxy no-proxy
proxy:当前对象的単值相关对象只有在调用它的主键外的其他属性的get方法时才加载它。
no-proxy:当前对象的単值相关对象只有在调用它的属性时才加载,需要字节码增强。
9. Hibernate检索策略
初始化数据
类级别检索策略
立即检索
延迟检索
默认的检索策略是立即检索。在Hibernate映射文件中,通过在<class>上配置 lazy属性来确定检索策略。对于Session的检索方式,类级别检索策略仅适用于load方法;也就说,对于get、qurey检索,持久化对象都会被立即加载而不管lazy是false还是true.一般来说,我们检索对象就是要访问它,因此立即检索是通常的选择。由于load方法在检索不到对象时会抛出异常(立即检索的情况下),因此我个人并不建议使用load检索;而由于<class>中的lazy属性还影响到多对一及一对一的检索策略,因此使用load方法就更没必要了。
关联级别检索策略
fetch (默认值select) | Lazy (默认值是true) | 策略 |
Join | False | 采用迫切左外联接检索。 |
Join | True | 采用迫切左外联接检索。 |
join | Extra | 采用迫切左外联接检索。 |
select | False | 采用立即检索 |
select | True | 采用延迟检索 |
select | Extra | 采用延迟检索 c.getOrders().size() 执行 select count(id) from orders where customer_id =? for(Order o:set){ o.getOrderNumber();} 将执行: select customer_id , id,order_number ,price from orders where customer_id=? |
subselect | false/true/extra 也分为3中情况 | 嵌套子查询(检索多个customer对象时) Lazy属性决定检索策略) select customer_id,order_number,price from orders where customer_id in (select id from customers) |
检索策略 | 优点 | 缺点 | 优先考虑使用的场合 |
立即检索 | 对应用程序完全透明,不管对象处于持久化状态还是游离状态,应用程序都可以从一个对象导航到关联的对象 | (1)select语句多 (2)可能会加载应用程序不需要访问的对象,浪费许多内存空间。 | (1)类级别 (2)应用程序需要立即访问的对象 (3)使用了二级缓存 |
延迟检索 | 由应用程序决定需要加载哪些对象,可以避免执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并节省内存空间。 | 应用程序如果希望访问游离状态的代理类实例,必须保证她在持久化状态时已经被初始化。 | (1)一对多或者多对多关联 (2)应用程序不需要立即访问或者根本不会访问的对象 |
迫切左外连接检索 | (1)对应用程序完全透明,不管对象处于持久化状态还是游离状态,都可从一个对象导航到另一个对象。 (2)使用了外连接,select语句少 | (1)可能会加载应用程序不需要访问的对象,浪费内存。 (2)复杂的数据库表连接也会影响检索性能。 | (1)多对一 (2)需要立即访问的对象 (3)数据库有良好的表连接性能。 |
10. Hibernate的检索方式
HQL(Hibernate Query Language)
l HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:
l 在查询语句中设定各种查询条件
l 支持投影查询, 即仅检索出对象的部分属性
l 支持分页查询
l 支持连接查询
l 支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字
l 提供内置聚集函数, 如 sum(), min() 和 max()
l 能够调用 用户定义的 SQL 函数或标准的 SQL 函数
l 支持子查询
l 支持动态绑定参数
OID 检索方式
按照对象的 OID 来检索对象
QBC 检索方式
使用 QBC(Query By Criteria) API 来检索对象. 这种 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口.
简单的查询
使用别名
对查询结果排序
分页查询
l 分页查询:
l setFirstResult(int firstResult): 设定从哪一个对象开始检索, 参数 firstResult 表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0. 默认情况下, Query 从查询结果中的第一个对象开始检索
l setMaxResult(int maxResults): 设定一次最多检索出的对象的数目. 在默认情况下, Query 和 Criteria 接口检索出查询结果中所有的对象
检索单个对象
绑定参数的形式,按参数名称绑定
绑定参数的形式,按参数位置绑定
在映射文件中定义命名查询语句
hibernate检索方式
短语 | 含义 |
Expression.eq | 等于= |
Expression.allEq | 使用Map,使用key/value进行多个等于的判断 |
Expression.gt | 大于> |
Expression.ge | 大于等于>= |
Expression.lt | 小于< |
Expression.le | 小于等于<= |
Expression.between | 对应sql的between子句 |
Expression.like | 对应sql的like子句 |
Expression.in | 对应sql的in子句 |
Expression.and | and 关系 |
Expression.or | or关系 |
Expression.sqlRestriction | Sql限定查询 |
Expression.asc() | 根据传入的字段进行升序排序 |
Expression.desc() | 根据传入的字段进行降序排序 |
HQL和QBC支持的各种运算
运算类型 | HQL运算符 | QBC运算方法 | 含义 |
比较运算 | = | Express.eq() | |
<> | Express.not(Express.eq()) | ||
>= | Express.ge() | ||
< | Express.lt() | ||
<= | Express.le() | ||
is null | Express.isNull() | ||
is not null | Express.isNotNull() | ||
范围运算符 | In | Express.in() | |
not in | Express.not(Express.in()) | ||
Between | Express.between() | ||
not between | Express.not(Express.between()) |
HQL和QBC支持的各种运算
运算类型 | HQL运算符 | QBC运算方法 | 含义 |
字符串模式匹配 | Like | Expression.like() | |
逻辑 | And | Expression.and()| Expression.conjunction() | |
Or | Expression.or()| Expression.disjunction() | ||
Not | Expression.not() | ||
迫切左外连接
11. 二级缓存
缓存的概念
计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝。缓存的物理介质通常是内存
Hibernate中提供了两个级别的缓存
Session 级别的缓存
它是属于事务范围的缓存。这一级别的缓存由 hibernate 管理的,一般情况下无需进行干预
SessionFactory 级别的缓存
它是属于进程范围的缓存
启用二级缓存的条件
很少被修改
很多系统模块都要用到
不是私有的数据,是共享的
二级缓存的供应商
配置二级缓存
例子
从二级缓存中取数据
注:当二级缓存关闭以后会是一个怎么样的情况?