从手写的持久层迁移到ORM

时间:2010-05-19 16:09:39

标签: java sql database performance orm

我们目前正在评估从手写持久层迁移到ORM的选项。

我们有一堆遗留持久对象(~200),它们实现了这样的简单接口:

interface JDBC {
    public long getId();
    public void setId(long id);
    public void retrieve();
    public void setDataSource(DataSource ds);
}

当调用retrieve()时,对象通过向使用setter中收到的ID提供的连接发出手写SQL查询来填充自身(这通常是查询的唯一参数)。它管理自己的语句,结果集等。有些对象具有retrive()方法的特殊风格,如retrieveByName(),在这种情况下会发出不同的SQL。

查询可能非常复杂,我们经常连接几个表来填充表示与其他对象的关系的集合,有时连接查询是在特定的getter(延迟加载)中按需发出的。基本上,我们已经手动实现了大部分ORM的功能。

原因是表现。我们对速度有非常强烈的要求,早在2005年(编写此代码时)性能测试表明,主流ORM都没有像手写SQL一样快。

我们现在面临的让我们想到ORM的问题是:

  • 此代码中的大多数路径都经过了充分测试并且稳定。但是,一些很少使用的代码容易出现非常难以检测的结果集和连接泄漏
  • 我们正在通过向持久层添加缓存来挤压一些额外的性能,并且在此设置中手动维护缓存对象是一个很大的
  • 当数据库架构发生变化时,支持此代码是一个大问题。

我正在寻找可能是我们最佳选择的建议。据我所知,ORMs在过去5年中已经取得了进展,所以可能现在有一个提供可接受性能的ORM。在我看到这个问题时,我们需要解决这些问题:

  • 找到一种方法来重用至少一些书面SQL来表达映射
  • 有可能发出本机SQL查询而无需手动分解其结果(即避免手动rs.getInt(42),因为它们对架构更改非常敏感)
  • 添加非侵入式缓存层
  • 保持表现数字。

您是否可以推荐任何ORM框架?

更新要了解我们正在讨论的性能数据:

  • 后端数据库是TimesTen,与JVM在同一台机器上运行的内存数据库
  • 我们发现将rs.getInt("column1")更改为rs.getInt(42)会带来我们认为重要的性能提升。

6 个答案:

答案 0 :(得分:5)

如果您需要允许发出本机SQL查询的标准持久层,请考虑使用iBATIS。它是您的对象和SQL之间相当薄的映射。 http://ibatis.apache.org/

对于缓存和延迟连接,Hibernate可能是更好的选择。我没有将iBATIS用于这些目的。

Hibernate提供了很大的灵活性,允许您在遍历对象图时指定延迟加载的某些默认值,还可以在需要更加已知的加载时间时使用SQL或HQL查询预先获取数据。但是,转换工作对您来说会很复杂,因为它在学习和配置方面具有相当高的入门条件。注释使我更容易。

您未提及有关切换到标准框架的两个好处: (1)当你有大量的网站和论坛来支持你时,减少错误就变得容易了。 (2)新员工更便宜,更容易,更快捷。

祝您好好解决性能和可用性问题。你指出的权衡是非常普遍的。对不起,如果我传福音。

答案 1 :(得分:4)

对于大部分查询,我会使用hibernate。它被广泛使用,记录良好,并且通常具有高性能。如果hibernate没有产生足够高效的查询,你可以下载到手写的SQL。 Hibernate在指定域对象映射到的表名和列时提供了很多控制,在大多数情况下,您可以将其改编为适用于现有模式。

  
      
  • 找到一种方法来重用至少一些书面SQL来表达映射   映射在JPA中使用注释表示。您可以在创建JPQL查询时使用现有SQL作为指南。

  •   
  • 添加非侵入式缓存层

  •   

在hibernate中缓存是自动且透明的,除非您特别选择参与。您可以将实体标记为只读,或从缓存中逐出,控制何时将更改刷新到数据库(当然,在事务内部 - 当网络延迟成为问题时,自动使用批处理可以提高性能。)

  
      
  • 有可能发行原生   SQL查询没有必要   手动分解他们的结果(即   避免手动rs.getInt(42)   对架构更改非常敏感)
  •   

Hibernate允许您编写SQL,并将其映射到您的实体。你不直接处理ResultSet - hibernate负责解构你的实体。请参阅休眠手册中的Chpt 16, Native SQL

  
      
  • 当数据库架构发生变化时,支持此代码是一个大问题。
  •   

管理架构更改仍然很麻烦,因为您现在实际上有两个架构 - 数据库架构和JPA映射(对象架构)。如果您选择让hibernate生成数据库模式并将数据移动到该模式,则不再直接对数据库中的内容负责,因此您将面临对计算机生成的模式进行自动更改的问题。有些工具可以提供帮助,例如dbmigrate和liquibase,但它不是在公园散步。相反,如果您手动管理数据库架构,则必须仔细地重新编写实体,JPA注释和查询以适应架构更改。添加列和新实体相对简单,但更复杂的更改(例如将单个属性更改为属性集合或重构对象层次结构)将涉及更广泛的更改。没有简单的方法 - db或hibernate是决定架构的“主”,当一个更改时,另一个必须遵循。代码更改并不是那么糟糕 - 根据我的经验,它正在迁移困难的数据。但这是数据库的基本问题,并且会出现在您选择的任何解决方案中。

所以,总而言之,我会使用hibernate,并使用JPA接口。

答案 2 :(得分:3)

我最近钻了一堆Java ORM并没有提出比Hibernate更好的东西。 Hibernate的性能可以帮助您实现并满足您的性能目标。

很多人认为迁移到Hibernate将使一切变得如此棒,但它实际上只是将一系列问题从JDBC查询转移到Hibernate调优。阅读一堆书或(更好)聘请“Hibernate人”进来帮助。

在您的重构期间,我建议您使用JPA,以便在Next Big Thing出现时(或者您转移到Oracle)取消插入并重新插入新的持久性提供程序

答案 3 :(得分:2)

你真的需要迁移吗?是什么迫使你搬家?这里是否有一些真正需要或者只是发明工作的人(“宇航员建筑师”)?

我同意上述答案 - 如果你必须移动 - Hibernate或iBatis是不错的选择。 iBatis特别是如果你想要更接近SQL。

答案 4 :(得分:1)

如果您需要更高的性能:删除数据库(用于在线工作)并直接处理持久性。添加缓存不会帮助您使用TimesTen数据库,它只会添加一个额外的副本(减慢您的速度)。

你可能想看看GemFire。

答案 5 :(得分:1)

这里有很多好的建议,我不再重复了。我唯一没有看到的建议可能对您有用,就是在内存中缓存参考数据。

我过去做过很多这样做,确实节省了很多时间。如果您有大量相当静态的引用表,请在启动时将它们全部加载到内存中,并每隔几分钟刷新一次。这样你就不会一遍又一遍地对数据库进行永不改变的数据。