【原创译文】深入理解Android为什么不允许Room数据库对象间(外键)引用

简介: 【原创译文】深入理解Android为什么不允许Room数据库对象间(外键)引用译者zhangphil@csdn注:当我开始使用Android Room技术时候,Room明确禁止对象间外键引用,让我感觉不可思议,也觉得不正常,因为对象间引用几乎是所有ORM数据库技术非常普遍的设计和理念,并且这对开发者来说无疑很友好很有用,为什么Android官方的Room却禁止了呢?看了这篇谷歌Android官方技术文档我才恍然大悟。
【原创译文】深入理解Android为什么不允许Room数据库对象间(外键)引用


译者zhangphil@csdn注:当我开始使用Android Room技术时候,Room明确禁止对象间外键引用,让我感觉不可思议,也觉得不正常,因为对象间引用几乎是所有ORM数据库技术非常普遍的设计和理念,并且这对开发者来说无疑很友好很有用,为什么Android官方的Room却禁止了呢?看了这篇谷歌Android官方技术文档我才恍然大悟。这篇文章在Android数据库开发中很有启发意义,因此我特意把它翻译出来以飨读者。
第一,该文档Android官方回答了Android Room禁止对象(外键)引用的原因,但是开发者需要明白,虽然Android Room不允许外键引用,但保留了@Embedded内嵌对象这一设计(见附录文章2),其实通过Room的@Embedded内嵌对象,可以变通的实现外键引用,且性能更佳。
第二,该篇文章更大价值是启发Android开发者在常见的数据库数据访问时候,是如何影响性能以及如何改善APP在加载数据库数据时的性能问题。
第三,开发者在使用常见的ORM数据库如ORMLite过程中,普遍存在对象间(外键)引用,这没什么问题,但是如果对象间引用过程中,非常普通的set/get代码若发生在Android UI主线程,看似一条简单的set/get会严重影响Android性能吗?如果会,又是如何影响呢?本篇技术文档将给出启迪性见解。



以下是我对谷歌Android官方原文的翻译:

关键技术收获:Android Room不允许在不同entity实例对象之间进行(外键、外链)引用。取而代之的是,作为开发者你必须明确的显式请求你自己App需要的数据。

在数据库中各自不同对象之间建立映射引用关系是一种惯常做法并且在服务器端这种技术路线可以良好工作。甚至当程序在它们使用这些变量时候直接存取访问,服务器端仍然性能表现良好。

然而上述按需所取的“懒加载”模式在客户端并不可行,因为这种代码场景发生在Android的UI主线程,在UI主线程就这样发起对硬盘的信息查询将导致明显的性能问题。典型的UI线程要在16毫秒内计算、绘制和更新布局,就算一次数据库查询仅花费5毫秒,也依然可能会把你APP绘制图像帧的时间耗完,引发显而易见的视觉错误。更不幸的是,如果数据库查询事务单独的并行进行,或者此时Android设备也正在进行其他高强度硬盘访问任务,那么将会花费更多时间完成数据查询。如果你不使用懒加载,那么就意味你的APP需要取出更多你不需要的的冗余数据,制造了内存消耗浪费问题。
ORM(对象关系映射)通常会把这些决定留给开发者,以让开发者自行决定使用何种最适合的技术路线解决开发者自己APP的情况。开发者通常的策略是在APP和UI里面共享数据库模型Model。此种解决方案未必就好,然而,随着UI的改变,这种共享数据库模型Model引发的问题,开发者很难预知和调试。
举例来说,考虑一种情况:UI要加载一批Book对象,每一个Book对象中引用一个Author 对象。在最初你可能会设计查询策略是使用懒加载Book对象实例,然后使用Book的getAuthor方法返回Author。getAuthor()的第一次调用将触发数据库查询。然后一会,你也认识到你需要在APP的UI里面展示author的名字。你能够很简单的增加这个方法,如下面展示的代码片段:
authorNameTextView.setText(user.getAuthor().getName());
然而,这看似没有问题的代码改变却导致数据库中Author表将会在UI Main Thread主线程被查询。
如果你在此之前先查询author的信息,并把author预先加载出来,这会变得比较困难调整策略如果你却不再使用这些数据。例如,你的APP UI不再需要展示Author 的信息,你的APP却在事实上加载了你不需要的数据,这就浪费了宝贵的内存空间。如果Author 类引用了另外的表,像Book那样,那么这样会导致你的APP性能更加低。
有鉴于此,取而代之的是:在Android Room中,若同一时间内引用多个数据库实体,你应该创建一个POJO,该POJO内嵌每一个你打算使用的实体,此时编写一个查询语句查询需要响应的数据库表。这种良好组织结构的Model,结合Android Room健壮的查询能力,允许你的APP以更低的系统开销加载数据,改进你APP的性能和用户体验。


(正文翻译结束,by zhangphil@csdn)


附录:
1,我翻译的谷歌Android官方原文文档链接:https://developer.android.google.cn/training/data-storage/room/referencing-data.html#understand-no-object-references 
2,《Android官方ORM数据库Room技术解决方案:@Embedded内嵌对象(二)》链接:http://blog.csdn.net/zhangphil/article/details/78621009 

3,我翻译的谷歌Android官方原文内容:


Understand why Room doesn't allow object references

________________________________________
Key takeaway: Room disallows object references between entity classes. Instead, you must explicitly request the data that your app needs.

