【问题标题】:Is this bad database coding?这是糟糕的数据库编码吗?
【发布时间】:2013-01-01 17:16:39
【问题描述】:

在扩展 SQLiteOpenHelper 的 DatabaseHelper 类中,我设置了各种方法来将 Cursors 返回到我的其他活动,这样我就不会在除 DatabaseHelper 之外的任何其他类中执行任何查询。在这些方法中,我不会在之后关闭光标或数据库,而是像这样返回它:

public Cursor getCoursesLeft()
{
    // Open a readable database.
    SQLiteDatabase database = this.getReadableDatabase();

    // Query the database and return the cursor.
    return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
            new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}

无论我从哪个 Activity 调用方法,我都会确保关闭使用后返回的 Cursor。

既然 Cursor 是一个对象,它应该通过引用传递,对吗?所以从其他 Activity 关闭它应该关闭原始对象,如果我理解正确,关闭 Cursor 也会关闭数据库。

这是一种糟糕的编码习惯吗?

我似乎会随机收到一个 LogCat 错误,说数据库上从未调用过 close,而我在代码中唯一能找到的可能是我如何在这些方法中返回游标的原因。

【问题讨论】:

  • 它的设计相当奇怪。通常,希望一个对象或层“拥有”数据库游标,管理它们,并且只将游标“借用”到其他层,或者根本不公开它们。我会考虑从您启动它的任何地方返回整个数据库操作的结果。您还可以使用回调模式使其他类不知道游标生命周期。 (例如:static.springsource.org/spring/docs/3.0.6.RELEASE/javadoc-api/…

标签: android sqlite


【解决方案1】:

如果我理解正确,关闭光标也会关闭 数据库。

这听起来不太对劲。您必须在关闭所有游标后显式关闭数据库。 logcat 错误是由于您没有关闭数据库而可能试图打开它的另一个实例。

顺序很重要,首先是游标,然后是数据库实例。

<bad joke in 3.. 2.. 1...>

其余的听起来并不是什么不好的做法,当你需要 db 时,你只需要 db 即可。 :D

[编辑]:你说你已经这样做了:

public Cursor getCoursesLeft()
{
    // Open a readable database.
    SQLiteDatabase database = this.getReadableDatabase();
                   ^^^ here you're creating a new instance of the db
which means the db is opened for reading, and the scope of this variable
is lost outside this function. This means you can not close this instance explicitly

    // Query the database and return the cursor.
    return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
            new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}

而是有一个数据库变量,您可以在此方法之外访问它,并在您使用完光标后关闭它(并且您已经关闭了光标)

SQLiteDatabase database;
public Cursor getCoursesLeft()
{
    // Open a readable database.
    database = this.getReadableDatabase();

    // Query the database and return the cursor.
    return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
            new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}
public void someOtherFunction() {
  Cursor blah = getCoursesLeft();
  // do something with blah
  blah.close();
  database.close();
}

【讨论】:

  • 能否在使用Cursor前关闭数据库,会不会影响Cursor访问数据?
  • 永远不要先使用数据库。总是首先游标,然后是数据库实例。
  • 好的,那么当我只能访问返回的光标时,我将如何关闭数据库实例?
  • 人们在这种情况下使用的最佳实践是将所有数据库访问权限放入一个单例类中。这样,在任何给定时间都只存在一个 DB 实例。在这个类中有一些静态方法来打开和关闭数据库。
  • 这不是我所做的将所有数据库访问放入 DatabaseHelper 扩展类吗?
【解决方案2】:

不关闭游标只会导致内存泄漏。关闭数据库是不同的。

关闭游标就像关闭与创建游标时生成的某些.file 文件的特定连接。

因此您应该始终关闭光标。

这是不好的编码吗?

不,是的。不要让您的 Activity 与这些临时文件混为一谈。虽然什么都不会发生,但它看起来并不好

【讨论】:

  • 我确实关闭了光标,在活动完成后使用它。我收到数据库未关闭错误,而不是光标错误。
  • 您必须在完成数据库后运行db.close() 方法。否则会出现该错误
  • 如何从我拥有的当前代码中做到这一点?我是否必须更改处理返回数据的方式?
  • 不会是这样的。您创建自定义数据库类的实例。所以要么在你完成实例后关闭它。或者,如果您需要整个应用程序中的数据。创建静态类Database并关闭onPause()中的数据库
  • 现在我已经在大多数活动的 onCreate 中实例化它,并在 onDestroy 中关闭。你是说我应该在完成任何数据调用后立即将其更改为关闭它?
猜你喜欢
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
  • 2012-09-06
  • 2011-08-01
  • 1970-01-01
  • 2015-07-23
  • 2011-01-13
相关资源
最近更新 更多