我在会议室数据库中有一个表,其字段设置为index
,它是autoincrement
。 Sqlite
将一些元数据保存在其主表中,以保留上一次自动生成的值的计数。
基于我的应用逻辑,我将清除数据库并保留结构;假设我已经向数据库中插入了3个项目,并且发生了上述操作,所以我清除了项目,但是当我插入一个新项目时,它的自动生成的字段将是4,从长远来看,这将导致溢出和应用程序崩溃。我通过删除autoincrement
并手动设置该字段来解决该问题!
现在,我的问题是,如何在每次数据库清除后将自动递增的字段值重置为1(我更喜欢仅以空间的方式)?
答案 0 :(得分:1)
自动递增的工作方式是在确定新值时使用两个值:-
max(the_autoincrement_column)
(即,为已编码AUTOINCREMENT的 rowid 列作为别名的列),第二个是从表 sqlite_sequence 中获得的,该表是在名称列中具有表名称的行的seq列中。
1被添加到更大的值。
理论上,要进行重置,您应该从表中删除所有行,并从 sqlite_sequence 表中删除相应的行。
但是,房间可以保护系统表。简而言之,似乎没有办法利用空间来完成后者,因此是问题所在。 innerHTML
但必须在房间外(之前)运行,因此受到限制。
但是,就溢出而言,基本上按照:-
- 表中的最大行数
表中理论上的最大行数是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拥有数据库时,以下内容会重置序列。
以下是构建“会议室数据库”的步骤,即插入两行,重置顺序(包括删除最近添加的行)
:-
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;
}
}