提交 27b74620 编写于 作者: W wizardforcel

2020-06-24 20:17:09

上级 bbb75e8d
......@@ -92,7 +92,7 @@ public class FirstJunitTest {
**`@Before`** – 在指定的每种测试方法之前运行。 这用于各种目的。 读取或分配数据,初始化或如果多个测试需要先创建相似的对象才能执行,则最好在之前注释的方法下进行指定。
**`@After`** – 在执行每种测试方法之后运行。 通常,会指定与环境清理相关的命令,例如,关闭打开的资源/数据库连接,删除临时数据,释放内存等。即使`@Before``@Test`方法引发异常,也可以保证运行带`after`的方法。
**`@After`** – 在执行每种测试方法之后运行。 通常,会指定与环境清理相关的命令,例如,关闭打开的资源/数据库连接,删除临时数据,释放内存等。即使`@Before``@Test`方法引发异常,也可以保证运行带`after`的方法。
键入这些注释,在它们下方会出现一条弯曲的线。 悬停时,日食将建议所有可能的快速修复。 单击建议导入`org.junit`程序包的第一个修复程序。
......
# Hibernate Framework 基础
# Hibernate 框架基础
> 原文: [https://javabeginnerstutorial.com/hibernate/hibernate-framework-basic/](https://javabeginnerstutorial.com/hibernate/hibernate-framework-basic/)
## 什么是休眠
## 什么是 Hibernate
Hibernate 是 Java 语言的对象关系映射(ORM)库,它提供了一个框架,用于将面向对象的域模型映射到传统的关系数据库。 Hibernate 通过使用高级对象处理功能代替与持久性相关的直接数据库访问,解决了对象关系阻抗不匹配的问题。
......@@ -22,13 +22,13 @@ Hibernate 通过对象/关系映射促进了 Java 域对象的存储和检索。
例如:
DB2:org.hibernate.dialect.DB2Dialect
DB2:`org.hibernate.dialect.DB2Dialect`
MySQL:org.hibernate.dialect.MySQLDialect
MySQL:`org.hibernate.dialect.MySQLDialect`
## 什么是 HQL
HQL 是 [**Hibernate Query Language**](https://javabeginnerstutorial.com/hibernate/hibernate-4-with-query-languages/) 的缩写。 这是 hibernate 提供的 SQL 启发式语言。 开发人员可以编写类似查询的 SQL 来处理数据对象。
HQL 是 [**Hibernate 查询语言**](https://javabeginnerstutorial.com/hibernate/hibernate-4-with-query-languages/)的缩写。 这是 hibernate 提供的 SQL 启发式语言。 开发人员可以编写类似查询的 SQL 来处理数据对象。
## 连接池
......@@ -40,7 +40,7 @@ Hibernate 具有自己的内部[连接池](https://javabeginnerstutorial.com/hib
## Hibernate 关联
**什么是 Hibernate 关联**:数据库中的任何表都可以连接到同一数据库或其他数据库中的其他表。 这些表可以通过一些键(Foreign ..)相互关联。 这种情况可以由关联处理。
**什么是 Hibernate 关联**:数据库中的任何表都可以连接到同一数据库或其他数据库中的其他表。 这些表可以通过一些键(外键..)相互关联。 这种情况可以由关联处理。
例如:数据库中有 2 个表格,**学生**,和**科目**。 一个学生可以学习一个科目或一个以上的科目。 在这种情况下,每个学生在“学生”表中将只有一个条目,但“科目”表可能包含多个学生表中相应记录的记录。
......@@ -50,7 +50,7 @@ Hibernate 具有自己的内部[连接池](https://javabeginnerstutorial.com/hib
* 类(持久性)(POJO)
* 数据库表
* 映射文件(.hbm
* 映射文件(`.hbm`
**与 POJO 相关的规则**
......@@ -85,7 +85,7 @@ Hibernate 具有自己的内部[连接池](https://javabeginnerstutorial.com/hib
## 休眠缓存
缓存是提高系统性能的一种方法,因为它可以减少对数据库的查询。 查询数据库始终会对性能产生影响,因为它是 I / O 操作。 而且 I / O 操作比仅使用应用内存的操作要慢得多。 有两种类型的缓存。
缓存是提高系统性能的一种方法,因为它可以减少对数据库的查询。 查询数据库始终会对性能产生影响,因为它是 I/O 操作。 而且 I/O 操作比仅使用应用内存的操作要慢得多。 有两种类型的缓存。
* 一级缓存(实体缓存)
* 二级缓存(查询缓存)
......
......@@ -201,7 +201,7 @@ Java 8 by JBT (ISBN:9393939894
Hibernate 提供了一个很好的功能,可以利用 Java 对象和关系数据库之间的映射。 当然,该示例应用并没有显示 Hibernate 的全部功能:为了获得更好的用户体验,您可以添加一个用户界面来在应用中创建和列出书籍。
在下一篇文章中,我将展示如何摆脱 XML 配置(某些开发人员称为“XML-Hell”)并改为使用注释。 因此,请继续关注。
在下一篇文章中,我将展示如何摆脱 XML 配置(某些开发人员称为“XML 地狱”)并改为使用注释。 因此,请继续关注。
您可以在此处找到并下载应用[的源。](https://github.com/ghajba/hibernate_example/)
[您可以在此处找到并下载应用的源码](https://github.com/ghajba/hibernate_example/)
......@@ -2,27 +2,27 @@
> 原文: [https://javabeginnerstutorial.com/hibernate/hibernate-4-annotations-configuration/](https://javabeginnerstutorial.com/hibernate/hibernate-4-annotations-configuration/)
在最后的介绍性文章中,我提到了所谓的“XML-Hell”,它是 XML 在 Hibernate 配置中的大量使用。 在本文中,我将介绍基于注释的配置,您可以在其中使用 Hibernate 在实体上的注释来减少所需的 XML 数量。
在最后的介绍性文章中,我提到了所谓的“XML 地狱”,它是 XML 在 Hibernate 配置中的大量使用。 在本文中,我将介绍基于注释的配置,您可以在其中使用 Hibernate 在实体上的注释来减少所需的 XML 数量。
## 为什么注释很好
正如您将在示例代码中看到的那样:使用注释,您可以在实体类定义本身中看到属性映射是什么,因此您无需查找正确的`.hbm.xml`文件即可查找 映射定义。
而且有一个很好的副作用:您只需要修改实体。 例如,如果要向`Book`类添加新的 Date 字段,则还需要在`Book.hbm.xml`文件中添加映射。 使用注释,这只是 Java 类中的更改。 您将在本文后面的示例中找到有关使用日期的示例。
而且有一个很好的副作用:您只需要修改实体。 例如,如果要向`Book`类添加新的`Date`字段,则还需要在`Book.hbm.xml`文件中添加映射。 使用注释,这只是 Java 类中的更改。 您将在本文后面的示例中找到有关使用日期的示例。
### 一个例子
在此示例中,我将继续使用第一篇文章中介绍的 Book 实体。 现在,我将转换 POJO 以使用批注而不是 XML 配置-在本系列的后续部分中,我将继续介绍。 这是因为注释比 XML 更易于阅读和查找。
在此示例中,我将继续使用第一篇文章中介绍的`Book`实体。 现在,我将转换 POJO 以使用注解而不是 XML 配置-在本系列的后续部分中,我将继续介绍。 这是因为注释比 XML 更易于阅读和查找。
#### 实体
对于实体,我需要添加一些注释以表示与 XML 文件中相同的映射。
第一个是告诉 Hibernate `Book`类是一个实体。 我们可以通过`@Entity`批注来实现。 否则,Hibernate 将在启动时引发异常,并显示错误消息“`hibernate_example.Book`”是未知实体。
第一个是告诉 Hibernate `Book`类是一个实体。 我们可以通过`@Entity`注解来实现。 否则,Hibernate 将在启动时引发异常,并显示错误消息“`hibernate_example.Book`”是未知实体。
下一个是表定义。 我将书添加到`BOOKS`表中。 如果没有明确的表定义,Hibernate 会将实体添加到 `BOOK`表中。 通常,我可以说没有表定义,实体将保存在与实体类相同名称的表中。 要命名表,我必须在课程上使用`@Table`。 该注释具有名为*名称*的参数。 此名称定义表的名称-因此我添加了此属性并将其命名为 `BOOKS`
最后,我将 ISBN 定义为实体的 **ID**。 这是通过`@ID`完成的。
最后,我将 ISBN 定义为实体的 **ID**。 这是通过`@ID`完成的。
让我们看看整个修改后的实体:
......@@ -81,7 +81,7 @@
## 扩展实体
前面我提到过,添加日期字段有点复杂,因为映射日期并不是那么简单的动作。 为此,我需要在字段上使用`@Temporal`批注,以告知 Hibernate 我要将日期存储在数据库中,并且当我读取数据库时希望返回日期 信息。 `javax.persistence.TemporalType`告诉我要存储哪种信息。 现在是日期。
前面我提到过,添加日期字段有点复杂,因为映射日期并不是那么简单的动作。 为此,我需要在字段上使用`@Temporal`注解,以告知 Hibernate 我要将日期存储在数据库中,并且当我读取数据库时希望返回日期 信息。 `javax.persistence.TemporalType`告诉我要存储哪种信息。 现在是日期。
```java
@Temporal(TemporalType.DATE)
......@@ -102,7 +102,7 @@
## 结论
Hibernate 可以利用一组标准注释来消除映射 XML 文件的需要。 通过使用标准`javax.persistence`批注,您可以从 Hibernate 切换到另一个实现标准接口的 ORM 解决方案。
Hibernate 可以利用一组标准注释来消除映射 XML 文件的需要。 通过使用标准`javax.persistence`注解,您可以从 Hibernate 切换到另一个实现标准接口的 ORM 解决方案。
但是,如今有些开发人员正在谈论“注释地狱”,因为您几乎可以使用注释配置任何内容,有时这会使应用的可读性变差。
......
......@@ -50,9 +50,9 @@
如您所见,这里有一个新的注释:`@ManyToMany`。 这告诉 Hibernate `Author`实体映射到其他`Book`实体。 `mappingBy`属性用于告诉 Hibernate 哪个实体是关系的所有者。 这主要用于*一对多**多对一*关系中。
## 将作者添加到 Book 实体
## 将作者添加到`Book`实体
现在,将作者字符串更改为作者列表。 它看起来与 Author 实体完全相同:
现在,将作者字符串更改为作者列表。 它看起来与`Author`实体完全相同:
```java
@Entity
......@@ -114,7 +114,7 @@
}
```
在这里,我没有在`@ManyToMany`批注中添加任何参数,因为作者是所有者。
在这里,我没有在`@ManyToMany`注解中添加任何参数,因为作者是所有者。
## 关系类型
......@@ -122,15 +122,15 @@
### 一对一关系
对于一个实体,此关系类型仅包含一种引用类型,而对于另一实体也是如此。 在这种情况下,您可以选择用于存储参考的实体。例如,如果我将 ISBN 提取为具有其他一些属性的单独实体,则可能是 Books 与 ISBN 号之间的关系:一本书具有一本 ISBN 和一本 ISBN 准确地指一本书。
对于一个实体,此关系类型仅包含一种引用类型,而对于另一实体也是如此。 在这种情况下,您可以选择用于存储参考的实体。例如,如果我将 ISBN 提取为具有其他一些属性的单独实体,则可能是书籍与 ISBN 号之间的关系:一本书具有一本 ISBN 和一本 ISBN 准确地指一本书。
### 一对多和多对一关系
在这种情况下,一个实体在其他实体中具有许多引用。 如果一本书只能有一位作者,那就是这种情况。 在这种情况下,引用 I​​D 将存储在`BOOKS`表中,因为有一本书参考了其作者。 我们在作者实体中使用*一对多*,在 Book 实体中使用*多对一*
在这种情况下,一个实体在其他实体中具有许多引用。 如果一本书只能有一位作者,那就是这种情况。 在这种情况下,引用 I​​D 将存储在`BOOKS`表中,因为有一本书参考了其作者。 我们在作者实体中使用*一对多*,在`Book`实体中使用*多对一*
### 多对多关系
如您在第一个示例中所看到的,这种关系有点复杂。 在这里,我们需要一个单独的表格来包含书籍和作者之间的引用。 这就是所谓的**联接表**。 该表由 Hibernate 自动维护,但是您可以告诉该表如何命名。 如果您不选择名称,则 Hibernate 会使用实体名称,并用下划线将其分开,所有者名称为 site-entity。 在此示例中,联接表名为:`BOOKS_AUTHORS`
如您在第一个示例中所看到的,这种关系有点复杂。 在这里,我们需要一个单独的表格来包含书籍和作者之间的引用。 这就是所谓的**联接表**。 该表由 Hibernate 自动维护,但是您可以告诉该表如何命名。 如果您不选择名称,则 Hibernate 会使用实体名称,并用下划线将其分开,所有者名称为站点实体。 在此示例中,联接表名为:`BOOKS_AUTHORS`
## 更改`main`方法
......
......@@ -8,7 +8,7 @@
## HQL 和 JPQL
HQL 是 Hibernate 的默认查询语言(缩写为 Hibernate Query Language)。 JPQL 用于更通用的 Java 持久性查询语言,它是 HQL 的子集。 这意味着有效的 JQPL 查询也是有效的 HQL 查询-但并非总是如此。
HQL 是 Hibernate 的默认查询语言(缩写为 Hibernate 查询语言)。 JPQL 用于更通用的 Java 持久性查询语言,它是 HQL 的子集。 这意味着有效的 JQPL 查询也是有效的 HQL 查询-但并非总是如此。
HQL 背后的主要思想是,您可以在查询中使用实体名称,而不是数据库中的表名称。 这使存储和查询更加透明,您可以在开发人员之间划分任务,因为编写查询的人只需要知道实体名称即可。
......@@ -66,7 +66,7 @@ session.createCriteria(Author.class).add(Restrictions.like("name", "M%")).list()
为什么本地查询会更好? 因为您可以消除 Hibernate 本质上执行的一些连接。
例如,对带有 Hibernate 的 Authors 进行计数的查询最终会导致以下 SQL:
例如,对带有 Hibernate 的`Authors`进行计数的查询最终会导致以下 SQL:
```java
select count(*) from Author a inner join PERSONS p on a.name = p.name
......
......@@ -16,11 +16,11 @@
### 在哪里更改
更改将在`src/main/resources/`下的`hibernate.cfg.xml`文件中进行。 在这里,您必须在`<!– 数据库连接设置 –>`下的块中设置字段。
更改将在`src/main/resources/`下的`hibernate.cfg.xml`文件中进行。 在这里,您必须在`<!– 数据库连接设置 –>`下的块中设置字段。
这意味着以下参数:
* 正确的数据库驱动程序的 driver_class
* 正确的数据库驱动程序的`driver_class`
* 网址指向正确的数据库
* 合适用户的用户名
* 密码和正确的密码(对于 H2,大多数情况下未设置)
......@@ -36,18 +36,18 @@
我将在这里列出一些常用数据库的驱动程序。 但是,这意味着在运行应用时,您也需要在类路径上使用驱动程序。
* MySQL5:用于 InnoDB 表的 hibernate.dialect.MySQL5InnoDBDialect,用于其他的 org.hibernate.dialect.MySQL5Dialect
* Oracle:9i 及更高版本的 jdbc.OracleDriver
* MS SQL Server:microsoft.sqlserver.jdbc.SQLServerDriver
* PostgreSQL:postgresql.Driver
* MySQL5:用于 InnoDB 表的`hibernate.dialect.MySQL5InnoDBDialect`,用于其他的`org.hibernate.dialect.MySQL5Dialect`
* Oracle:9i 及更高版本的`jdbc.OracleDriver`
* MS SQL Server:`microsoft.sqlserver.jdbc.SQLServerDriver`
* PostgreSQL:`postgresql.Driver`
这些是最常用的关系数据库。 要将这些驱动程序放在示例项目中的类路径上,只需将正确的 JAR 导入为项目的 pom.xml 中的依赖项即可。
这些是最常用的关系数据库。 要将这些驱动程序放在示例项目中的类路径上,只需将正确的 JAR 导入为项目的`pom.xml`中的依赖项即可。
## 更新示例
现在该切换到永久性存储了。 在该示例中,我将使用 H2,因为它已经作为依赖项存在,并且与其他数据库不同,它不需要安装和配置,因此您也无需执行任何操作。
为了获得持久的 H2 商店,我只需将 connection.url 从 jdbc:h2:mem:db1;…更改为 jdbc:h2:file:./ example;…。 如您所见,区别在于使用**文件**而不是**内存**告诉 H2 它必须查找文件,并且该文件位置需要路径。
为了获得持久的 H2 存储,我只需将`connection.url``jdbc:h2:mem:db1;…`更改为`jdbc:h2:file:./example;…`。 如您所见,区别在于使用**文件**而不是**内存**告诉 H2 它必须查找文件,并且该文件位置需要路径。
如果您的`example.db`文件在本地不存在,请不要担心:如果缺少该文件,H2 将创建新的数据库文件。
......
# 使用 Hibernate 4 批量执行
# 使用 Hibernate 4 批处理
> 原文: [https://javabeginnerstutorial.com/hibernate/batch-execution-with-hibernate-4/](https://javabeginnerstutorial.com/hibernate/batch-execution-with-hibernate-4/)
......@@ -8,7 +8,7 @@
因为这比打开一个事务向数据库插入 1000000(一百万)个条目并最后提交或为每个相同容量的插入打开事务要好。
Batch 为您提供了管理此工具的正确工具:在 Hibernate 自动调用 commit 之后定义一个限制,以将您的数据持久存储在应用后面的数据库中。
批处理为您提供了管理此工具的正确工具:在 Hibernate 自动调用`commit`之后定义一个限制,以将您的数据持久存储在应用后面的数据库中。
## 天真的方法
......@@ -29,17 +29,17 @@ public static void naiveApproach() {
}
```
上面的代码做了我一开始所描述的:它打开一个事务并在插入 1000000 条记录后保存。 根据您的硬件,您可以到达循环的结尾并在结尾处调用一次提交。 如果您的内存不足,您的应用可能会抛出 OutOfMemoryException,因为 Hibernate 将所有新的 Book 实例存储在内存中的第二级缓存中。
上面的代码做了我一开始所描述的:它打开一个事务并在插入 1000000 条记录后保存。 根据您的硬件,您可以到达循环的结尾并在结尾处调用一次提交。 如果您的内存不足,您的应用可能会抛出`OutOfMemoryException`,因为 Hibernate 将所有新的`Book`实例存储在内存中的第二级缓存中。
为了进行测试,我将插入次数增加到 10000000(一千万),以查看应用崩溃之前需要花费多长时间。 凭借近三百万本新书,我达到了应用的 2 GB 内存。
为了进行测试,我将插入次数增加到 10000000(一千万),以查看应用崩溃之前需要花费多长时间。 凭借近三百万本新书,我达到了应用的 2GB 内存。
这意味着,如果二级缓存消耗了应用可用的所有内存,则数据库条目将消失,您可以重新开始。
## 设置批处理大小,将二级缓存保持在较低水平
为了使二级缓存的大小保持较低,您可以在`hibernate.cfg.xml`中引入批处理大小。 这将告诉休眠容器每隔 n 行要批量插入。 可以使用属性 hibernate.jdbc.batch_size 设置批处理大小。
为了使二级缓存的大小保持较低,您可以在`hibernate.cfg.xml`中引入批处理大小。 这将告诉休眠容器每隔 n 行要批量插入。 可以使用属性`hibernate.jdbc.batch_size`设置批处理大小。
有趣的是,Hibernate 的文档不仅引入了此属性,而且还需要修改上面的朴素代码(我只会复制相关的 for 循环):
有趣的是,Hibernate 的文档不仅引入了此属性,而且还需要修改上面的朴素代码(我只会复制相关的`for`循环):
```java
for (int i = 0; i < 1_000_000; i++) {
......@@ -52,7 +52,7 @@ for (int i = 0; i < 1_000_000; i++) {
}
```
如果仔细看一下上面的代码,您会看到解决方案是将批处理大小大块中的会话 flush()和 clear()保持为较低的二级缓存大小。
如果仔细看一下上面的代码,您会看到解决方案是将批处理大小大块中的会话`flush()``clear()`保持为较低的二级缓存大小。
### 那么为什么要设置批处理大小?
......@@ -64,9 +64,9 @@ for (int i = 0; i < 1_000_000; i++) {
但是,还有一些透明的限制,您最终将看不到。
一个示例是如果您使用 GenerationType.IDENTITY,则 Hibernate 透明地禁用批处理。
一个示例是如果您使用`GenerationType.IDENTITY`,则 Hibernate 透明地禁用批处理。
第二个示例是 Hibernate 查看要一起批处理的语句:如果当前语句与前一个相同,则在未达到 batch_size 的情况下将它们合并在一起。 在上面的示例中,语句相似,因此将它们批处理在一起。 但是,如果我们将“作者”和“书籍”一起添加到数据库中,则 Hibernate 会看到交替的语句,并且将从每个语句开始一个批处理组。 要解决此问题,可以使用 hibernate.order_inserts 和 hibernate.order_updates 属性。 这使 Hibernate 在插入之前对语句进行了排序,因此可以看到 50 个 Book 插入可以一起批处理,并且 50 个 Authors 可以一起批处理。
第二个示例是 Hibernate 查看要一起批处理的语句:如果当前语句与前一个相同,则在未达到`batch_size`的情况下将它们合并在一起。 在上面的示例中,语句相似,因此将它们批处理在一起。 但是,如果我们将“作者”和“书籍”一起添加到数据库中,则 Hibernate 会看到交替的语句,并且将从每个语句开始一个批处理组。 要解决此问题,可以使用`hibernate.order_inserts``hibernate.order_updates`属性。 这使 Hibernate 在插入之前对语句进行了排序,因此可以看到 50 个`Book`插入可以一起批处理,并且 50 个`Authors`可以一起批处理。
## 手动保存数据
......@@ -87,7 +87,7 @@ for (int i = 0; i < 1_000_000; i++) {
}
```
如果我们达到了 batch_size,则上面的代码将提交事务,并在会话上开始新事务,因为前一个事务已因提交而失效。
如果我们达到了`batch_size`,则上面的代码将提交事务,并在会话上开始新事务,因为前一个事务已因提交而失效。
## 结论
......
......@@ -2,15 +2,15 @@
> 原文: [https://javabeginnerstutorial.com/hibernate/caching-with-hibernate-4/](https://javabeginnerstutorial.com/hibernate/caching-with-hibernate-4/)
如果您有更大的应用,则应考虑性能以及如何提高性能。 缓存是执行此操作的一种方法,因为它可以减少对数据库的查询。 查询数据库始终会对性能产生影响,因为它是 I / O 操作。 而且 I / O 操作比仅使用应用内存的操作要慢得多。
如果您有更大的应用,则应考虑性能以及如何提高性能。 缓存是执行此操作的一种方法,因为它可以减少对数据库的查询。 查询数据库始终会对性能产生影响,因为它是 I/O 操作。 而且 I/O 操作比仅使用应用内存的操作要慢得多。
缓存在您的应用和数据库之间起作用,以尽可能避免数据库命中次数。
## 实体缓存
默认情况下,Hibernate 使用第一级缓存,这意味着它将通过会话将实体存储在应用的内存中(为 Hibernate 分配)。 它是所有实体都必须传递的强制性缓存。 这有两个好处:如果经常访问该实体,则 Hibernate 会记住它;如果您的应用再次需要该实体,则将从会话的缓存中返回它; 第二个好处是,如果您在一个实体上执行多个更新,则 Hibernate 尝试将这些更新分组在一起,并延迟实际的数据库调用以减少 I / O 流量。 如果关闭会话,则存储在第一级缓存中的对象将被销毁并保存或更新到数据库。
默认情况下,Hibernate 使用第一级缓存,这意味着它将通过会话将实体存储在应用的内存中(为 Hibernate 分配)。 它是所有实体都必须传递的强制性缓存。 这有两个好处:如果经常访问该实体,则 Hibernate 会记住它;如果您的应用再次需要该实体,则将从会话的缓存中返回它; 第二个好处是,如果您在一个实体上执行多个更新,则 Hibernate 尝试将这些更新分组在一起,并延迟实际的数据库调用以减少 I/O 流量。 如果关闭会话,则存储在第一级缓存中的对象将被销毁并保存或更新到数据库。
您可以使用可选的二级缓存来扩展此缓存。 一级始终是强制性的,始终会首先被咨询。 二级缓存用于跨会话缓存对象。 对于二级缓存,有一些第三方解决方案可以与 Hibernate 一起使用。 Hibernate 提供了 org.hibernate.cache。 提供程序必须实现 CacheProvider 接口,以使 Hibernate 处理缓存。
您可以使用可选的二级缓存来扩展此缓存。 一级始终是强制性的,始终会首先被咨询。 二级缓存用于跨会话缓存对象。 对于二级缓存,有一些第三方解决方案可以与 Hibernate 一起使用。 Hibernate 提供了`org.hibernate.cache`。 提供程序必须实现`CacheProvider`接口,以使 Hibernate 处理缓存。
市场上有一些缓存提供程序,但是 Hibernate 希望您为整个应用选择一个提供程序。
......@@ -29,7 +29,7 @@
* **只读**此策略应用于永远不会更新的持久对象。 这对于读取和缓存应用配置以及其他静态数据非常有用。 这是具有最佳性能的最简单的策略,因为没有重载可以检查是否在数据库中更新了实体。
* **读写**此策略对由应用更新的实体很有用。 但是,如果数据是通过数据库或其他应用更新的,则 Hibernate 无法判断是否发生了更改,并且您的数据可能已过时。
* **非受限读写**如果应用仅偶尔更新数据并且不需要严格的事务隔离,则此缓存策略可能是合适的。
* **事务性**此缓存策略为完全事务性缓存提供程序(例如 JBoss TreeCache)提供支持。 这样的缓存只能在 JTA 环境中使用,并且必须指定 transaction.manager_lookup_class
* **事务性**此缓存策略为完全事务性缓存提供程序(例如 JBoss TreeCache)提供支持。 这样的缓存只能在 JTA 环境中使用,并且必须指定`transaction.manager_lookup_class`
也不奇怪:EHCache 支持上述所有这四种策略,因此是开始使用二级缓存提供程序的不错选择。
......
# 使用 Hibernate 4 进行审
# 使用 Hibernate 4 进行审
> 原文: [https://javabeginnerstutorial.com/hibernate/auditing-with-hibernate-4/](https://javabeginnerstutorial.com/hibernate/auditing-with-hibernate-4/)
在本文中,我将向您简要介绍使用 Hibernate 进行实体审,或更具体地说,是使用 Hibernate Envers,因为这是 Hibernate 核心的 3.x 版本的一部分。
在本文中,我将向您简要介绍使用 Hibernate 进行实体审,或更具体地说,是使用 Hibernate Envers,因为这是 Hibernate 核心的 3.x 版本的一部分。
顺便说一句:Envers 保留用于实体版本控制。
## 我为什么要关心审计?
如果您从事较大的项目(或将来某个时候),则审将在您的应用中扮演重要角色,以监视谁更改了敏感数据。 有时仅监视谁进行了更改是不够的:您想知道已更改的内容以及哪些值也已更改。
如果您从事较大的项目(或将来某个时候),则审将在您的应用中扮演重要角色,以监视谁更改了敏感数据。 有时仅监视谁进行了更改是不够的:您想知道已更改的内容以及哪些值也已更改。
为此,您可以创建自己的自定义解决方案或使用 Hibernate Envers,它是 Hibernate 核心的一部分,提供了开箱即用的功能。
仅提及一个场景:您是汽车零售应用的开发人员。 有人出售一辆豪华轿车的正常价格要低 80% 的汽车,却没人知道谁改变了价格。 最后,您会感到内 gui,因为您没有监视,因此必须在很短的时间内解决此问题。
仅提及一个场景:您是汽车零售应用的开发人员。 有人出售一辆豪华轿车的正常价格要低 80% 的汽车,却没人知道谁改变了价格。 最后,您会感到后悔,因为您没有监视,因此必须在很短的时间内解决此问题。
如果听起来很绝望,并且您想袖手旁观,请继续阅读。
......@@ -28,7 +28,7 @@
</dependency>
```
如果您的类路径上有 Envers,只需在要审核的实体或属性上使用 [[受电子邮件保护]](/cdn-cgi/l/email-protection) 批注
如果您的类路径上有 Envers,只需在要审计的实体或属性上使用 [[受电子邮件保护]](/cdn-cgi/l/email-protection) 注解
```java
@Entity
......@@ -39,21 +39,21 @@
}
```
在这种情况下,Hibernate 自动管理实体的版本控制。 它将创建一个包含实体表名称和后缀 _AUD 的表。 在此示例 BOOKS_AUD 中,它在那里存储实体的所有字段以及两个额外的列:REVTYPE 和 REV
在这种情况下,Hibernate 自动管理实体的版本控制。 它将创建一个包含实体表名称和后缀`_AUD`的表。 在此示例`BOOKS_AUD`中,它在那里存储实体的所有字段以及两个额外的列:`REVTYPE``REV`
REVTYPE 是修订版本的类型,它可以采用值 add,mod,del 分别插入,修改或删除。
`REVTYPE`是修订版本的类型,它可以采用值`add``mod``del`分别插入,修改或删除。
REV 字段保存所存储条目的修订号。
`REV`字段保存所存储条目的修订号。
如果仅使用@Audited 注释对实体的一个或某些字段进行注释,则* _AUD 表将包含两个额外的审核字段,即使用@Audited 注释的字段和实体的 ID。
如果仅使用`@Audited`注释对实体的一个或某些字段进行注释,则`*_AUD`表将包含两个额外的审计字段,即使用`@Audited`注释的字段和实体的 ID。
Hibernate 创建了一个称为 REVINFO 的额外表,其中在实体发生更改时 REV 编号与时间戳进行映射。
Hibernate 创建了一个称为`REVINFO`的额外表,其中在实体发生更改时`REV`编号与时间戳进行映射。
## 自定义修订表
您可以根据需要自定义修订表,以使用所需的信息扩展核心功能。 正如我上面提到的,一种这样的情况是与实体更改一起记录与应用会话关联的当前用户(在 Web 应用的情况下)。
为此,您需要一个自定义@Entity 对象,该对象扩展了 org.hibernate.envers.DefaultRevisionEntity 并具有 [[受电子邮件保护]](/cdn-cgi/l/email-protection) 批注。 对于@RevisionEntity,如果要更新表中的数据,则必须添加自定义监听器类。 在此示例中,它将是用户名。 该监听器必须实现 org.hibernate.envers.RevisionListener 接口,如下所示。
为此,您需要一个自定义`@Entity`对象,该对象扩展了`org.hibernate.envers.DefaultRevisionEntity`并具有`@RevisionEntity`注解。 对于`@RevisionEntity`,如果要更新表中的数据,则必须添加自定义监听器类。 在此示例中,它将是用户名。 该监听器必须实现`org.hibernate.envers.RevisionListener`接口,如下所示。
```java
@Entity
......@@ -76,9 +76,9 @@ public class AuditRevisionListener implements RevisionListener {
}
```
## 在生产过程中切换审
## 在生产过程中切换审
您应该关心的一件事是在生产(甚至测试)期间切换审核表。 引入新表后,修订 ID(审核表中 REV 字段的内容)将立即重置并开始从 1 开始计数(如果您未指定其他任何要开始的序列)。 这意味着您必须知道何时切换以找到正确的修订信息,以找到正确的修订信息。
您应该关心的一件事是在生产(甚至测试)期间切换审计表。 引入新表后,修订 ID(审计表中`REV`字段的内容)将立即重置并开始从 1 开始计数(如果您未指定其他任何要开始的序列)。 这意味着您必须知道何时切换以找到正确的修订信息,以找到正确的修订信息。
## 结论
......
......@@ -18,11 +18,11 @@
### 自动版本控制
要使用自动版本控制,只需在您希望在乐观锁定的版本控制下拥有的实体中添加一个字段或方法,然后使用 [[受电子邮件保护]](/cdn-cgi/l/email-protection) 批注对其进行批注。 如文档所述,此批注可用于以下类型:int,Integer,short,Short,long,Long,java.sql.Timestamp
要使用自动版本控制,只需在您希望在乐观锁定的版本控制下拥有的实体中添加一个字段或方法,然后使用 [[受电子邮件保护]](/cdn-cgi/l/email-protection) 注解对其进行注解。 如文档所述,此注解可用于以下类型:`int``Integer``short``Short``long``Long``java.sql.Timestamp`
如果在加载实体和将其刷新回数据库之间发生一些更新,则会从 Hibernate 收到一条错误消息:
线程“主”中的异常 org.hibernate.StaleObjectStateException:行已由另一个事务更新或删除(或未保存值的映射不正确):[hibernate_example.joined.Book# 1]
线程“主”中的异常`org.hibernate.StaleObjectStateException`:行已由另一个事务更新或删除(或未保存值的映射不正确):`[hibernate_example.joined.Book#1]`
## 悲观并发控制
......@@ -30,18 +30,18 @@
但是, `LockMode`类定义了一些可由 Hibernate 获得的机制:
* WRITE:在 Hibernate 更新或插入行时自动获取
* 升级:可以在明确的用户请求下使用 SELECT…FOR UPDATE 在支持此语法的数据库上获取
* UPGRADE_NOWAIT:可在 Oracle 下使用 SELECT…FOR UPDATE NOWAIT 根据明确的用户请求获取
* 读取:Hibernate 读取数据时自动获取
* NONE:表示没有锁,在事务结束时所有对象都切换到此锁模式
* PESSIMISTIC_FORCE_INCREMENT:加载实体时强制增加版本。
* `WRITE`:在 Hibernate 更新或插入行时自动获取
* `UPGRADE`:可以在明确的用户请求下使用`SELECT…FOR UPDATE`在支持此语法的数据库上获取
* `UPGRADE_NOWAIT`:可在 Oracle 下使用`SELECT…FOR UPDATE NOWAIT`根据明确的用户请求获取
* `READ`:Hibernate 读取数据时自动获取
* `NONE`:表示没有锁,在事务结束时所有对象都切换到此锁模式
* `PESSIMISTIC_FORCE_INCREMENT`:加载实体时强制增加版本。
上面提到的“显式用户请求”可以表示为以下调用之一:
* LockOptions 参数指定 LockMode 的 load()
* buildLockRequest()
* setLockMode()
*`LockOptions`参数指定`LockMode``load()`
* `buildLockRequest()`
* `setLockMode()`
## 设置锁定模式的示例
......@@ -64,7 +64,7 @@ Java 8 in Action by Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft (ISBN: 9781617
每行末尾的方括号包含实体的版本号。
如果我们想将锁定移动到 getBooks()方法中,可以执行以下操作:
如果我们想将锁定移动到`getBooks()`方法中,可以执行以下操作:
```java
private static List<Book> getBooks(Session session) {
......@@ -74,7 +74,7 @@ private static List<Book> getBooks(Session session) {
}
```
有趣的是 setLockMode 方法的第一个字符串参数:它是实体使用此锁定的别名,您必须在查询的`FROM`块中使用此别名。
有趣的是`setLockMode`方法的第一个字符串参数:它是实体使用此锁定的别名,您必须在查询的`FROM`块中使用此别名。
使用此仓库方法加载书籍后,将书籍打印到控制台的结果可能是这样的:
......@@ -89,7 +89,7 @@ Java 8 in Action by Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft (ISBN: 9781617
版本号仅在当前会话中更新,直到您更新实体并将其保存到数据库为止。
如果不这样做,您会在应用中看到版本增量,但是它们不会保存到数据库中,即使您使用某些* _FORCE_INCREMENT 策略。
如果不这样做,您会在应用中看到版本增量,但是它们不会保存到数据库中,即使您使用某些`*_FORCE_INCREMENT`策略。
```java
| 1 |   Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft | 9781617291999 | 2015-07-29 | Java 8 in Action | 0 |
......@@ -98,15 +98,15 @@ Java 8 in Action by Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft (ISBN: 9781617
| 4 | Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft | 9781617291999 |   2015-07-29 | Java 8 in Action | 0 |
```
如果我们不更新旧条目,则上面的块显示了数据库中的实体。 这些列从左到右如下:ID,作者,ISBN,出版,TITLE 和 VERSION
如果我们不更新旧条目,则上面的块显示了数据库中的实体。 这些列从左到右如下:ID,作者,ISBN,出版,标题和版本
要进行一些版本更改,请取消注释示例中的代码块,然后运行应用。 该块将书籍的日期更新为当前日期,并将实体保存回数据库中。 为此,您需要进行交易
要进行一些版本更改,请取消注释示例中的代码块,然后运行应用。 该块将书籍的日期更新为当前日期,并将实体保存回数据库中。 为此,您需要进行事务
要开始交易,只需调用 session.beginTransaction();,如果完成调用 session.getTransaction()。commit();, 完成并写入数据库或 session.getTransaction()。rollback()以还原此事务中所做的所有更改。 或者,您可以存储由 beginTransaction()方法返回的*事务*对象,并在此*事务*实例上调用 commit()或 rollback()
要开始事务,只需调用`session.beginTransaction();`,如果完成调用`session.getTransaction().commite()`, 完成并写入数据库或`session.getTransaction().rollback()`以还原此事务中所做的所有更改。 或者,您可以存储由`beginTransaction()`方法返回的*事务*对象,并在此*事务*实例上调用`commit()``rollback()`
## 一些交易方式
## 一些事务方式
如果我提到了交易,请允许我给您一些模式(甚至是反模式),以了解通常如何处理交易
如果我提到了事务,请允许我给您一些模式(甚至是反模式),以了解通常如何处理事务
### 每个操作的会话(反模式)
......@@ -122,7 +122,7 @@ Java 8 in Action by Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft (ISBN: 9781617
### 每个应用的会话
开发人员不同意这是模式还是反模式,因为有时应用很小,您确实可以打开一个事务并在最后调用 commit。 但是,对于大型应用而言,这是一种太糟糕的方法,在大型应用中,最终的应用故障会导致数据丢失,或者如果存在并发用户并且数据相关,则这些用户之间将无法处于同步状态。
开发人员不同意这是模式还是反模式,因为有时应用很小,您确实可以打开一个事务并在最后调用`commit`。 但是,对于大型应用而言,这是一种太糟糕的方法,在大型应用中,最终的应用故障会导致数据丢失,或者如果存在并发用户并且数据相关,则这些用户之间将无法处于同步状态。
## 结论
......
......@@ -30,7 +30,7 @@
第一种解决方案与以前的方法类似:为每个架构创建连接池,并根据当前用户的租户标识符选择连接池。
第二种解决方案将使用默认模式指向数据库本身,并使用 SET SCHEMA SQL 命令(或类似的如果数据库允许的话)对每个连接更改数据库模式。 在这种情况下,单个连接池将为所有租户提供服务,但是在使用此连接之前,它将使用用户的租户标识符将其更改为正确的架构。
第二种解决方案将使用默认模式指向数据库本身,并使用`SET SCHEMA` SQL 命令(或类似的如果数据库允许的话)对每个连接更改数据库模式。 在这种情况下,单个连接池将为所有租户提供服务,但是在使用此连接之前,它将使用用户的租户标识符将其更改为正确的架构。
### 分区数据
......@@ -46,34 +46,34 @@
Session session = sessionFactory.withOptions().tenantIdentifier( yourTenantIdentifier ).openSession();
```
如您所见,在打开会话时,您需要提供租户标识符。 在这种情况下,您还必须提供一个 MultiTenancyStrategy,以让 Hibernate 知道要在数据库中寻找哪种策略(或者如果您启用了 Hibernate 的模式管理,则可以创建该策略):
如您所见,在打开会话时,您需要提供租户标识符。 在这种情况下,您还必须提供一个`MultiTenancyStrategy`,以让 Hibernate 知道要在数据库中寻找哪种策略(或者如果您启用了 Hibernate 的模式管理,则可以创建该策略):
* NONE:这是默认设置,如果您使用 tenantIdentifier 打开会话,则会引发异常
* 施玛
* `NONE`:这是默认设置,如果您使用`tenantIdentifier`打开会话,则会引发异常
* 模式
* 数据库
* 判别器:Hibernate 计划从版本 **5** 开始支持此策略。
如果您没有为`NONE`以外的其他策略提供租户标识符,则会出现异常。 当使用`NONE`以外的策略时,必须指定一个 MultiTenantConnectionProvider
如果您没有为`NONE`以外的其他策略提供租户标识符,则会出现异常。 当使用`NONE`以外的策略时,必须指定一个`MultiTenantConnectionProvider`
可以在您的 Hibernate 配置中使用 hibernate.multiTenancy 设置来设置这些策略(在本例中为 hibernate.cfg.xml 文件)。
可以在您的 Hibernate 配置中使用`hibernate.multiTenancy`设置来设置这些策略(在本例中为`hibernate.cfg.xml`文件)。
### MultiTenantConnectionProvider
### `MultiTenantConnectionProvider`
要使用两个可用的多租户提供程序之一,我们需要配置 MultiTenantConnectionProvider。 在这种特殊情况下,这意味着我们必须自己实现。
要使用两个可用的多租户提供程序之一,我们需要配置`MultiTenantConnectionProvider`在这种特殊情况下,这意味着我们必须自己实现。
在本文的示例应用中,我添加了接口的最基本的实现。
是的,有两种实现方式,因为 SCHEMA 和 DATABASE 策略需要单独处理。
是的,有两种实现方式,因为`SCHEMA``DATABASE`策略需要单独处理。
MultiTenantConnectionProviderImpl 类用于 DATABASE 策略。
`MultiTenantConnectionProviderImpl`类用于`DATABASE`策略。
MultiTenantConnectionProviderWithDbPoolImpl 类用于 SCHEMA 策略。
`MultiTenantConnectionProviderWithDbPoolImpl`类用于`SCHEMA`策略。
DatabasePool 实现的唯一问题是它使用 H2 数据库,而 H2 不知道 USE SQL 命令,因此在尝试运行应用时遇到异常。
`DatabasePool`实现的唯一问题是它使用 H2 数据库,而 H2 不知道`USE` SQL 命令,因此在尝试运行应用时遇到异常。
## 关于租户 ID 的注释
如果您使用的是数据库,请使用字符串作为租户 ID(除非您使用 DISCRIMINATOR 策略),因为架构必须具有文本名称,并且如果您提供数字(即使在 CurrentTenantIdentifierResolverImpl 中作为字符串),也会出现数据库异常
如果您使用的是数据库,请使用字符串作为租户 ID(除非您使用`DISCRIMINATOR`策略),因为架构必须具有文本名称,并且如果您提供数字(即使在`CurrentTenantIdentifierResolverImpl`中作为字符串),也会出现数据库异常
## 模式更新
......@@ -81,7 +81,7 @@ DatabasePool 实现的唯一问题是它使用 H2 数据库,而 H2 不知道 U
这意味着您必须手动创建要使用的架构,并将必需的表添加到这些架构。 或者,可以使用 Liquibase 或 FlyWay 之类的迁移工具来提供帮助。
下面的脚本显示了如何创建模式及其中的 BOOKS 表。
下面的脚本显示了如何创建模式及其中的`BOOKS`表。
如果不存在则创建模式示例;
使用示例;
......
......@@ -24,15 +24,15 @@ C3P0 是一个开源连接池,它具有一个 Hibernate 程序包,您可以
c3p0 连接池的最重要的配置属性如下:
* c3p0.min_size:池中的最小 JDBC 连接数。 休眠默认值:1
* c3p0.max_size:池中最大 JDBC 连接数。 休眠默认值:100
* c3p0.timeout:从池中删除空闲连接时(秒)。 休眠默认值:0,永不过期。
* c3p0.max_statements:将缓存准备好的语句数。 提高性能。 休眠默认值:0,禁用缓存。
* c3p0.idle_test_period – 自动验证连接之前的空闲时间(以秒为单位)。 休眠默认值:0
* `c3p0.min_size`:池中的最小 JDBC 连接数。 休眠默认值:1
* `c3p0.max_size`:池中最大 JDBC 连接数。 休眠默认值:100
* `c3p0.timeout`:从池中删除空闲连接时(秒)。 休眠默认值:0,永不过期。
* `c3p0.max_statements`:将缓存准备好的语句数。 提高性能。 休眠默认值:0,禁用缓存。
* `c3p0.idle_test_period` – 自动验证连接之前的空闲时间(以秒为单位)。 休眠默认值:0
### C3P0 的配置
要使用您的应用配置 C3P0,您需要设置以下属性。 在这种情况下,让我们在 hibernate.cfg.xml 中查看基于 XML 的已知配置:
要使用您的应用配置 C3P0,您需要设置以下属性。 在这种情况下,让我们在`hibernate.cfg.xml`中查看基于 XML 的已知配置:
```java
<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
......@@ -68,7 +68,7 @@ Proxool 是 C3P0 的替代连接池,但是它需要更多配置,因此我个
### Proxool 的配置
如前所述,仅在 hibernate.cfg.xml 文件中配置 Proxool 是不够的,您还需要一个单独的 XML 文件:
如前所述,仅在`hibernate.cfg.xml`文件中配置 Proxool 是不够的,您还需要一个单独的 XML 文件:
```java
<property name="hibernate.connection.provider_class">org.hibernate.connection.ProxoolConnectionProvider</property>
......@@ -76,11 +76,11 @@ Proxool 是 C3P0 的替代连接池,但是它需要更多配置,因此我个
<property name="hibernate.proxool.xml">proxool.xml</property>
```
与第一行的 C3P0 一样,hibernate.connection.provider_class 是可选的。
与第一行的 C3P0 一样,`hibernate.connection.provider_class`是可选的。
hibernate.proxool.xml 属性中提到了 XML 文件。
`hibernate.proxool.xml`属性中提到了 XML 文件。
proxool.xml 包含以下内容:
`proxool.xml`包含以下内容:
```java
<proxool-config>
......@@ -98,17 +98,17 @@ proxool.xml 包含以下内容:
</proxool-config>
```
如您所见,您必须在 Proxool 中提供数据库连接。 这是强制性的。 但是,由于这个原因,您可以从 hibernate.cfg.xml 文件中保留连接配置。
如您所见,您必须在 Proxool 中提供数据库连接。 这是强制性的。 但是,由于这个原因,您可以从`hibernate.cfg.xml`文件中保留连接配置。
Proxool 存在一个缺点:您必须定义要使用的方言。 使用 C3P0 和默认的 Hibernate 配置,您无需设置要使用的方言,但 Proxool 需要此信息。
如果一切都已设置好,则在启动应用时,您可以在日志中或控制台上看到以下条目:
org.hibernate.proxool.internal.ProxoolConnectionProvider 配置
`org.hibernate.proxool.internal.ProxoolConnectionProvider`配置
## 一般关于配置
Hibernate 使用其魔力来根据您配置的属性来标识要使用的连接池提供程序。 但是,您可以使用 hibernate.connection.provider_class 属性定义连接提供程序。
Hibernate 使用其魔力来根据您配置的属性来标识要使用的连接池提供程序。 但是,您可以使用`hibernate.connection.provider_class`属性定义连接提供程序。
如果未配置连接池,则使用默认值。 启动应用时,它在日志或控制台输出中可见:
......
# 休眠自举
# Hibernate 自举
> 原文: [https://javabeginnerstutorial.com/hibernate/hibernate-bootstrapping/](https://javabeginnerstutorial.com/hibernate/hibernate-bootstrapping/)
......@@ -20,11 +20,11 @@
首先,您需要项目中正确的依赖项。 至于本系列文章中的所有示例,我正在使用 Hibernate 版本 5.3.6。 最终版本和 H2 版本 1.4.197。
我们需要创建一个 StandardServiceRegistry,一个 Metadata 对象,并使用它来启动 SessionFactory
我们需要创建一个`StandardServiceRegistry`,一个元数据对象,并使用它来启动`SessionFactory`
### hibernate.cfg.xml
### `hibernate.cfg.xml`
大多数时候,我使用基于 XML 的配置文件 hibernate.cfg.xml 来设置 StandardServiceRegistry
大多数时候,我使用基于 XML 的配置文件`hibernate.cfg.xml`来设置`StandardServiceRegistry`
```java
<hibernate-configuration>
......@@ -54,16 +54,18 @@
使用此文件可以使配置独立于源代码,并以结构化的方式概述配置。
最终配置配置= new Configuration()。configure();
最终的 StandardServiceRegistryBuilder 构建器= new StandardServiceRegistryBuilder()。configure(“hibernate.cfg.xml”);
```java
final Configuration configuration = new Configuration().configure();
final StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().configure(hibernate.cfg.xml);
```
如示例代码所示,您需要告诉 Hibernate 您正在使用 hibernate.cfg.xml 文件。 在以前的 Hibernate 版本中,您不需要指定使用此文件来设置服务注册表,因为这是默认行为。
如示例代码所示,您需要告诉 Hibernate 您正在使用`hibernate.cfg.xml`文件。 在以前的 Hibernate 版本中,您不需要指定使用此文件来设置服务注册表,因为这是默认行为。
### 程序配置
使用 Hibernate 5,您可以选择以 Java 代码编程配置 ORM。
让我们看看如何将先前显示的 hibernate.cfg.xml 文件映射到 Java 代码中。 为此,我创建了一个名为 HibernateUtil 的类,如下所示:
让我们看看如何将先前显示的`hibernate.cfg.xml`文件映射到 Java 代码中。 为此,我创建了一个名为`HibernateUtil`的类,如下所示:
```java
package hibernate_example;
......@@ -123,9 +125,9 @@ public class HibernateUtil {
因此,我更喜欢将配置保存在单独的文件中,而不是在 Java 代码中-但这是我个人的看法。
### hibernate.properties
### `hibernate.properties`
让代码喘气的一种方法是将配置提取到属性文件中-在大多数情况下,该文件称为 hibernate.properties
让代码喘气的一种方法是将配置提取到属性文件中-在大多数情况下,该文件称为`hibernate.properties`
使用上面的示例,我们可以将配置提取到以下文件中:
......@@ -140,7 +142,7 @@ hibernate.show_sql=true
hibernate.hbm2ddl.auto=create
```
现在,我们也必须改编 HibernateUtil 类以使用此新文件:
现在,我们也必须改编`HibernateUtil`类以使用此新文件:
```java
package hibernate_example;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册