# Python 生成器
> 原文: [https://javabeginnerstutorial.com/python-tutorial/python-generator/](https://javabeginnerstutorial.com/python-tutorial/python-generator/)
本文旨在为 python 生成器提供一些温和的介绍,并希望能激发读者为他们找到有趣的用法。
这是一个有点复杂的主题,包含许多小细节,因此我们将使用下面的约定来提供更多信息。 随意跳过这些内容,因为它们不是理解所必需的,但是对于好奇的人,它们应该提供更多的见解。
## 什么是生成器?
生成器是功能强大的编程工具,可用于对大型或计算昂贵的数据进行有效的迭代。 与其他迭代方法相比,它还拥有更简单的代码和更好的性能。
实现 python 生成器的主要方法是:
* 生成器函数(在 Python 2.2 中添加)
* 生成器表达式(在 Python 2.4 中添加)
首先了解一些核心概念是必不可少的,因此现在让我们深入研究。
## 迭代和可迭代对象
您可能已经知道, *迭代*只是重复代码行的更正式术语,例如在`while`和`for`循环中。
基于*可迭代*对象的概念,Python 在该语言中内置了一种特别灵活的迭代方法,**经常在`for`循环中使用**。 每当我们以前谈论`for `循环时,**它们始终对可迭代对象进行操作**。
可迭代的对象通常是序列类型,例如列表,范围,元组或集合,在 Python 中,可迭代的对象意味着可以用`for`之类的东西来迭代对象。
```py
# These are all iterable objects that 'for' is operating on
my_list = [1,2,3,"Python",4]
my_tuple = (5,6,7,"Rocks")
my_set = {8,9,10}
for item in my_list:
print(item)
for item in my_tuple:
print(item)
for item in my_set:
print(item)
for x in range(5):
print(x)
```
> 在幕后,我们将对象称为“可迭代”这一事实意味着它公开了一个名为“`__iter__()`”的方法,该方法返回该对象的迭代器。
## 迭代器
迭代器是控制可迭代对象上的循环行为的对象。 其目的是跟踪到目前为止迭代已到达的位置。
当“`for`”函数和相关函数在可迭代对象上运行时,它们实际上首先要从该对象请求一个迭代器。 如果失败,则将引发异常,否则,该迭代器将反复用于获取序列中的下一项,直到序列用尽。
实际上,这意味着“`for`”可以循环可提供迭代器的任何对象,但不能在其他任何事情上循环。像`int`或`float`之类的对象不能与其一起使用,因为它们没有实现正确的方法。
```py
# Example: for statement works over a list, but not over a float
my_list = [3,5,7,9]
my_float = 1.1
for item in my_list:
print(item)
for item in my_float:
print(item)
```
### 输出
```py
3
5
7
9
Traceback (most recent call last):
File ".\examples\iterator_demo.py", line 23, in <module>
for item in my_float:
TypeError: 'float' object is not iterable
```
> 迭代器可以跟踪程序在循环中的位置,并在请求时提取下一个项目。
迭代器必须:
* 创建时将其设置为循环。
* 实现必须返回下一项的`__next __()`方法
* 循环结束时,`__next__()`方法还必须引发`StopIteration()`异常。
通常,迭代器对象使用存储在其属性之一中的循环计数器或类似计数器来跟踪其位置。 这是一个如何在实践中使用的示例:
* 创建一个迭代器:将循环计数器设置为零。
* 迭代器的`__next__()`称为:检查循环计数器
* 如果完成,则返回`StopIteration()`异常
* 如果还没有完成,请增加循环计数器并返回下一个项目
## 生成器细节
生成器可以看作是迭代器的经过改进的版本,旨在由程序员以更直观的方式编写,并使用更少的代码。 生成器和迭代器之间存在细微的差异:
* 生成器是一种特殊的迭代器
* 他们定义了类似行为的函数
* 他们跟踪自己的内部状态(例如局部变量),这与迭代器不同
> 为了扩展最后一点,迭代器在每次循环时都以新状态开始-对`__next__()`的每次调用都是一个新的函数调用,需要自己设置并创建自己的状态。
>
> 生成器不需要执行一次以上的设置-它可以重用上一次调用中的状态。 当运行相同的代码数千次时,这将变得更加高效。
在以下各节中,我们将介绍如何实现生成器,为什么从中受益于生成器以及一些可用代码示例。
**进一步阅读**:本文档中不涉及但与之紧密相关的高级主题包括:
* 将值发送到生成器(“`send()`”方法)
* 连接生成器(`yield from`表达式)
* 并发/并行处理/协程
在本文结尾处的一些参考文献中对它们进行了介绍,但是为了对所有这些概念进行很好的介绍,强烈建议特别使用 [Dave Beazley 的](http://www.dabeaz.com/generators-uk/)PPT。
## 实现生成器
### 生成器函数
生成器函数可能是在 Python 中实现生成器的最简单方法,但与常规函数和循环相比,它们的学习曲线仍然稍高。
简而言之,生成器函数是一种特殊的函数,可以在运行时逐个产生其结果,而不必等待完成并立即返回所有结果。
它们很容易发现,因为您会注意到,使用关键字“`yield`”返回值。 此处可以使用通常的“返回”,但只能退出该函数。
> 如果生成器没有设法“*产生*”任何数据,但是击中了“返回”,则调用者将返回一个空列表(`[]`)
以下是一些通常用于创建生成器函数的语法示例:
```py
# Form 1 - Loop through a collection (an iterable) and apply some processing to each item
def generator_function(collection):
#setup statements here if needed
for item in collection:
#do some processing
return_value = apply_something_processing_to(item)
yield return_value
# Form 2 - Set up an arbitrary loop and return items that are generated by that - similar to range() function
def generator_function(start,stop,step):
#setup statements here
loop_counter = <initial value based on start>
loop_limit = <final value based on stop>
#might need to add one to limit to be inclusive of final value
loop_step = <value to increment counter by, based on step>
#step could be negative, to run backwards
while loop_counter != loop_limit:
#do some processing
return_value = generate_item_based_on(loop_counter)
#increment the counter
loop_counter += loop_step
yield return_value
# Form 3 - Illustrates return mechanism - imagine the processing we're doing requires some kind of setup beforehand, perhaps connecting to a network resource
def generator_function(collection):
#setup statements here if needed
setup_succeeded = do_some_setup()
if setup_succeeded:
for item in collection:
#do some processing
return_value = apply_something_processing_to(item)
yield return_value
else:
return
```
如注释中所述,第一种形式逐步遍历可迭代的项目集合,并对每个项目进行某种处理,然后再“`yield`”。 虽然不是很令人兴奋,但对于简单的旧迭代当然可以实现,但是它的强大之处在于它可以成为其他生成器链的一部分。 由于每个项目需要更多的处理,生成器很快变得易于维护代码。
第二种形式是一个示例,可以适用于生成任意长度的值的序列,支持无限序列或无限循环序列等。 例如,该机制在处理数学或科学问题时非常有用。
这是调用生成器函数的一些示例语法:
```py
#Form 1 - more readable
my_generator = generator_function(arguments)
for result in my_generator:
output(result)
#Form 2 - more concise
for result in generator_function(arguments):
output(result)
```
在第一种形式中,在第一条语句中设置了生成器,并将对它的引用存储在变量中。 然后由以下“`for`”循环使用(或使用)它。
在第二种形式中,不存储生成器,而是由“`for`”循环立即使用生成器。
#### 实践中的生成器函数
这是说明创建和使用简单生成器函数的示例。 它将文本文件过滤为仅包含特定字符串的行。 它还显示了三种稍微不同的调用生成器的方式,有关详细信息,请参见注释:
```py
#Example: Generator Functions
def filtered_text(text_lines,wanted_text):
""" Compares each line in text_lines to wanted_text
Yields the line if it matches """
for line in text_lines:
if wanted_text in line:
yield line
#slow method - read whole file into memory, then use the generator to filter text
#need to wait for the whole file to load before anything else can begin
#uses more memory
#not much benefit here!
with open("Programming_Books_List.txt",'r') as file_obj:
lots_of_text = file_obj.readlines()
matches = filtered_text(lots_of_text,"Python")
for match in matches:
print(match)
#faster method - use the file object as an iterator, filter it with the generator
#only needs to keep current line in memory
#current line is only read directly before use
#outputs each match directly after it is found (before the file has finished reading)
with open("Programming_Books_List.txt",'r') as file_obj:
matches = filtered_text(file_obj,"Python")
for match in matches:
print(match)
#sleeker method - this is doing the same as the faster method above, but in fewer lines of code
#instead of storing the generator object in a variable, it is immediately used in a for loop
#this is perhaps less readable, so it can be harder to debug
with open("Programming_Books_List.txt",'r') as file_obj:
for match in filtered_text(file_obj,"Python"):
print(match)
```
### 生成器表达式
生成器表达式是创建简单生成器函数的另一种方法。 这些趋向于更加简洁,通常导致单行代码,但并不总是像生成器函数那样可读。
它们的主要缺点是它们不如生成器函数灵活。 很难在生成器表达式中实现任何特别复杂的操作,因为您限于可以在单个表达式中轻松编写的内容。
一些示例语法可能会有所帮助:
```py
#Form 1: basic form - iterate over all items, run some processing on each
new_generator = (apply_processing to(item) for item in iterable)
#Form 2: filter - rejects items if the condition is not true
new_generator = (item for item in iterable if condition)
#Form 3: combination of forms 1 and 2
new_generator = (apply_processing to(item) for item in iterable if condition)
```
它们看起来类似于列表推导,但实际上,列表推导会在返回之前将其整个输出构建到内存中的列表中,而生成器表达式一次只会返回其输出一项。
创建生成器后,即可使用与使用生成器函数几乎相同的方式来使用(或使用)生成器。 这里有一些示例:
```py
#Form 1 - more readable
my_generator = (apply_processing to(item) for item in iterable)
for result in my_generator:
output(result)
#Form 2 - more concise
for result in (apply_processing to(item) for item in iterable):
output(result)
```
#### 实践中的生成器表达式
这是上一本书的清单示例,使用表格 2 进行了覆盖:
```py
#Example: Generator Expressions
with open("Programming_Books_List.txt",'r') as file_obj:
for match in (line for line in file_obj if "Python" in line):
print(match)
```
注意,**仅需要这三行**。 使用生成器函数执行此操作所需的最少行数为 7。 这要简洁得多,并能生成精美的代码,但不能在所有情况下都使用。
## 为什么要使用生成器?
在以下情况下,生成器特别有用:
1. 对大量数据执行重复性任务,其中原始数据“仅需要一次”
2. 在长数据序列上执行计算(可能适合或可能不适合内存-甚至可能是无限的!)
3. 生成数据序列,其中仅应在需要时才计算每个项目(惰性求值)
4. 对数据流中的多个项目执行一系列相同的操作(在管道中,类似于 Unix 管道)
在第一种情况下,如果数据本身不需要存储在内存中或再次引用,则生成器非常有效。 它们使程序员可以零碎地处理较小的数据块,并逐一产生结果。 程序绝对不需要保留先前迭代中的任何数据。
生成器带来的好处是:
* 减少内存使用
* 比其他迭代方法更快的速度和更少的开销
* 它们可以优雅地构造管道
在上一个书单搜索示例中,使用生成器并没有真正对性能或资源使用带来任何好处,因为这是一个非常简单的用例,并且源数据不是很大。 而且,所需的处理非常少,以致于可以使用其他方法轻松实现。
但是,如果每行所需的处理复杂得多怎么办? 也许是某种文本分析,自然语言处理或根据字典检查单词?
假设在该示例中,我们还希望获取每个书名,在十个不同的在线书店中进行搜索,然后返回最便宜的价格。 然后,让我们扩展源数据,例如我们将图书清单替换为 Amazon 可用的每本图书的副本。
在这样的规模下,问题变得如此之大,以至于传统的迭代将需要大量资源,并且相对难以以任何效率进行编码。
在这种情况下,使用生成器将大大简化代码,并且意味着可以在找到第一个书名后立即开始处理。 此外,即使处理非常大的源文件,开销也很小。
## 基本用法
### 无限序列
到目前为止,使用生成器生成斐波那契数列的一个相当陈词滥调的示例在计算机科学教学界是一个古老的偏爱,但仍然值得一看。
这是代码:
```py
#Example: Fibonacci sequence using generators
def fibonacci(limit):
""" Generate the fibonacci sequence, stop when
we reach the specified limit """
current = 0
previous1 = 0
previous2 = 0
while current <= limit:
return_value = current
previous2 = previous1
previous1 = current
if current == 0:
current = 1
else:
current = previous1 + previous2
yield return_value
for term in fibonacci(144):
print(term)
```
其输出如下:
```py
0
1
1
2
3
5
8
13
21
34
55
89
144
```
这是一个非常琐碎的用例,但它确实说明了一个事实,即生成器正在处理其本地变量中的前两个值的存储,并且这些值在迭代之间不会丢失。 没有其他数据被存储,因此该函数在整个生命周期(从第一个迭代到十万次迭代)中将使用几乎相同数量的内存。
## 高级用法
### 使用生成器作为管道
管道是可以看到生成器实际功率的地方。 它们可以通过简单地将生成器链接在一起来实现,以使一个生成器的输出传递到下一个生成器的输入。 当需要对一组数据依次执行多项操作时,它们非常有用。
正如 Dave Beazley 的精彩演讲(请参阅参考资料)中所指出的那样,系统程序员可以充分利用生成器。 比兹利没有产生任意的数学序列,而是演示了有用的技术,例如解析 Web 服务器日志,监视文件和网络端口,遍历文件和文件系统等等。
下面是我自己的示例,该示例混合使用了生成器函数和表达式来对多个文件执行文本搜索。 我将其设置为在当前目录的所有 Python 文件中搜索字符串“`# TODO:`”。
> 每当我在代码中发现问题时,或者有一个以后想实现的想法时,我都想使用该表示法在尽可能靠近需要的地方插入待办事项。
>
> 它通常派上用场,但是在处理包含大量文件的大型项目时,这些说明可能会丢失!
这个示例有点费解,可以通过使用正则表达式(很有可能还有其他库或 OS 函数)进行改进,但是作为一个纯 Python 演示,它应该说明使用生成器可以实现的一些功能:
```py
# pipeline_demo.py
#Example: Search for "# TODO:" at start of lines in Python
# files, to pick up what I need to work on next
import os
def print_filenames(filenames):
"""Prints out each filename, and returns it back to the pipeline"""
for filename in filenames:
print(filename)
yield filename
def file_read_lines(filenames):
"""Read every line from every file"""
for filename in filenames:
with open(filename,'r') as file_obj:
for line in file_obj:
yield line
#get a list of all python files in this directory
filenames_list = os.listdir(".")
#turn it into a generator
filenames = (filename for filename in filenames_list)
#filter to only Python files (*.py)
filenames = (filename for filename in filenames if filename.lower().endswith(".py"))
#print out current file name, then pop it back into the pipeline
filenames = print_filenames(filenames)
#pass the filenames into the file reader, get back the file contents
file_lines = file_read_lines(filenames)
#strip out leading spaces and tabs from the lines
file_lines = (line.lstrip(" \t") for line in file_lines)
#filter to just lines starting with "# TODO:"
filtered = (line for line in file_lines if line.startswith("# TODO:"))
#strip out trailing spaces, tabs and newlines
filtered = (line.rstrip() for line in filtered)
#display output
for item in filtered:
print(item)
# TODO: Write generator example
# TODO: Test on current folder
# TODO: Test on a line indented with spaces
# TODO: Test on a line indented with tabs
# TODO: Add more TODOs
```
输出:
```py
test-TODOs.py
# TODO: Test finding a TODO in another file
test-noTODOs.py
pipeline_demo.py
# TODO: Write generator example
# TODO: Test on current folder
# TODO: Test on a line indented with spaces
# TODO: Test on a line indented with tabs
# TODO: Add more TODOs
```
这个想法可以进一步发展-如上所述,在系统编程中,甚至在系统管理空间中,都有无数的用例。 如果需要管理服务器上的日志文件,则这种技术将非常有价值。
请参阅以下参考资料,以获取有关该主题的更多信息和一些出色的示例。
您可以在 [JBTAdmin Github 上获得与本文相关的所有代码](https://github.com/JBTAdmin/python/tree/master/Generator%20Examples)。
## 参考书目/进一步阅读
标题:Python Wiki – 生成器
作者:多个
来源: [Python Wiki](https://wiki.python.org/moin/Generators)
标题:Python Wiki – 迭代器
Authors: Multiple
来源: [Python Wiki](https://wiki.python.org/moin/Iterator)
标题:Python 生成器
作者:斯科特·罗宾逊
资料来源:[滥用栈网站](http://stackabuse.com/python-generators/)
标题:Python 实践手册 – 第 5 章。迭代器&生成器
作者:Anand Chitipothu
资料来源: [Python 实践手册网站](https://anandology.com/python-practice-book/iterators.html)
标题:系统程序员的生成器技巧 – 版本 2.0
作者:David M. Beazley
资料来源: [David Beazley 的网站](http://www.dabeaz.com/generators-uk/)
标题:Python 生成器的 2 大好处(以及它们如何永久改变了我)
作者:亚伦·麦克斯韦(Aaron Maxwell)
来源: [O’Reilly 网站](https://www.oreilly.com/ideas/2-great-benefits-of-python-generators-and-how-they-changed-me-forever)
###### 下一篇文章
- JavaBeginnersTutorial 中文系列教程
- Java 教程
- Java 教程 – 入门
- Java 的历史
- Java 基础知识:Java 入门
- jdk vs jre vs jvm
- public static void main(string args[])说明
- 面向初学者的 Java 类和对象教程
- Java 构造器
- 使用 Eclipse 编写 Hello World 程序
- 执行顺序
- Java 中的访问修饰符
- Java 中的非访问修饰符
- Java 中的数据类型
- Java 中的算术运算符
- Java 语句初学者教程
- 用 Java 创建对象的不同方法
- 内部类
- 字符串构建器
- Java 字符串教程
- Java 教程 – 变量
- Java 中的变量
- Java 中的局部变量
- Java 中的实例变量
- Java 引用变量
- 变量遮盖
- Java 教程 – 循环
- Java for循环
- Java 教程 – 异常
- Java 异常教程
- 异常处理 – try-with-resources语句
- Java 异常处理 – try catch块
- Java 教程 – OOPS 概念
- Java 重载
- Java 方法覆盖
- Java 接口
- 继承
- Java 教程 – 关键字
- Java 中的this关键字
- Java static关键字
- Java 教程 – 集合
- Java 数组教程
- Java 集合
- Java 集合迭代器
- Java Hashmap教程
- 链表
- Java 初学者List集合教程
- Java 初学者的Map集合教程
- Java 初学者的Set教程
- Java 初学者的SortedSet集合教程
- Java 初学者SortedMap集合教程
- Java 教程 – 序列化
- Java 序列化概念和示例
- Java 序列化概念和示例第二部分
- Java 瞬态与静态变量
- serialVersionUID的用途是什么
- Java 教程 – 枚举
- Java 枚举(enum)
- Java 枚举示例
- 核心 Java 教程 – 线程
- Java 线程教程
- Java 8 功能
- Java Lambda:初学者指南
- Lambda 表达式简介
- Java 8 Lambda 列表foreach
- Java 8 Lambda 映射foreach
- Java 9
- Java 9 功能
- Java 10
- Java 10 独特功能
- 核心 Java 教程 – 高级主题
- Java 虚拟机基础
- Java 类加载器
- Java 开发人员必须知道..
- Selenium 教程
- 1 什么是 Selenium?
- 2 为什么要进行自动化测试?
- 3 Selenium 的历史
- 4 Selenium 工具套件
- 5 Selenium 工具支持的浏览器和平台
- 6 Selenium 工具:争霸
- 7A Selenium IDE – 简介,优点和局限性
- 7B Selenium IDE – Selenium IDE 和 Firebug 安装
- 7C Selenium IDE – 突破表面:初探
- 7D Selenium IDE – 了解您的 IDE 功能
- 7E Selenium IDE – 了解您的 IDE 功能(续)。
- 7F Selenium IDE – 命令,目标和值
- 7G Selenium IDE – 记录和运行测试用例
- 7H Selenium IDE – Selenium 命令一览
- 7I Selenium IDE – 设置超时,断点,起点
- 7J Selenium IDE – 调试
- 7K Selenium IDE – 定位元素(按 ID,名称,链接文本)
- 7L Selenium IDE – 定位元素(续)
- 7M Selenium IDE – 断言和验证
- 7N Selenium IDE – 利用 Firebug 的优势
- 7O Selenium IDE – 以所需的语言导出测试用例
- 7P Selenium IDE – 其他功能
- 7Q Selenium IDE – 快速浏览插件
- 7Q Selenium IDE – 暂停和反射
- 8 给新手的惊喜
- 9A WebDriver – 架构及其工作方式
- 9B WebDriver – 在 Eclipse 中设置
- 9C WebDriver – 启动 Firefox 的第一个测试脚本
- 9D WebDriver – 执行测试
- 9E WebDriver – 用于启动其他浏览器的代码示例
- 9F WebDriver – JUnit 环境设置
- 9G WebDriver – 在 JUnit4 中运行 WebDriver 测试
- 9H WebDriver – 隐式等待
- 9I WebDriver – 显式等待
- 9J WebDriver – 定位元素:第 1 部分(按 ID,名称,标签名称)
- 9K WebDriver – 定位元素:第 2 部分(按className,linkText,partialLinkText)
- 9L WebDriver – 定位元素:第 3a 部分(按cssSelector定位)
- 9M WebDriver – 定位元素:第 3b 部分(cssSelector续)
- 9N WebDriver – 定位元素:第 4a 部分(通过 xpath)
- 9O WebDriver – 定位元素:第 4b 部分(XPath 续)
- 9P WebDriver – 节省时间的捷径:定位器验证
- 9Q WebDriver – 处理验证码
- 9R WebDriver – 断言和验证
- 9S WebDriver – 处理文本框和图像
- 9T WebDriver – 处理单选按钮和复选框
- 9U WebDriver – 通过两种方式选择项目(下拉菜单和多项选择)
- 9V WebDriver – 以两种方式处理表
- 9W WebDriver – 遍历表元素
- 9X WebDriver – 处理警报/弹出框
- 9Y WebDriver – 处理多个窗口
- 9Z WebDriver – 最大化窗口
- 9AA WebDriver – 执行 JavaScript 代码
- 9AB WebDriver – 使用动作类
- 9AC WebDriver – 无法轻松定位元素? 继续阅读...
- 10A 高级 WebDriver – 使用 Apache ANT
- 10B 高级 WebDriver – 生成 JUnit 报告
- 10C 高级 WebDriver – JUnit 报表自定义
- 10D 高级 WebDriver – JUnit 报告自定义续
- 10E 高级 WebDriver – 生成 PDF 报告
- 10F 高级 WebDriver – 截屏
- 10G 高级 WebDriver – 将屏幕截图保存到 Word 文档
- 10H 高级 WebDriver – 发送带有附件的电子邮件
- 10I 高级 WebDriver – 使用属性文件
- 10J 高级 WebDriver – 使用 POI 从 excel 读取数据
- 10K 高级 WebDriver – 使用 Log4j 第 1 部分
- 10L 高级 WebDriver – 使用 Log4j 第 2 部分
- 10M 高级 WebDriver – 以无头模式运行测试
- Vue 教程
- 1 使用 Vue.js 的 Hello World
- 2 模板语法和反应式的初探
- 3 Vue 指令简介
- 4 Vue Devtools 设置
- 5 数据绑定第 1 部分(文本,原始 HTML,JavaScript 表达式)
- 6 数据绑定第 2 部分(属性)
- 7 条件渲染第 1 部分(v-if,v-else,v-else-if)
- 8 条件渲染第 2 部分(v-if和v-show)
- 9 渲染列表第 1 部分(遍历数组)
- 10 渲染列表第 2 部分(遍历对象)
- 11 监听 DOM 事件和事件修饰符
- 12 监听键盘和鼠标事件
- 13 让我们使用简写
- 14 使用v-model进行双向数据绑定
- 15 表单输入绑定
- 18 类绑定
- Python 教程
- Python 3 简介
- Python 基础知识 - 又称 Hello World 以及如何实现
- 如何在 Windows 中安装 python
- 适用于 Windows,Mac,Linux 的 Python 设置
- Python 数字和字符串
- Python 列表
- Python 集
- Python 字典
- Python 条件语句
- Python 循环
- Python 函数
- 面向对象编程(OOP)
- Python 中的面向对象编程
- Python 3 中的异常处理
- Python 3:猜数字
- Python 3:猜数字 – 回顾
- Python 生成器
- Hibernate 教程
- Hibernate 框架基础
- Hibernate 4 入门教程
- Hibernate 4 注解配置
- Hibernate 4 的实体关系
- Hibernate 4 中的实体继承模型
- Hibernate 4 查询语言
- Hibernate 4 数据库配置
- Hibernate 4 批处理
- Hibernate 4 缓存
- Hibernate 4 审计
- Hibernate 4 的并发控制
- Hibernate 4 的多租户
- Hibernate 4 连接池
- Hibernate 自举