`
chelsea
  • 浏览: 117754 次
  • 来自: ...
社区版块
存档分类
最新评论

ORM问题域

    博客分类:
 
阅读更多

 

假设我们必须处理对象的存储, 加载, 和查询. 性能和引用完整性的约束, 给接口的实现带来了以下问题:

  1. 加载根对象时如何避免加载大半个数据库

  2. 存储时如何更新整个对象图

  3. 存储时如何高效的更新整个对象图

  4. 何时同步对象的内存状态和持久存储状态

  5. 如何确保在出错时保持对象内存状态和持久存储状态之间的一致性

  6. 如何保证引用的唯一性以避免可能的更新冲突

 

对性能的精益求精, 又促使人们解决更多的细节问题:

  1. N+1查询问题

  2. 分离查询模型和存储模型

  3. 尽量减少查询语句

 

 

这些问题的解决方案又会带来新的问题.

 

1. 加载根对象时如何避免加载大半个数据库

 

更多的时候这是一个建模问题, 为什么我只需要显示一点信息, 更新一点信息, 却拉家带口把八杆子打不着的亲戚都带上 : 细粒度对象设计, 直接访问需要的信息, 减少所谓根对象的存在

一个workaround是延迟加载, 当你无法修复你错误的建模时, 当真正去访问子对象的时候再发出查询语句去加载. 这个方案会带来如下问题:

  1. 查询语句较多. 无解, 延迟意味着至少两条SQL语句, 只能尽量减少

  2. 延迟加载的时机, 是自动透明的延迟加载, 还是用户确定何时加载

Hibernate可通过配置文件指定是否lazy load, 一旦指定, 后面的load就是透明的在访问子对象时发生. 也可在发出每次查询时显式指定

Entity Framework则要求用户在每一次查询时显式指定包含哪个子对象, 对没有指定包含的子对象, 只能在访问前显示使用load(). 理由是决定加载不加载,何时加载都是程序员的责任

  1. 然而更大的问题是如何管理数据库连接, 要确保延迟加载的时候数据库连接是开着的

可以使用Interceptor等技术维持 Session per request, Open Session in View pattern(处理好异常等, 确保session会关闭).

能在一个 Session 中使用两个事务吗?

是的,这事实上是这种模式(Open Session In View)的一个更好的实现。在一个请求事件中,一个数据库事务用于数据的读写。第二个数据库事务仅用于在渲染视图期间读数据。在这点上没有对对象的修改。因此,数据库锁早在第一个事务时就被释放了,这使得应用有更好的可伸缩性,第二个事务可以被优化。要使用两阶段的事务,你需要比 Servlet Filter 更强大的拦截器 - AOP 是个很好的选择。JBoss Seam 使用了这种模式。

为什么 Hibernate 不在需要时就加载 Object?

每个月很多人都会有这种想法,为什么 Hibernate 不能在有需要的就开启一个新的数据库连接(更有效率的是开启一个 Session),然后加载集合或是初始化代理,而是选择抛出一个 LazyInitializationException。当然,这种想法,第一眼看上去可能是明智之举。但这种做法有很多的缺点,只有当你考虑特别的事务访问时才会发现。

如果 Hibernate 可以进行任意的数据库连接和事务,这种操作是开发人员不可知,并且也是在任何事务边界之外的,那还要事务边界做什么。当 Hibernate 开启了新的数据库连接去加载集合,但同时集合的拥有者却被删除了,这是将会发生什么?(注意,这种情况是不会发生在上面提到的两阶段的事务模式中的 - 单个 Session 可对实体可重复读。)当所有的对象都可以通过关联导航获取时为什么还要有 Service 层?这种方式将消耗多少内存?哪些对象要首先被清除掉?所有这些问题都是无解的,因为 Hibernate 是一个在线的事务处理服务(并包含一些批处理操作),并不是一个“在未定义的工作单元中从数据持久仓库取得对象”的服务。此外,对于 n+1 查询问题,我们是否需要 n+1 的事务和连接的问题?

这个问题的解决方案当然是正确的工作单元划分和设计,支撑其的拦截技术就像这里所展现的一样,并且/或者正确的抓取技术,使得特定工作单元所需的全部信息能够以最小的影响、最好的性能和伸缩性被获得。

 

 

2. 存储时如何更新整个对象图

框架支持级联更新. 是否应该级联更新, 哪些操作可以级联, 哪些不可以, 对象之间的哪些类型的关联可以级联, 哪些不可以, 则是程序员的责任

  • 通常被聚合的对象, 其生命周期应由父对象负责, 新增/更新/删除都应级联

  • 自身有存在意义的实体, 可以级联更新, 但不应删除和新增

 

3. 存储时如何高效的更新整个对象图

常用工作单元模式, Unit of Work.

 

4. 何时同步对象的内存状态和持久存储状态

任何改动都立即提交到数据库会带来额外开销. 一个时机是事务提交时.

 

Hibernate: 每间隔一段时间,Session会执行一些必需的SQL语句来把内存中的对象的状态同步到JDBC连接中。这个过程被称为刷出(flush),默认会在下面的时间点执行:

 

  • 在某些查询执行之前

  • 在调用org.hibernate.Transaction.commit()的时候

  • 在调用Session.flush()的时候

 

5. 如何确保在出错时保持对象内存状态和持久存储状态之间的一致性

数据库事务回滚, 清空内存缓存, 重新加载

 

6. 如何避免或处理可能的更新冲突

保证引用的唯一性: 使用单一的加载入口和缓存, Identity Map .

乐观离线锁会引入更新冲突问题, 一般使用Versioning来解决, 类似版本控制系统的更新问题; 但业务对象很少能自动Merge, Merge的语义也不好定义, 所以一般检测到冲突之后只好重做了, 或者取决于业务逻辑, Last Win也是一种策略.

 

7. N+1查询问题

  • Eager Load + JOIN

  • 截然不同的一种避免N+1次查询的方法是,使用二级缓存。

N + 1 是关联引入的问题, 网上的解释和例子倾向于拿one-2-many说事, 但实际上one-2-one依然面临使用多于一条SQL语句加载的问题

 

8. 分离查询模型和存储模型

适合业务关系的对象模型未必对查询是高效的. 需要单独针对查询建模, 可以用单独的索引表来实现. 在更新业务对象的存储时同时更新索引表

 

9. 尽量减少查询语句

比如join over multiple select, 比如批量抓取

 

10. 值类型

不需要有ID, 通常被聚合. 有对应的Class, 但一般没有对应的Table, 仅是Table中的几个字段

挑战在于将对象语言类型系统(和开发者定义的实体和值类型)映射到 SQL/数据库类型系统。 Hibernate: 提供了连接两个系统之间的桥梁:对于实体类型,我们使用class, subclass 等等。对于值类型,我们使用 property, component 及其他,通常跟随着type属性。这个属性的值是Hibernate 的映射类型的名字

 

分享到:
评论

相关推荐

    JsonStore:轻量级ORM可将域对象作为文档持久存储在SQL中

    当与JsonStore.Sql扩展包一起使用时,它也可以作为微型Orm。 入门 添加NuGet参考 PM > Install-Package JsonStore.Sql 给定以下要存储的类 public class Foo { public string Id { get ; set ; } public string ...

    .NET的ORM映射工具 AutoMapper.zip

    这需要 通过设计完成,因为让DTO回写到,比方说:域模型或其他东西,就会更改它的持久性,同时人们也认为它是反模式的。在这种解决方案中,命令消息在双向映射 中往往是更好的选择。然而,在某些特定环境中,有人...

    goorm:goorm自用封装包(仿照laravel)

    WhereIN(字段字符串,作用域[] interface {}) WhereNotIn(字段字符串,范围[] interface {}) WhereBetween(字段字符串,左字符串,右字符串) WhereNull(fields ... string):选择为空细分

    Arbiter:SalesForce ORM

    创建您自己的易于理解或与您的问题域相匹配的内容。 或者只是去掉那些令人讨厌的下划线... 。 使更新和创建新对象变得容易快捷 可选的字段验证和默认值 仲裁者没有给您的东西: 一种修改Salesforce对象和模式的...

    multi-domain-web-demo:ORM (entity, jpa, queryDsl),利用MyBatis多域的多模块项目

    基于 Spring 的多域、多模块示例 Web 项目这是一个使用Springframework的多模块项目,在域处理方式中使用ORM和Mybatis创建业务逻辑后,配置项目示例,使得Web区可以根据需要使用Orm或Mybatis域。项目结构 multi-...

    doctrine-tutorial:使用Doctrine ORM + ODM的小教程

    原则ORM + ODM快速入门介绍我们将为HelloFresh域的非常简化的版本编写一个小型应用程序。 在编写此应用程序时,我们将看到Data Mapper和Repository模式如何实现域和基础结构之间的清晰隔离。 我们将使用MySQL存储...

    模拟:模拟ORM:LaravelPHP的数据映射器ORM

    (该项目正在寻找新的维护者)模拟ORM Analogue是适用于PHP的灵活,易于使用的ORM 。 这是附带Laravel框架采用数据映射模式,而不是原来的Active ... 使用这个简单的域模型: use Analogue \ ORM \ Entity ;use Ill

    YB.ORM:用于C ++的对象关系映射(ORM)的工具-开源

    YB.ORM是用于C ++的对象关系映射(ORM)的工具。 受到Hibernate或SQLAlchemy之类的启发。 应该与数据库无关。 包括用于域对象代码生成的工具。 表的元数据描述是一个XML文件。

    JFinal(JAVA 极速WEB ORM框架 ) v3.2.zip

    JFinal 是基于 Java 语言的极速 WEB ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有ruby、python等动态语言的开发效率!为您...

    couchbase-lite-orm:适用于Couchbase Lite的Java ORM

    Couchbase Lite ORM仅将文档转换为您的域对象,反之亦然。 您不需要扩展任何类。 您只需要注释您的班级。 该库将不使用反射。 反思是太慢了。下载Gradle: compile ' ...

    photon:微型ORM,可让开发人员控制执行SQL,同时还提供一种简单的方法来对实体执行基本的CRUD操作

    由于他们将SQL隐藏在泄漏抽象之后执行,因此,对问题进行诊断和故障排除需要对ORM的内部运作有深入的了解。 光子查询只是普通SQL,因此您始终确切知道ORM正在运行的查询。 Photon是唯一支持流畅API的Java ORM之一。...

    Gallus:一个 Dapper 启发的支持嵌套集合映射的 Micro-ORM

    Gallus - 可以的小 ORM。 Gallus 是一个受启发的微 ORM,它遵循与 Dapper 相同的精神,但它... 作为开发人员,我们希望编写代码并专注于问题域,而编写 SQL 被视为不必要的分心,这是 ORM 寻求解决的困难。 我认为这是

    laravel ORM关联关系中的 with和whereHas用法

    在使用Laravel的Eloquent ORM时,我们常常需要处理模型之间的关联关系,这时,with方法和whereHas方法是两个经常被用到的查询作用域(query scope),它们分别用于预加载关联数据和筛选特定条件的关联数据。...

    Hibernate面试问题大全

    - 域对象的保存和检索 - 数据库表和列名更改的处理 - 预保存和后检索逻辑的集中 - 复杂连接以获取相关项目 - 从对象模型创建数据库模式 7. 为何需要Hibernate XML映射文件? Hibernate的XML映射文件告诉Hibernate...

    hibernate培训

    概念模型描述问题域的实体和关系,关系数据模型基于此建立数据库的静态结构,而域模型是面向对象的设计模型,包含实体域对象、过程域对象和事件域对象。域对象间的关联、依赖、聚集和一般化构成了对象间复杂的关系...

    msgphp:可重用的域层。 随附行业标准基础架构

    支持的一流ORM是 支持的一流消息总线是 基于消息 每个域层都提供了一组使用它的消息。 通常,消息被分类为命令消息,事件消息和查询消息。 主要优点是我们可以直观地创建独立的业务逻辑流。 它通过在Web和CLI中...

    Laravel开发-scope-applicator-laravel

    作用域通常用于Eloquent ORM,是处理复杂查询时的一个强大工具。本文将深入探讨Laravel中的作用域应用程序绑定及其在实际开发中的应用。 一、Eloquent ORM与作用域 Eloquent是Laravel提供的一个强大的ORM(对象...

    hibernate一些文档资料

    - **概念模型**:用于描述问题域中的实体及其关系,不涉及具体实现细节。 - **关系数据模型**:定义数据库结构,包括表、索引、视图等。 - **域模型**:在软件设计阶段创建,包括实体、过程、事件等类型的域对象。 ...

    xUtils3:Android orm,位图,http,视图注入。

    xUtils3简介 xUtils包含了orm,http,图像,视图注解,但依然很轻量级(251K),并且...支持cookie(实现域,路径,有效期等特性) 支持缓存(实现了Cache-Control,Last-Modified,ETag等特性,缓存内容过多时使用过期

Global site tag (gtag.js) - Google Analytics