×

Android 原生 SQLite 以及 GreenDao 简单使用

96
龙衣袭
2018.08.10 22:23* 字数 596

为啥使用数据库?

缓存!!!当然内容少的可以使用文件存储,还可以使用SharedPreferences.

sqlite 增删改查

环境配置

创建数据库、创建表:

1. 先创建一个数据库管理类

public class MyDataBase extends SQLiteOpenHelper {
    private static final String TAG = "MyDataBase";
    private Context mContext ;

    // 建表命令
    public static final String CREATE_BOOK = "create table Book ("
            +"id integer primary key autoincrement,"
            +"author text,"
            +"price real,"
            +"pages integer,"
            +"name text)";

    public MyDataBase(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context ;
    }


    @Override
    public void onCreate(SQLiteDatabase db) {
        // 创建表
        db.execSQL(CREATE_BOOK);
        Log.e(TAG, "onCreate: 创建数据库成功");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

2. 在合适的地方创建数据库(这里为了测试方便,点击按钮后开始创建数据库)

mMyDataBase = new MyDataBase(getContext(), "BookStore.db", null, 1);
Button btnCreateDb = view.findViewById(R.id.btn_create_db);
btnCreateDb.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 创建数据库
        mMyDataBase.getWritableDatabase();

    }
});

不出意外这时候数据库已经创建成功。window 系统可通过配置环境变量后通过 adb 命令来查看数据库是否创建成功。

参考:

Android的ADB配置环境和adb指令使用

如何使用adb命令查看android中的数据库

有时候我们需要添加新的数据表,但是在MyDataBase onCreate方法中添加新的创建表命令却没有创建出表单,这是因为在 onCreate 方法创建过数据库之后就不会再被调用了,也就不会执行里面的操作了。这时候该怎么添加新的表单呢?

数据库升级(添加新的表)

  1. 在 MyDataBase 中添加创建表的语句
public static final String CREATE_CATEGORY = "create table category ("
        +"id integer primary key autoincrement,"
        +"category_name text,"
        +"category_code integer)";
  1. 在 MyDataBase 的 onUpgrade 方法中添加如下语句:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // 判断新添加的 category 表是否存在(一般不存在),存在则删除
    db.execSQL("drop table if exists Category");
}
  1. 在 onCreate 方法中添加建表命令
@Override
public void onCreate(SQLiteDatabase db) {
    // 创建表
    db.execSQL(CREATE_BOOK);
    // 新添加的 category 表
    db.execSQL(CREATE_CATEGORY);
    Log.e(TAG, "onCreate: 创建数据库成功");
}
  1. 在 创建数据库名的地方修改数据库的版本号,将其改为比之前大的数值
// 最后一个参数改为 2(之前是 1 )
mMyDataBase = new MyDataBase(getContext(), "BookStore.db", null, 2);

以下的操作可以利用 adb 命令查看结果。

增加一条数据

查看添加的数据 adb 命令:select * from Book;

btnAddData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 添加两条数据
        SQLiteDatabase db = mMyDataBase.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("name","DataBase Test");
        values.put("author","Aller");
        values.put("pages","450");
        values.put("price","20.98");
        db.insert("Book",null,values);

        // 第二条数据
        values.put("name","Android DataBase");
        values.put("author","Dong");
        values.put("pages","520");
        values.put("price","70.98");
        db.insert("Book",null,values);

        // 在 ui 上显示
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mTvShowResult.setText("插入了两条数据");
            }
        });


    }
});

更新一条数据

查看添加的数据 adb 命令:select * from Book;注意看修改的值

btnDeleteData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 更新了名字为 Dong 的作者的书价格
        SQLiteDatabase db = mMyDataBase.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("price",89.99);
        db.update("Book",values,"name = ?", new String[]{"Dong"});
        // 在 ui 上显示
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mTvShowResult.setText("更新了名字为 Dong 的作者的书价格");
            }
        });

    }
});

删除一条数据

查看添加的数据 adb 命令:select * from Book; 注意看表中数据的个数

btnUpdateData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 删除数据库中页码书大于500的书籍
        SQLiteDatabase db = mMyDataBase.getWritableDatabase();
        db.delete("Book","pages > ?", new String[]{"500"});
        // 在 ui 上显示
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mTvShowResult.setText("删除数据库中页码书大于500的书籍");
            }
        });

    }
});

