如何通过Android中的Room删除数据库元数据?

时间:2019-05-11 20:20:53

标签: android sqlite android-sqlite android-room

我在会议室数据库中有一个表,其字段设置为index,它是autoincrement Sqlite 将一些元数据保存在其主表中,以保留上一次自动生成的值的计数。

基于我的应用逻辑,我将清除数据库并保留结构;假设我已经向数据库中插入了3个项目,并且发生了上述操作,所以我清除了项目,但是当我插入一个新项目时,它的自动生成的字段将是4,从长远来看,这将导致溢出和应用程序崩溃。我通过删除autoincrement并手动设置该字段来解决该问题!

现在,我的问题是,如何在每次数据库清除后将自动递增的字段值重置为1(我更喜欢仅以空间的方式)?

1 个答案:

答案 0 :(得分:1)

自动递增的工作方式是在确定新值时使用两个值:-

  • 第一个等效于使用max(the_autoincrement_column) (即,为已编码AUTOINCREMENT的 rowid 列作为别名的列)
  • 第二个是从表 sqlite_sequence 中获得的,该表是在名称列中具有表名称的行的seq列中。

    • 请注意,这些值未存储在主表sqlite_master(架构)中,而是存储在sqlite_sequence表中。
    • 只有使用了AUTOINCREMENT后,sqlite_sequence表才会存在。

1被添加到更大的值。

理论上,要进行重置,您应该从表中删除所有行,并从 sqlite_sequence 表中删除相应的行。

但是,房间可以保护系统表。简而言之,似乎没有办法利用空间来完成后者,因此是问题所在。 innerHTML 必须在房间外(之前)运行,因此受到限制。

  • 注意,答案中还有其他代码可用于从0(触发器)开始编号。

但是,就溢出而言,基本上按照:-

  
      
  1. 表中的最大行数
  2.   
     

表中理论上的最大行数是2乘以64的幂   (18446744073709551616或大约1.8e + 19)。此限制无法达到   因为将达到140 TB的最大数据库大小   第一。 140 TB的数据库最多只能容纳大约   1e + 13行,然后仅当没有索引且每行   包含很少的数据。   Here is answer is an example that does the above

使用自动增量时,它是2的63的幂(9,223,372,036,854,775,808‬)(没有自动增量,您可以使用负值(java),因此您可以使用第64位,因此可以达到理论上的最大值)可能是磁盘容量,而不是达到的最高ID。

其他

经过一番游戏之后,当Room拥有数据库时,以下内容会重置序列。

以下是构建“会议室数据库”的步骤,即插入两行,重置顺序(包括删除最近添加的行)

  • 通过将数据库作为标准SQLiteDatabase打开
    • 请注意同时使用OPENREADWRITE和ENABLEWRITEAHEADLOGGING
    • (如果不是后者,则警告消息说在打开数据库时无法关闭WAL,因此只能在WAL模式下将其打开)
  • 删除表中的现有行,并
  • 从sqlite_sequence中删除相应的行,最后
  • 关闭另一个数据库。

:-

public class MainActivity extends AppCompatActivity {

    public static final String DBNAME = "mydatabase";
    public static final String MYTABLENAME = "mytable";

    MyDatabase mydb,mydb2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mydb = Room.databaseBuilder(this,MyDatabase.class,DBNAME).allowMainThreadQueries().build();
        MyTableDAO mytabledao = mydb.getMyTableDAO();
        MyTable mt1 = new MyTable();
        mt1.setName("Test001");
        mytabledao.insert(mt1);
        MyTable mt2 = new MyTable();
        mt2.setName("Test002");
        mytabledao.insert(mt2);
        for (MyTable mt: mytabledao.getAllMyTables()) {
            Log.d("MYTABLEROW","ID=" + String.valueOf(mt.getId()) + " Name=" + mt.getName());
        }

        /*
        while (mydb.isOpen()) {
            mydb.close();
        }
        Ouch if used :-
        E/ROOM: Invalidation tracker is initialized twice :/. (ignored)
        E/ROOM: Cannot run invalidation tracker. Is the db closed?
        java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
        */
        resetSequencedTable(MYTABLENAME);
        //mydb2 = Room.databaseBuilder(this,MyDatabase.class,DBNAME).allowMainThreadQueries().build(); // No Good

        /*
            Works even though :-
            05-12 12:31:40.112 28585-28585/? D/MYTABLEROW: ID=1 Name=Test001
            05-12 12:31:40.112 28585-28585/? D/MYTABLEROW: ID=2 Name=Test002
            05-12 12:31:40.114 28585-28585/? E/SQLiteLog: (5) statement aborts at 2: [PRAGMA journal_mode=PERSIST]
            05-12 12:31:40.115 28585-28585/? W/SQLiteConnection: Could not change the database journal mode of '/data/user/0/soa.myapplication/databases/mydatabase' from 'wal' to 'PERSIST' because the database is locked.  This usually means that there are other open connections to the database which prevents the database from enabling or disabling write-ahead logging mode.  Proceeding without changing the journal mode.
            05-12 12:31:40.126 28585-28585/? D/MYTABLEROW: ID=1 Name=Test003
            05-12 12:31:40.126 28585-28585/? D/MYTABLEROW: ID=2 Name=Test004
         */

        for (MyTable mt: mytabledao.getAllMyTables()) {
            Log.d("MYTABLEROW","ID=" + String.valueOf(mt.getId()) + " Name=" + mt.getName());
        }
        MyTable mt3 = new MyTable();
        mt3.setName("Test003");
        mytabledao.insert(mt3);
        MyTable mt4 = new MyTable();
        mt4.setName("Test004");
        mytabledao.insert(mt4);
        for (MyTable mt: mytabledao.getAllMyTables()) {
            Log.d("MYTABLEROW","ID=" + String.valueOf(mt.getId()) + " Name=" + mt.getName());
        }
    }

    private void resetSequencedTable(String table) {
        Log.d("RESETSEQ","Initiating sequence reset");
        SQLiteDatabase db = SQLiteDatabase.openDatabase(this.getDatabasePath(DBNAME).toString(),null,SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING);
        db.delete(table,null,null);
        String whereclause = "name=?";
        String[] whereargs = new String[]{table};
        db.delete("sqlite_sequence",whereclause,whereargs);
        db.close();
        Log.d("RESETSEQ", "Terminating sequence reset");
    }
}

该表的实体为:-

@Entity(tableName = MainActivity.MYTABLENAME)
public class MyTable {
    @PrimaryKey(autoGenerate = true)
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}