实现Burt Beckwith式GORM的性能-没有集合
来源:互联网 发布:excel sql语句 编辑:程序博客网 时间:2024/06/07 06:07
不再使用GORM/Hibernate集合?
Burt Beckwithhttp://burtbeckwith.com/ 先生讲述了在 Grails中提高GORM的性能。他的演讲在 http://www.infoq.com/presentations/GORM-Performance
他的观点是在你的域对象中不使用集合,因为在对象被添加之前,集合可能需要从数据库中被完全加载。
我决定在我的工作项目中使用它。这个项目有18个域类。我遇到了一些问题,这些问题让我头疼几个小时,然后我才解决这些问题。更新整个项目从“hasMany/belongsTo“风格到没有集合风格它花费了我半天的时间 。这里是一个非常简单的域类,采用典型的 GORM 一对多的级联关系。
购物车程序示例
让我们用一个购物车示例代码开始。我们有一个购物车对象包含许多Item对象。
典型的GORM 关系
grails-app\domain\shopping\Cart.groovy
package shoppingclass Cart {String namestatic hasMany = [ items : Item ]static mapping = {sort "name"items sort:"name"}static constraints = { name nullable:false, blank:false, unique:true } String toString() { "Cart $name" }}
grails-app\domain\shopping\Item.groovy
package shoppingclass Item {String nameInteger quantitystatic belongsTo = [ cart : Cart ]static mapping = {sort "name"}static constraints = { name nullable:false, blank:false, unique:['cart'] quantity nullable:false } String toString() { "$quantity $name" }}
grails-app\conf\BootStrap.groovy
import shopping.*class BootStrap { def init = { servletContext -> def cart = new Cart(name:"alpha").save() cart.addToItems new Item(name:"apples", quantity:10) cart.addToItems new Item(name:"milk", quantity:2) cart.addToItems new Item(name:"bread", quantity:3) cart.save() } def destroy = { }}
删除 hasMany 和 belongsTo
现在,遵照Burt Beckwith的建议,我们删除 belongsTo 和 hasMany 关系,并且在子类中嵌入父对象
现在我们的代码看起来像这样:
BelongsTo 和HasMany 被删除
grails-app\domain\shopping\Cart.groovy
package shoppingclass Cart {String namestatic mapping = {sort "name"} static constraints = { name nullable:false, blank:false, unique:true } String toString() { "Cart $name" }}
grails-app\domain\shopping\Item.groovy
package shoppingclass Item {String nameInteger quantityCart cartstatic mapping = {sort "name"} static constraints = { name nullable:false, blank:false, unique:['cart'] quantity nullable:false } String toString() { "$quantity $name" }}
grails-app\conf\BootStrap.groovy
import shopping.*class BootStrap { def init = { servletContext -> def cart = new Cart(name:"alpha").save() new Item(cart:cart, name:"apples", quantity:10).save() new Item(cart:cart, name:"milk", quantity:2).save() new Item(cart:cart, name:"bread", quantity:3).save() } def destroy = { }}
这是所有的修改。
在 Cart.groovy 文件
- 删除了static hasMany = [ items : Item ]
- 从mappings中删除了 items sort:”name”
在 Item.groovy 文件
- 删除了 belongsTo
- 增加了 Cart cart
在 BootStrap.groovy 文件
- 修改了我们创建子类对象的方式.
- 从: cart.addToItems new Item(name:”apples”, quantity:10)
- 到 : new Item(cart:cart, name:”apples”, quantity:10)
新的问题和解决方案
我们已经完成了吗?当然不是–它并非那么简单。还有一些其他的问题需要解决::
- 子类对象items访问不再那么容易。
- 集合排序(在mapping中定义)不再发生。
- 不能删除父对象因为外键关系.
- 脚手架不再显示子类的对象.
让我们一次解决这些问题。
子类对象items访问不再那么容易
这个问题很容易修改。我们在Cart类中只是增加一个新的方法到父对象(Cart),它返回子对象的集合(Item):
grails-app\domain\shopping\Cart.groovy
.... def getItems() { Items.findAllByCart(this) } ....
集合排序(在mapping中定义)不再发生.
这个问题也很容易。我们只需要稍微修改上面的代码. 我们增加了一个排序的参数到findAllBy*方法中。
grails-app\domain\shopping\Cart.groovy
.... def getItems() { Item.findAllByCart(this, [sort:"name"]) } ....
现在,我们能访问购物车中的items就像我们有了一个hasMany的关系.
println cart.items
不能删除父对象因为外键关系.
这是令人头痛的问题。不是因为它很困难,但它需要做一些小的研究找到一个优雅的解决方案.
这个问题是如果我做一个购物车的删除操作,它将会失败因为购物车中有items。在老的hasMany / belongsTo方案中将会自动级联删除items和cart。现在我们没有了,因此我们必须手动做删除.
这是我知道的最好的解决方案(如果有一个更好的方案让我知道)是在Cart对象上使用beforedelete事件对象。
在一个对象被删除之前,GORM会触发 beforeDelete事件。你能将代码放置在beforeDelete方法中,做你想做的任何事情。在我们的例子中,我们将删除子类的item对象。想看一看beforeDelete详细文档请访问 这里.
让我们修改Cart.groovy 的代码和增加beforeDelete方法.
grails-app\domain\shopping\Cart.groovy
.... def beforeDelete() { Item.withNewSession { items*.delete() } } ....
(这是我喜欢的Groovy的原因–一行代码能做那么多的工作!)
首先,我们建立了一个Hibernate的session。如果你读了关于beforeDelete的文档,你应该知道(这种情况)使用一个新的session为删除操作是为了避免产生StackOverflow异常。
其次,我们删除子类items的所有对象。我们使用groovy的扩展操作符调用列表中所有项的方法。
所以,这一行代码,当父对象(Cart)被删除时,所有的子对象(Item)将被删除。
脚手架不再显示子类的对象.
自从父类对象不再知道关于子类对象以后,默认的Grails的脚手架不再显示购物车中的项目。我不知道解决的方式,除了不使用脚手架。
最终Cart 和 Item 的代码
grails-app\domain\shopping\Cart.groovy
package shoppingclass Cart {String namestatic mapping = {sort "name"}static constraints = {name nullable:false, blank:false, unique:true}String toString() {"Cart $name"}def getItems() {Item.findAllByCart(this, [sort:"name"])}def beforeDelete() {Item.withNewSession { items*.delete() }} }
grails-app\domain\shopping\Item.groovy
package shoppingclass Item {String nameInteger quantityCart cartstatic mapping = {sort "name"}static constraints = {name nullable:false, blank:false, unique:['cart']quantity nullable:false}String toString() {"$quantity $name"}}
我的观点
实现困难(Implementation Difficulty)
一旦我知道了怎样去实施这一方案,部署它在我的域类里那是相当简单。记住你需要更新任何使用addTo* 和removeFrom*方法的代码。
复杂性/维护(Complexity / Maintenance)
这种解决方案使我的应用程序理解更复杂吗?我不这么认为。一个有经验的Groovy编程者能够理解的cart.getItems()方法。beforeDelete需要一点时间来理解,但它很快就学会了。
同样使用belongsTo / hasMany也很复杂。请看GORM Gotchas Part 2。我不认为这一方案比使用belongsTo / hasMany更复杂.
性能(Performance)
还不知道。我没有在一个真实的应用中考虑过子类对象加载的性能问题。
我会再次这么做(Would I Do It Again)
肯定。我有一个项目崩溃了,因为它有超过20个对象和 超过30个关系。Hibernate 和GORM 导致各种异常,当时,对于如何解决问题我太缺乏经验。我考虑尝试使用“没有集合”技术,看看我是否能完成这个项目。我有一个好的预感,这个方法行不通,但我需要证明这一点。
英文原文:Implementing Burt Beckwith’s GORM Performance – No Collections
备注:英文原文回复更精彩,有兴趣的朋友可以看英文回复。
- 实现Burt Beckwith式GORM的性能-没有集合
- Grails的GORM
- GORM的基础CRUD
- GORM
- Gails中的GORM的关系
- Grails2中GORM 的继承
- set集合的实现和性能
- GORM - 有趣的名称,严肃的技术
- GORM的高级特性及其他
- Groovy书写不依赖与实体的GORM
- java集合框架之List实现类的性能分析
- 集合的性能提升
- 关于集合的性能问题
- java集合的初始化性能
- java集合的性能选择
- Gorm错误
- java集合框架之Set集合实现类性能对比
- Set集合没有重复的元素
- 校招感悟
- 社説 20150106 安倍政権の課題 「強い経済」を諸改革の基盤に
- 正则练习
- 使用POI 3.10.1读取 Excel 2007格式
- 正式踏上前端之路
- 实现Burt Beckwith式GORM的性能-没有集合
- 企业应用通用架构图
- 活用设计模式:如何避免一连串的if else
- 让dedecms站点内容自动更新到微博
- github初尝试
- Libgdx 1.5.2发布
- 供应链金融:互联网金融又见新玩法
- 浅谈javascript中的全局变量
- 浅谈事件冒泡与事件捕获