查询一条数据

注意在 手机UI上 查看mTvShowResult.setText(mStringBuilder);输出的值

btnQueryData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 查询一条数据
        mStringBuilder = new StringBuilder();
        SQLiteDatabase db = mMyDataBase.getWritableDatabase();
        Cursor cursor = db.query("Book", null, null, null, null, null, null);
        if (cursor.moveToFirst()){
            // 有数据
            do {
                String name = cursor.getString(cursor.getColumnIndex("name"));
                String author = cursor.getString(cursor.getColumnIndex("author"));
                int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                double price = cursor.getDouble(cursor.getColumnIndex("price"));
                mStringBuilder.append("数据-->"+name + author + pages + price);
                mStringBuilder.append("\n");

            }while (cursor.moveToNext());
        }

        cursor.close();
        // 在 ui 上显示
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mTvShowResult.setText(mStringBuilder);
            }
        });
    }
});

GreenDao 增删改查

GreenDao Github 地址

GreenDao 官方文档

环境配置

  • 第一步:project:build.gradle 下添加
buildscript {
    
    repositories {
        // 添加这两行
        jcenter()
        mavenCentral()
    }
    dependencies {
        // 还有这两行
        classpath 'com.android.tools.build:gradle:3.1.2'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
      
    }
}
  • 第二步:在 module:build.gradle中添加
apply plugin: 'org.greenrobot.greendao'

dependencies {
    ...
    implementation 'org.greenrobot:greendao:3.2.2'
    ...
}

// 数据库配置
greendao {
    schemaVersion 1
    daoPackage 'com.damon.viewpagereventbustest.gen'
    targetGenDir 'src/main/java'
}
  • 第三步:在 BaseApplication中配置数据库(别忘了在 maifest.xml 中配置 BaseApplication )
public class BaseApplication extends Application {


    private DaoSession mDaoSession;

    @Override
    public void onCreate() {
        super.onCreate();
        DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this,  "greendao-db");
        Database db = helper.getWritableDb();
        mDaoSession = new DaoMaster(db).newSession();
    }

    public DaoSession getDaoSession() {
        return mDaoSession;
    }
}
  • 第四步:使用
// 在 fragment 中获取 BaseApplication
DaoSession daoSession = ((BaseApplication) getActivity().getApplication()).getDaoSession();

// 获取到 mUserDao 就可以为所欲为了~~
mUserDao = daoSession.getUserDao();

增加一条数据

btnAddData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 添加两条数据
        User user = new User();
        user.setName("小王");
        user.setAge(18);
        mUserDao.insert(user);

        User user2 = new User();
        user2.setName("小董");
        user2.setAge(24);
        mUserDao.insert(user2);


        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mTvShowResult.setText("插入了两条数据");
            }
        });
    }
});

更新一条数据

btnUpdateData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 更新数据,先拿到该数据才能更新
        List<User> users = mUserDao.loadAll();
        for (int i = 0; i < users.size(); i++) {
            if (users.get(i).getName().equals("小董")){
                User user = users.get(i);
                user.setAge(19);
                mUserDao.update(user);
                // 在 ui 上显示
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTvShowResult.setText("更新了名字为 小董 的年龄");
                    }
                });
                break;
            }
        }

    }
});

删除一条数据

btnDeleteData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 先查到数据,才能删除
        List<User> users = mUserDao.loadAll();
        for (int i = 0; i < users.size(); i++) {
            if (users.get(i).getName().equals("小董")){
                User user = users.get(i);
                mUserDao.delete(user);
                // 在 ui 上显示
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTvShowResult.setText("删除小董");
                    }
                });
                break;
            }
        }
    }
});

查询数据

btnQueryData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 查询一条数据
        mStringBuilder = new StringBuilder();
        List<User> users = mUserDao.loadAll();
        for (int i = 0; i < users.size(); i++) {
            mStringBuilder.append("数据-->"+users.get(i).getName() + users.get(i).getAge());
            mStringBuilder.append("\n");
        }
        // 在 ui 上显示
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mTvShowResult.setText(mStringBuilder);
            }
        });
    }
});

数据库升级