Mapping relationships from a database to the respective object model is a common practice and works very well on the server side. Even when the program loads fields as they're accessed, the server still performs well.
However, on the client side, this type of lazy loading isn't feasible because it usually occurs on the UI thread, and querying information on disk in the UI thread creates significant performance problems. The UI thread typically has about 16 ms to calculate and draw an activity's updated layout, so even if a query takes only 5 ms, it's still likely that your app will run out of time to draw the frame, causing noticeable visual glitches. The query could take even more time to complete if there's a separate transaction running in parallel, or if the device is running other disk-intensive tasks. If you don't use lazy loading, however, your app fetches more data than it needs, creating memory consumption problems.
Object-relational mappings usually leave this decision to developers so that they can do whatever is best for their app's use cases. Developers usually decide to share the model between their app and the UI. This solution doesn't scale well, however, because as the UI changes over time, the shared model creates problems that are difficult for developers to anticipate and debug.
For example, consider a UI that loads a list of Book objects, with each book having an Author object. You might initially design your queries to use lazy loading such that instances of Book use a getAuthor() method to return the author. The first invocation of the getAuthor() call queries the database. Some time later, you realize that you need to display the author name in your app's UI, as well. You can add the method call easily enough, as shown in the following code snippet:
authorNameTextView.setText(user.getAuthor().getName());
However, this seemingly innocent change causes the Author table to be queried on the main thread.
If you query author information ahead of time, it becomes difficult to change how data is loaded if you no longer need that data. For example, if your app's UI no longer needs to display Author information, your app effectively loads data that it no longer displays, wasting valuable memory space. Your app's efficiency degrades even further if the Author class references another table, such as Books.
To reference multiple entities at the same time using Room, you instead create a POJO that contains each entity, then write a query that joins the corresponding tables. This well-structured model, combined with Room's robust query validation capabilities, allows your app to consume fewer resources when loading data, improving your app's performance and user experience.
相关文章
|
2月前
|
SQL 关系型数据库 数据库连接
php连接数据库之PDO,PDO的简单使用和预定义占位符的使用以及PDOStatement对象的使用,占位符的不同形式,bindValue和bindParam绑定预定义占位符参数的区别
本文介绍了PHP中PDO(PHP Data Objects)扩展的基本概念和使用方法。内容包括PDO类和PDOStatement类的介绍,PDO的简单使用,预定义占位符的使用方法,以及PDOStatement对象的使用。文章还讨论了绑定预定义占位符参数的不同形式,即bindValue和bindParam的区别。通过具体示例,展示了如何使用PDO进行数据库连接、数据查询、数据插入等操作。
php连接数据库之PDO,PDO的简单使用和预定义占位符的使用以及PDOStatement对象的使用,占位符的不同形式,bindValue和bindParam绑定预定义占位符参数的区别
|
2月前
|
数据库 Python
django中数据库外键可以自定义名称吗
django中数据库外键可以自定义名称吗
|
3月前
|
SQL Java 数据库连接
Hibernate 是一款开源 ORM(对象关系映射)框架,封装了 JDBC,允许以面向对象的方式操作数据库,简化了数据访问层的开发。
Hibernate 是一款开源 ORM(对象关系映射)框架,封装了 JDBC,允许以面向对象的方式操作数据库,简化了数据访问层的开发。通过映射机制,它可以自动处理对象与数据库表之间的转换,支持主流数据库,提高了代码的可移植性和可维护性。其核心接口包括 SessionFactory、Session 和 Transaction 等,通过它们可以执行数据库的 CRUD 操作。配置方面,需在项目中引入 Hibernate 及数据库驱动依赖,并创建 `hibernate.cfg.xml` 配置文件来设置数据库连接和 Hibernate 行为参数。
44 1
|
3月前
|
数据库连接 数据库
实现加载驱动、得到数据库对象、关闭资源的代码复用,将代码提取到相应的工具包里边。优化程序
该博客文章展示了如何通过创建工具类`Connectiontools`实现数据库连接、语句执行以及资源关闭的代码复用,以优化程序并提高数据库操作的效率和安全性。
|
3月前
|
存储 SQL 数据库
【计算机三级数据库技术】第7章 数据库及数据库对象--附思维导图
文章概述了数据库的创建、维护、架构、分区表、索引和索引视图的操作要点,并提供了SQL Server环境下的具体T-SQL命令示例。内容涵盖了数据库文件的管理、架构的使用、分区表的创建和优化、索引的创建与删除,以及索引视图的定义和应用场景。
32 2
|
3月前
|
SQL 关系型数据库 数据库
手把手教你管理PostgreSQL数据库及其对象
手把手教你管理PostgreSQL数据库及其对象
47 0
|
3月前
|
SQL 数据库
拒绝了对对象 ‘GetTips‘ (数据库 ‘vipsoft‘,架构 ‘dbo‘)的 EXECUTE 权限
拒绝了对对象 ‘GetTips‘ (数据库 ‘vipsoft‘,架构 ‘dbo‘)的 EXECUTE 权限
40 0
|
4月前
|
Oracle 关系型数据库 数据库
|
4月前
|
存储 JSON 数据库
项目管理定义问题之什么是序列化大对象的值对象数据库形态
项目管理定义问题之什么是序列化大对象的值对象数据库形态