ORM问题域

ORM问题域 - 切尔斯基 - 博客频道 - CSDN.NET http://blog.csdn.net/chelsea/article/details/5094652

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

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

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

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

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

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

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

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

N+1查询问题

分离查询模型和存储模型

尽量减少查询语句

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

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

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

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

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

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

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

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

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

可以使用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 的事务和连接的问题?

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

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

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

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

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

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

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

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

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

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

在某些查询执行之前

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

在调用Session.flush()的时候

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

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

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

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

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

  1. N+1查询问题

Eager Load + JOIN

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

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

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

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

  1. 尽量减少查询语句

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

  1. 值类型

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容