StackOverFlow上一位大佬给的解决思路:

1. The class catch all the Daos that you got
2. Creates the temporary tables based on the old version's scheme (generateTempTables method)
3. Import all the data to this new tables (generateTempTables method)
4. Drop all the tables of the old version (DaoMaster.dropAllTables method)
5. Creates the tables of the new version (DaoMaster.createAllTables method)
6. Updates the new version's tables from the temporaries (restoreData method)
7. Drop all temporary tables (restoreData method)

工具类代码实现如下:(直接复制可用)

public class MigrationHelper {
    private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
    private static MigrationHelper instance;

    public static MigrationHelper getInstance() {
        if(instance == null) {
            instance = new MigrationHelper();
        }
        return instance;
    }

    @SafeVarargs
    public final void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        generateTempTables(db, daoClasses);
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
        restoreData(db, daoClasses);
    }

    @SafeVarargs
    private final void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (Class<? extends AbstractDao<?, ?>> daoClass : daoClasses) {
            DaoConfig daoConfig = new DaoConfig(db, daoClass);

            String divider = "";
            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            ArrayList<String> properties = new ArrayList<>();

            StringBuilder createTableStringBuilder = new StringBuilder();

            createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");

            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tableName).contains(columnName)) {
                    properties.add(columnName);

                    String type = null;

                    try {
                        type = getTypeByClass(daoConfig.properties[j].type);
                    } catch (Exception exception) {
//                        Crashlytics.logException(exception);
                    }

                    createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);

                    if (daoConfig.properties[j].primaryKey) {
                        createTableStringBuilder.append(" PRIMARY KEY");
                    }

                    divider = ",";
                }
            }
            createTableStringBuilder.append(");");

            db.execSQL(createTableStringBuilder.toString());

            String insertTableStringBuilder = "INSERT INTO " + tempTableName + " (" +
                    TextUtils.join(",", properties) +
                    ") SELECT " +
                    TextUtils.join(",", properties) +
                    " FROM " + tableName + ";";

            db.execSQL(insertTableStringBuilder);
        }
    }

    @SafeVarargs
    private final void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (Class<? extends AbstractDao<?, ?>> daoClass : daoClasses) {
            DaoConfig daoConfig = new DaoConfig(db, daoClass);

            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            List<String> properties = new ArrayList<>();

            for (int j = 0; j < daoConfig.properties.length; j++) {
                String columnName = daoConfig.properties[j].columnName;

                if (getColumns(db, tempTableName).contains(columnName)) {
                    properties.add(columnName);
                }
            }

            String insertTableStringBuilder = "INSERT INTO " + tableName + " (" +
                    TextUtils.join(",", properties) +
                    ") SELECT " +
                    TextUtils.join(",", properties) +
                    " FROM " + tempTableName + ";";

            db.execSQL(insertTableStringBuilder);
            db.execSQL("DROP TABLE " + tempTableName);
        }
    }

    private String getTypeByClass(Class<?> type) throws Exception {
        if(type.equals(String.class)) {
            return "TEXT";
        }
        if(type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
            return "INTEGER";
        }
        if(type.equals(Boolean.class)) {
            return "BOOLEAN";
        }

        //        Crashlytics.logException(exception);
        throw new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
    }

    private static List<String> getColumns(Database db, String tableName) {
        List<String> columns = new ArrayList<>();
        Cursor cursor = null;
        try {
            cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
            if (cursor != null) {
                columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
            }
        } catch (Exception e) {
            Log.v(tableName, e.getMessage(), e);
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return columns;
    }
}

使用: 在 DaoMaster.java 中添加如下内容(该文件在 module:build.gradle 中配置的路径:

greendao {
    schemaVersion 1 // 升级后需要改为比之前版本(1)大的数值
    daoPackage 'com.damon.viewpagereventbustest.gen'//这是我配置的路径
    targetGenDir 'src/main/java'
})
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
    Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
    if (newVersion > oldVersion) {
        // 升级、数据库迁移操作
        MigrationHelper.getInstance().migrate(db, UserDao.class);
    }else {
        // 默认操作
        dropAllTables(db, true);
        onCreate(db);
    }
}

以上代码已通过测试,有问题可以沟通~谢谢理解和支持!

开发
Web note ad 1