SQLiteBlobTooBigException:写入数据库时行太大,无法放入CursorWindow

ghg1uchk  于 2023-10-23  发布在  SQLite
关注(0)|答案(7)|浏览(576)

当我尝试在android上添加sqllite DB时,我看到了上面的错误。我正在使用cloudant库。下面是堆栈跟踪:

2019-07-17 18:04:48.292 5522-5753/org.iprd.identity E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT docs.docid, docs.doc_id, revid, sequence, current, deleted, parent, json FROM revs, docs WHERE docs.docid=? AND revs.doc_id=docs.doc_id AND revid=? ORDER BY revs.sequence LIMIT 1
2019-07-17 18:04:48.302 5522-5522/org.iprd.identity E/DatabaseImpl: Failed to create document
    java.util.concurrent.ExecutionException: android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1
        at java.util.concurrent.FutureTask.report(FutureTask.java:123)
        at java.util.concurrent.FutureTask.get(FutureTask.java:193)
        at com.cloudant.sync.internal.documentstore.DatabaseImpl.get(DatabaseImpl.java:1084)
        at com.cloudant.sync.internal.documentstore.DatabaseImpl.create(DatabaseImpl.java:925)

我从来没有得到这个问题以前,但是,我最近做了一个改变,并开始使用第3方工具给我给予一些图像。有了这个新工具,图像大小似乎比以前大得多。我通过对图像进行Base64编码,将这些图像作为字符串存储在数据库中。然而,使用这个新工具,在存储图像时,我得到了上面的异常。
我有一个单元测试,我试图使用从这个图像中生成的字符串之一,但也抛出了一个错误,字符串大小太大,甚至无法编译。
解决这个问题的最佳方法是什么?-
1.我想做的是将图像存储在设备本身中,并将路径存储在DB中。
1.我们可以对图像进行一些压缩以减小其文件大小吗?
1.有没有可能调整一些db设置,以确保它可以处理更大的图像尺寸?
提前感谢!

nnsrf1az

nnsrf1az1#

我想做的是将图像存储在设备本身中,并将路径存储在DB中。
我不会回答的,因为你是最适合回答这个问题的。
我们可以对图像进行一些压缩以减小其文件大小吗?
有可能,但这并不一定会消除问题。即使你把图像压缩到2 Mb(光标窗口4 Mb限制的一半),那么可能一次只有一行适合光标窗口。结果可能是非常差的性能,瓶颈不是真正的SQLite,而是处理光标。

*不推荐

另一个解决方案,但仍然昂贵,将图像存储在部分/块中,这样做的一个例子(注意,没有进行调优来建立256 kb的块大小)可以在这里找到。注意到React时间被认为很短

*不推荐但如果性能不佳不是问题,那么可能是一个解决方案

不需要额外压缩/解压缩开销的解决方案是将图像或超过设定大小的图像存储在文件系统中(例如,外部存储器)并存储路径或路径的一部分。

  • 后一种选择,将小图像存储在数据库中,将大图像存储为文件,可以利用35% Faster Than The Filesystem)。
    *这里是一个混合路径/blob解决方案的例子。
    *注意这个例子既可以作为存储路径的基础,也可以作为混合解决方案的基础。
    *推荐

有没有可能调整一些db设置,以确保它可以处理更大的图像尺寸?
是的
你可以考虑:

  • 优化您的查询。首先,请参阅EXPLAIN QUERY PLANThe SQLite Query Optimizer Overview
  • 增加页面大小(注意限制),
  • 增加该高速缓存大小,
  • 同步切换到关闭的风险,
  • 使用独占锁定的风险。
  • 编译你自己的SQLite调优版本,应用compile time options来适应。
  • 进一步阅读上述链接,因为可能存在附加的适用调谐设置。
umuewwlo

umuewwlo2#

我的解决方法如下:当我从我的远程银行搜索图像时,我会检查它们的大小,如果它们大于500 kb,我会执行一个删除过程。

produto.setImagem_img(imagemTratada(rs.getBytes("imagem_img")));

神奇的方法:

private byte[] imagemTratada(byte[] imagem_img){

    while (imagem_img.length > 500000){
        Bitmap bitmap = BitmapFactory.decodeByteArray(imagem_img, 0, imagem_img.length);
        Bitmap resized = Bitmap.createScaledBitmap(bitmap, (int)(bitmap.getWidth()*0.8), (int)(bitmap.getHeight()*0.8), true);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        resized.compress(Bitmap.CompressFormat.PNG, 100, stream);
        imagem_img = stream.toByteArray();
    }
    return imagem_img;

}
z9gpfhce

z9gpfhce3#

是的-这是一个真正的问题。但我对此进行了修复。我们基本上是在我们的文档中的生物特征图像。我现在做的:存储各个生物特征实体(例如:指纹)在不同的文件。拥有一个具有此文档ID的主控文档。
例:我们捕捉一个人的拇指和食指。我们存储两个文档来存储它们-让我们称之为thumb.json和index.json。它们的文档ID分别为thumb_100和index_100。现在,我们有了一个生物识别博士,看起来像这样:
“thumb”:“thumb_100”“index”:“index_100”
这有助于我们从主文档中获取拇指和食指指纹。更重要的是,它确保单个行的大小不会超过限制或导致前面看到的异常。

dy2hfwbg

dy2hfwbg4#

我发现了如何使用length()和substr()来只请求1MB(CursorWindow的最大值是2MB),也许它会help。(如果用户有这个问题,你需要避免异常)此外,你可以使用context.getContentResolver().query(),选择只包括相关的列,这样你就不会加载与其他列相关的数据(并保存一些空间)。否则,我会推荐您建议的第一个选项,即将文件存储在内部存储中,并将文件路径存储在数据库中。

vohkndzv

vohkndzv5#

如果你想在SQLite或Room中将图像保存为字节数组,你应该压缩字节数组。
这样

Bitmap bmp = intent.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
9bfwbjaz

9bfwbjaz6#

我最近也遇到了同样的问题,经过一番研究,我找到了这个解决方案:
将以下代码添加到MainApplication.onCreate

try {
  Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
  field.setAccessible(true);
  field.set(null, 100 * 1024 * 1024); // 100MB is the new size
} catch (Exception e) {
  if (BuildConfig.DEBUG) {
    e.printStackTrace();
  }
}

您需要以下导入:

import android.database.CursorWindow;
import java.lang.reflect.Field;

感谢在github issue中发布此解决方案的@bashen1

6mzjoqzu

6mzjoqzu7#

将图像存储在应用程序私有存储下的设备中。并将图像路径存储在数据库中。

相关问题