迁移学习
您曾经与Rails的迁移一起工作吗? 他们使数据库更改变得轻而易举,不是吗? 尽管每个软件发行版不一定都涉及迁移,但是当某个软件发行版确实恰好可以利用它时,我总是对事情的进展很满意。 无论是添加新数据还是更改现有数据结构,Rails迁移都使开发数据存储库(无论是RDMBS还是像MongoDB这样的NoSQL数据存储库)变得轻松自如。
最近,当我发现自己为自己的一个Android应用程序更改了SQLite数据库的数据结构时,我发现自己希望有一些与Rails中类似的Android迁移机制。 las,我不能罚款,所以我做了其他开发人员会做的事情:我写了一个。
Droid Migrate是一个简单的命令行框架,可为使用SQLite的Android应用程序生成并运行数据库迁移。 迁移由包含up
和down
方法的DBVersion
类封装。 调用up
方法进行升级,调用down
进行回滚。 这些方法的工作完全取决于您。
此外,Droid Migrate生成一个DatabaseHelper
类,通过该类您可以获取与SQLite实例的基础连接–无论如何,这是在Android应用中 与SQLite进行 交互的规范方法,但是使用Droid Migrate,您将获得一个经过特殊增强的DatabaseHelper
,该DatabaseHelper
可以确定哪个版本目标数据库实例的版本是最新的,并运行适当的迁移以将数据库升级到该版本。
因此,使用新创建的DatabaseHelper
类,您仍然可以像通常一样与应用程序的数据库进行交互,但是,通过使用此类,可以为您处理所有迁移。 请允许我示范。
我已经创建了一个简单的应用程序,该应用程序目前不与任何数据库交互–它只是创建了一个ListView
,该ListView
旨在保存记录列表以供查看。 如果您想继续,可以在Github上找到此应用。 尽管如此,该应用程序的主要活动如下所示。
没有任何SQLite逻辑的简单Android应用
package com.b50.db.ex;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.textView1);
textView.setText("This would be a list from a DB if there was a DB");
}
}
我想做的就是添加与SQLite数据库进行交互的功能; 另外,我希望能够在后续版本中发展数据模型。 这是Droid Migrate闪耀的地方。
安装Droid Migrate(只需克隆或下载代码,进行构建,然后将其放入PATH
并创建名为DROID_MIGRATE_HOME
新环境变量)之后,我可以通过在根目录中打开一个终端来初始化我的应用程序以使用Droid Migrate我的应用程序并输入:
初始化Droid迁移
$> droid-migrate init -d a_catalog
-d
标志指定所需数据库的名称。 如果希望将新生成的类与主应用程序放在单独的包中,则可以通过-p
标志提供包名。
如果您查看应用程序的代码,则应该注意到许多新事物。 首先,您将看到两个新类和一个新的jar文件。 这些类是前面提到的DatabaseHelper
和一个名为DBVersion1
的类。 应用程序的libs
文件夹中新添加的jar文件包含一些与Droid Migrate的运行时依赖项相对应的类-此jar非常紧凑,只有4KB。
DatabaseHelper
类非常简单:
DatabaseHelper再简单不过了
package com.b50.db.ex;
import com.b50.db.ex.R;
import android.content.Context;
import com.b50.migrations.MigrationsDatabaseHelper;
public class DatabaseHelper extends MigrationsDatabaseHelper {
public DatabaseHelper(Context context) {
super(context, context.getString(R.string.database_name), null,
context.getResources().getInteger(R.integer.database_version),
context.getString(R.string.package_name));
}
}
该类扩展了Droid Migrate的MigrationsDatabaseHelper
,最终扩展了Android的SQLiteOpenHelper
因此,正如我前面提到的,您已经拥有通过DatabaseHelper
与SQLite交互所需的一切。 如果仔细观察,您会发现该类利用了专用的XML文件(最终会生成到R
类中)。
在res/values
文件夹中查看并打开新创建的migrations.xml
文件。 它看起来应该像这样:
migrations.xml包含数据库版本,程序包名称和数据库名称
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="database_version">1</integer>
<string name="database_name">a_catalog</string>
<string name="package_name">com.b50.db.ex</string>
</resources>
注意database_version
的值-为1。这对应于生成的DBVersion1
类。 看一看该课程:
DBVersion1是您的初始迁移类
package com.b50.db.ex;
import com.b50.migrations.AbstractMigration;
public class DBVersion1 extends AbstractMigration {
public void up() {
//execSQL("some sql create stmts");
}
public void down() {
//execSQL("some delete sql stmts");
}
}
在此类中,您可以实现初始迁移,这将创建各种表并填充它们。 使用execSQL
方法传递有效SQL String
。 例如,我将创建一个初始迁移,如下所示:
现在已实现DBVersion1
package com.b50.db.ex;
import com.b50.migrations.AbstractMigration;
public class DBVersion1 extends AbstractMigration {
public void up() {
String create = "CREATE TABLE hops (_id integer PRIMARY KEY AUTOINCREMENT DEFAULT NULL, name TEXT, description TEXT, substitutions TEXT DEFAULT '', alpha_acid TEXT DEFAULT '', beer_styles TEXT DEFAULT '', type TEXT DEFAULT '', user_notes TEXT DEFAULT '');";
execSQL(create);
String oneThing = "INSERT INTO 'hops' VALUES(1,'Amarillo','Spicy hop with mild bitterness and a noble aroma. Good all around hop.','Cascade, Centennial','7 to 10','Ale, IPA','Aroma', '');";
execSQL(oneThing);
}
public void down() {
execSQL("DROP TABLE hops;");
}
}
如您所见,我的up
方法创建一个表并插入一条记录。 我的down
方法回滚down
一切,在这种情况下,这意味着删除创建的表。
现在,我要做的就是利用我应用程序的DatabaseHelper
实例,Droid Migrate将确保正确初始化所有内容。 因此,我将更新原始活动以显示数据库中的内容的列表,根据我的初始迁移,我只知道这是一条记录。
更新了活动以与SQLite进行交互
package com.b50.db.ex;
import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
public class MainActivity extends Activity {
protected SQLiteDatabase db;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.db = (new DatabaseHelper(this)).getWritableDatabase();
ListView list = (ListView) findViewById(R.id.list);
ListAdapter adapter = getAdaptorForQuery("SELECT _id, name, description FROM hops ORDER BY name ASC", null);
list.setAdapter(adapter);
}
private ListAdapter getAdaptorForQuery(String queryString, String[] parameters) {
Cursor cursor = this.db.rawQuery(queryString, parameters);
return new SimpleCursorAdapter(this, R.layout.list_item, cursor,
new String[] { "name", "description" }, new int[] { R.id.hopName, R.id.description }, 0);
}
}
从上面的代码中可以看到,该应用程序现在对基础SQLite实例进行查询,并根据查询的结果集构建ListView
。
关键是如何获取SQLiteDatabase
实例: this.db = (new DatabaseHelper(this)).getWritableDatabase();
–这就是所有魔术发生的地方。 Droid Migrate将版本号传递给Android平台,如果有更改,Android平台将调用一系列生命周期方法,Droid Migrate与您的迁移相关联。
例如,让我们想象该应用程序的后续发行版将更多数据添加到hops
表中。 因此,我将生成一个新的迁移。 这是通过在项目的根目录中键入以下命令来完成的,如下所示:
产生新的迁移
$> droid-migrate generate up
up
标志表示数据库版本(即版本++)增加,而down
标志表示回滚(即版本–)。 如果查看应用程序的代码,您会注意到一个新类: DBVersion2
并且您的migrations.xml
文件已更新: database_version
值现在为2。
我将像这样实现DBVersion2
类:
实现DBVersion2以添加另一行数据
package com.b50.db.ex;
import com.b50.migrations.AbstractMigration;
public class DBVersion2 extends AbstractMigration {
public void up() {
execSQL("INSERT INTO 'hops' VALUES(100,'Zythos','New IPA style hop blend created to optimize and exceed the aroma characteristics of the traditional, and sometimes hard to get, IPA hops.','Amarillo, Columbus, Cascade','9.5 to 12','IPAs','Bittering and Aroma', '');");
}
public void down() {
execSQL("DELETE from 'hops' where _id = 100");
}
}
现在,如果我启动我的应用程序,则ListView
中将包含2个项目!
如果需要回滚怎么办? 就这么简单。 想象一下,添加第二行数据是一个巨大的错误,相反,我实际上只想要一行(即,我只想要最初在DBVersion1
创建的数据)。 我要做的就是在项目的根目录下键入:
Droid Migrate中的回滚同样简单
$> droid-migrate generate down
键入上面的命令后,您应该看到以下输出:
回滚到版本1!
Generating a rollback migration...
Rolling back your migrations.xml file to indicate database version 1
Done!
项目中唯一会更改的是migrations.xml
文件– database_version
值将回滚到1(或1减去当前版本的值)。
重新启动应用程序,然后DBVersion2
:因为执行了DBVersion2
的down
方法,所以显示一个值!
Droid Migrate使升级和回滚到基础SQLite数据库变得轻而易举。 而且,它不仅可以处理一个版本,还可以处理升级或回滚。 也就是说,如果应用程序实例从版本2升级到版本6,则每个迁移将按顺序(3、4、5和6)运行。 回滚也是如此。
如果您在Android应用程序中使用SQLite,强烈建议您看一下Droid Migrate !
翻译自: https://www.javacodegeeks.com/2013/07/introducing-android-migrations.html
迁移学习