我想知道实现取消删除的最佳方法是使用SQL作为存储数据的底层结构的应用程序。我问,因为在SQL中一旦发出删除语句,就无法再恢复数据。但是,想象一个应用程序用于将仓库物品客户和供应商数据以及更多内容保存在列表中您的移动应用程序可能在您的口袋中并意外删除数据,或者您可能只是在使用用户界面时出错。
处理这个问题的最佳方法是什么?您可以废除SQL,但随后应用程序将变得缓慢,代码行和代码复杂性肯定会增加。
谢谢。
您可以确保任何此类操作都需要确认。
您可以定期备份数据库,也可以在执行任何此类操作之前备份数据库。
您可以引入此类操作的日志记录,以允许将操作回滚到某个时间点。
没有特定的最佳方式,因为最合适的方式/可能取决于App的复杂性/简单性/效率。
在所有情况下,都会有额外的代码和复杂性。
简而言之,这些考虑因素应该是设计的一部分。
您能告诉我如何使用触发器从原始表信息中复制日志表中的值吗?
考虑以下 :-
DROP TRIGGER IF EXISTS logdelete;
DROP TABLE IF EXISTS main;
DROP TABLE IF EXISTS logtable;
CREATE TABLE IF NOT EXISTS logtable (timestamp TEXT DEFAULT CURRENT_TIMESTAMP, logaction TEXT, val1 TEXT, val2 TEXT, val3 TEXT);
CREATE TABLE IF NOT EXISTS main (id INTEGER PRIMARY KEY, val1 TEXT, val2 TEXT, val3 TEXT);
CREATE TRIGGER IF NOT EXISTS logdelete AFTER DELETE ON main
BEGIN
INSERT INTO logtable (logaction, val1, val2, val3) VALUES('DLT',old.val1,old.val2,old.val3);
END
;
INSERT INTO main (val1,val2,val3) VALUES
('A','B','C'),('D','E','F'),('G','H','I'),('J','K','L'),('M','N','O');
SELECT * FROM main;
SELECT * FROM logtable;
DELETE FROM main WHERE val1 IN ('D','J');
SELECT * FROM main;
SELECT * FROM logtable;
INSERT INTO main (val1,val2,val3) SELECT val1,val2,val3 FROM logtable WHERE logaction = 'DLT';
UPDATE logtable SET logaction = 'DLTDONE' WHERE logaction = 'DLT';
SELECT * FROM main;
SELECT * FROM logtable;
这个
在相关表中添加另一列以跟踪项目是否“已删除”。那么,你实际上不会删除任何记录;你只需要通过适当修改该列的值来软删除和取消删除
但可能允许logtable被删除。
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "mydb";
public static final int DBVERSION = 1;
public static final String TBL_MAIN = "main";
public static final String TBL_LOGTABLE = "logtable";
public static final String TRG_MAINDELETE = "logdelete";
public static final String COL_MAIN_ID = BaseColumns._ID;
public static final String COl_MAIN_VAL1 = "val1";
public static final String COL_MAIN_VAL2 = "val2";
public static final String COL_MAIN_VAL3 = "val3";
public static final String COL_LOGTABLE_TIMESTAMP = "timestamp";
public static final String COl_LOGTABLE_LOGACTION = "logaction";
public static final String COL_LOGTABLE_VAL1 = COl_MAIN_VAL1;
public static final String COL_LOGTABLE_VAL2 = COL_MAIN_VAL2;
public static final String COL_LOGTABLE_VAL3 = COL_MAIN_VAL3;
public static final String LOGACTION_DLTDONE = "DLTDONE";
public static final String LOGACTION_DELETE = "DLT";
private String main_crtsql = "CREATE TABLE IF NOT EXISTS " + TBL_MAIN + "(" +
COL_MAIN_ID + " INTEGER PRIMARY KEY," +
COl_MAIN_VAL1 + " TEXT," +
COL_MAIN_VAL2 + " TEXT, " +
COL_MAIN_VAL3 + " TEXT" +
")";
private String logtable_crtsql = "CREATE TABLE IF NOT EXISTS " + TBL_LOGTABLE + "(" +
COL_LOGTABLE_TIMESTAMP + " TEXT DEFAULT CURRENT_TIMESTAMP, " +
COl_LOGTABLE_LOGACTION + " TEXT, " +
COL_LOGTABLE_VAL1 + " TEXT, " +
COL_LOGTABLE_VAL2 + " TEXT, " +
COL_LOGTABLE_VAL3 + " TEXT " +
")";
private String logdelete_crtsql = "CREATE TRIGGER IF NOT EXISTS " + TRG_MAINDELETE +
" AFTER DELETE ON " + TBL_MAIN +
" BEGIN " +
"INSERT INTO " + TBL_LOGTABLE + "(" +
COl_LOGTABLE_LOGACTION + "," +
COL_LOGTABLE_VAL1 + "," +
COL_LOGTABLE_VAL2 + "," +
COL_LOGTABLE_VAL3 +
")" +
" VALUES(" +
"'DLT'," +
"old." + COL_LOGTABLE_VAL1 + "," +
"old." + COL_LOGTABLE_VAL2 + "," +
"old." + COL_LOGTABLE_VAL3 +
")" +
";" +
" END";
SQLiteDatabase mDB;
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
mDB = this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(logtable_crtsql);
db.execSQL(main_crtsql);
db.execSQL(logdelete_crtsql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public long addMain(String val1, String val2, String val3) {
ContentValues cv = new ContentValues();
cv.put(COl_MAIN_VAL1,val1);
cv.put(COL_MAIN_VAL2,val2);
cv.put(COL_MAIN_VAL3,val3);
return mDB.insert(TBL_MAIN,null,cv);
}
public int deleteMain(String val) {
String whereclause = COl_MAIN_VAL1 + "=?";
String[] whereargs = new String[]{val};
return mDB.delete(TBL_MAIN,whereclause,whereargs);
}
//INSERT INTO main (val1,val2,val3) SELECT val1,val2,val3 FROM logtable WHERE logaction = 'DLT';
//UPDATE logtable SET logaction = 'DLTDONE' WHERE logaction = 'DLT';
public void rollbackMain() {
String columns = " (" + COl_MAIN_VAL1 + "," + COL_MAIN_VAL2 + "," +COL_LOGTABLE_VAL3 + ")";
String values = " SELECT " + COL_LOGTABLE_VAL1 + "," + COL_LOGTABLE_VAL2 + "," + COL_LOGTABLE_VAL3 +
" FROM " + TBL_LOGTABLE + " WHERE " + COl_LOGTABLE_LOGACTION + "='" + LOGACTION_DELETE + "'";
String insertsql = "INSERT INTO " + TBL_MAIN + columns + values;
mDB.beginTransaction();
mDB.execSQL(insertsql);
ContentValues cv = new ContentValues();
cv.put(COl_LOGTABLE_LOGACTION,LOGACTION_DLTDONE);
String wherecluase = COl_LOGTABLE_LOGACTION + "=?";
String[] whereargs = new String[]{LOGACTION_DELETE};
mDB.update(TBL_LOGTABLE,cv,wherecluase,whereargs);
mDB.setTransactionSuccessful();
mDB.endTransaction();
}
public void logtables() {
Cursor csr = mDB.query(TBL_MAIN,null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
csr = mDB.query(TBL_LOGTABLE,null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
csr.close();
}
}
public class MainActivity extends AppCompatActivity {
DBHelper mDBHlpr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHlpr = new DBHelper(this);
// Empty main and logtable
mDBHlpr.getWritableDatabase().delete(DBHelper.TBL_MAIN,null,null);
mDBHlpr.getWritableDatabase().delete(DBHelper.TBL_LOGTABLE,null,null);
// Add some data
mDBHlpr.addMain("Fred","Banana","Rock");
mDBHlpr.addMain("Mary","Orange","Scissors");
mDBHlpr.addMain("Sue","Apple","Paper");
mDBHlpr.logtables();
//Delete some data
mDBHlpr.deleteMain("Mary");
mDBHlpr.deleteMain("MrNobody");
mDBHlpr.deleteMain("Sue");
mDBHlpr.logtables();
//Rollback
mDBHlpr.rollbackMain();
mDBHlpr.logtables();
}
}
(相当于以前的结果,虽然数据不同)
1.
2019-03-27 12:44:37.136 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@7f0608d 2019-03-27 12:44:37.137 I/System.out: 0 { 2019-03-27 12:44:37.137 I/System.out: _id=1 2019-03-27 12:44:37.137 I/System.out: val1=Fred 2019-03-27 12:44:37.137 I/System.out: val2=Banana 2019-03-27 12:44:37.137 I/System.out: val3=Rock 2019-03-27 12:44:37.137 I/System.out: } 2019-03-27 12:44:37.137 I/System.out: 1 { 2019-03-27 12:44:37.137 I/System.out: _id=2 2019-03-27 12:44:37.137 I/System.out: val1=Mary 2019-03-27 12:44:37.137 I/System.out: val2=Orange 2019-03-27 12:44:37.137 I/System.out: val3=Scissors 2019-03-27 12:44:37.137 I/System.out: } 2019-03-27 12:44:37.137 I/System.out: 2 { 2019-03-27 12:44:37.137 I/System.out: _id=3 2019-03-27 12:44:37.137 I/System.out: val1=Sue 2019-03-27 12:44:37.138 I/System.out: val2=Apple 2019-03-27 12:44:37.138 I/System.out: val3=Paper 2019-03-27 12:44:37.138 I/System.out: } 2019-03-27 12:44:37.138 I/System.out: <<<<<
2.
2019-03-27 12:44:37.138 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8d24242 2019-03-27 12:44:37.138 I/System.out: <<<<<
3.
2019-03-27 12:44:37.140 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@2c28253 2019-03-27 12:44:37.140 I/System.out: 0 { 2019-03-27 12:44:37.140 I/System.out: _id=1 2019-03-27 12:44:37.141 I/System.out: val1=Fred 2019-03-27 12:44:37.141 I/System.out: val2=Banana 2019-03-27 12:44:37.141 I/System.out: val3=Rock 2019-03-27 12:44:37.141 I/System.out: } 2019-03-27 12:44:37.141 I/System.out: <<<<<
4.
2019-03-27 12:44:37.142 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@fb8f790 2019-03-27 12:44:37.142 I/System.out: 0 { 2019-03-27 12:44:37.142 I/System.out: timestamp=2019-03-27 01:44:37 2019-03-27 12:44:37.142 I/System.out: logaction=DLT 2019-03-27 12:44:37.142 I/System.out: val1=Mary 2019-03-27 12:44:37.142 I/System.out: val2=Orange 2019-03-27 12:44:37.142 I/System.out: val3=Scissors 2019-03-27 12:44:37.143 I/System.out: } 2019-03-27 12:44:37.143 I/System.out: 1 { 2019-03-27 12:44:37.143 I/System.out: timestamp=2019-03-27 01:44:37 2019-03-27 12:44:37.143 I/System.out: logaction=DLT 2019-03-27 12:44:37.143 I/System.out: val1=Sue 2019-03-27 12:44:37.143 I/System.out: val2=Apple 2019-03-27 12:44:37.143 I/System.out: val3=Paper 2019-03-27 12:44:37.143 I/System.out: } 2019-03-27 12:44:37.144 I/System.out: <<<<<
5.
2019-03-27 12:44:37.145 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@68f7889 2019-03-27 12:44:37.145 I/System.out: 0 { 2019-03-27 12:44:37.146 I/System.out: _id=1 2019-03-27 12:44:37.146 I/System.out: val1=Fred 2019-03-27 12:44:37.146 I/System.out: val2=Banana 2019-03-27 12:44:37.146 I/System.out: val3=Rock 2019-03-27 12:44:37.146 I/System.out: } 2019-03-27 12:44:37.146 I/System.out: 1 { 2019-03-27 12:44:37.146 I/System.out: _id=2 2019-03-27 12:44:37.146 I/System.out: val1=Mary 2019-03-27 12:44:37.146 I/System.out: val2=Orange 2019-03-27 12:44:37.146 I/System.out: val3=Scissors 2019-03-27 12:44:37.146 I/System.out: } 2019-03-27 12:44:37.146 I/System.out: 2 { 2019-03-27 12:44:37.146 I/System.out: _id=3 2019-03-27 12:44:37.146 I/System.out: val1=Sue 2019-03-27 12:44:37.146 I/System.out: val2=Apple 2019-03-27 12:44:37.146 I/System.out: val3=Paper 2019-03-27 12:44:37.146 I/System.out: } 2019-03-27 12:44:37.146 I/System.out: <<<<<
6.
2019-03-27 12:44:37.147 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@4c6408e 2019-03-27 12:44:37.147 I/System.out: 0 { 2019-03-27 12:44:37.147 I/System.out: timestamp=2019-03-27 01:44:37 2019-03-27 12:44:37.147 I/System.out: logaction=DLTDONE 2019-03-27 12:44:37.147 I/System.out: val1=Mary 2019-03-27 12:44:37.147 I/System.out: val2=Orange 2019-03-27 12:44:37.147 I/System.out: val3=Scissors 2019-03-27 12:44:37.147 I/System.out: } 2019-03-27 12:44:37.147 I/System.out: 1 { 2019-03-27 12:44:37.147 I/System.out: timestamp=2019-03-27 01:44:37 2019-03-27 12:44:37.148 I/System.out: logaction=DLTDONE 2019-03-27 12:44:37.148 I/System.out: val1=Sue 2019-03-27 12:44:37.148 I/System.out: val2=Apple 2019-03-27 12:44:37.148 I/System.out: val3=Paper 2019-03-27 12:44:37.148 I/System.out: } 2019-03-27 12:44:37.148 I/System.out: <<<<<