说实话android的数据库确实比较难用,尤其是数据量较大的时候。使用的SQL语句可能就比较多了。再加上占位符,体积庞大。于是realm,greendao这些自动建立数据库的就出现了。

Realm

realm优点:比SQLite更简洁,更省空间,可以只保存在内存,应用关闭自动清理,自带加密功能。调用方法易读,易用。

缺点:
1.数据必须与数据库同步,第一次set之后,更新必须数据库的数据也要更新,简直有点霸王条款的意思?我每个对象都要写两次,一个对应数据库,一个对应其他的,这不太科学。
2.不能继承RealmObject以外的类【给的RealmModel实现方式是假的,继承就bug】。

数据库初始化

Realm.init(this);
        RealmConfiguration config = new RealmConfiguration.Builder()
                .name(Config.dbName)
                .schemaVersion(Config.dbVersion)
                //.isMemory()//内存缓存用
                .encryptionKey(Config.dbKey.getBytes())//加密字符串长度64即byte128
                .migration(DBUtil.getIntance())//升级数据库处理类(实现RealmMigration接口)
                .build();
        Realm.setDefaultConfiguration(config);

数据库升级(需要实现RealmMigration )

public class DBUtil implements RealmMigration {
    private static  DBUtil sIntance;
    public DBUtil() {
    }

    /**
     * 双检索单例
     * @return
     */
    public  static  DBUtil getIntance(){
        if (sIntance == null) {
            synchronized (DBUtil.class) {
                if (sIntance == null) {
                    sIntance = new DBUtil();
                }
            }
        }



        return  sIntance;
    }

    /**
     * 获取realm对象
     * @return
     */
    public Realm getRealm(){
        Realm realm =getDefaultInstance();
        return  realm;
    }

    /**
     * 版本升级处理
     * @param realm
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
        RealmSchema schema = realm.getSchema();
        switch ((int)oldVersion){
//            case 0:{
//                RealmObjectSchema personSchema = schema.get("User");//获取表
////                //新增@Required的id
//                personSchema
//                        .addField("outerId", String.class)//添加字段
//                        .transform(new RealmObjectSchema.Function() {
//                            @Override
//                            public void apply(DynamicRealmObject obj) {
//                                obj.set("outerId", "1");//为id设置默认值
//                            }
//                        });
////                        .removeField("age");//移除age属性
//                //注意version不要break,因为前面的版本都要升级
//            }
        }

    }
}

realm bean初始化

public class User extends RealmObject {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public NormalUser toNormalUser(){
        NormalUser user = new NormalUser();
        user.setId(id);
        user.setName(name);
        return user;
    }

}

dao层(手写)

public class UserDao implements BaseDao<User> {
    private UserDao(){
    }

    private Realm realm;
    private Realm getRealm(){
        if(realm == null)
            realm = DBUtil.getIntance().getRealm();
        return realm;
    }

    private static UserDao dao;
    public static UserDao getInstance(){
        if(dao == null)
            dao = new UserDao();
        return dao;
    }

    @Override
    public void insert(final User user) throws Exception {
        getRealm().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                User u = realm.createObject(User.class);
                u.setId(user.getId());
                u.setName(user.getName());
            }
        });
    }

    @Override
    public List<User> find() throws Exception {

        List<User> mlist = null;
        mlist =  getRealm().where(User.class).findAllSorted("id", Sort.ASCENDING);
        return mlist;
    }

    @Override
    public void update(final User user) throws Exception {
        getRealm().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                User u=realm.where(User.class).equalTo("id",user.getId()).findFirst();
                u.setName(user.getName());
            }

        });
    }


    @Override
    public void delete(final String id) throws Exception {
        getRealm().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                RealmResults<User> result = realm.where(User.class).equalTo("id", id).findAll();
                if(result!=null)
                    result.deleteAllFromRealm();
            }
        });

    }

    @Override
    public void close() {
        getRealm().close();
    }

    //分页查询
    public static <E extends RealmModel> List<E> getLimitList(RealmResults<E> data, int offset, int limit) {
        List<E> obtainList = new ArrayList();
        Realm realm = Realm.getDefaultInstance();
        if (data.size() == 0 ){
            return obtainList;
        }
        for (int i = offset; i < offset + limit; i++) {
            if (i >= data.size()) {
                break;
            }
            E temp = realm.copyFromRealm(data.get(i));
            obtainList.add(temp);
        }
        realm.close();
        return obtainList;
    }
}

realm插入:

try {
                    dao.insert(user);
                    dao.insert(user2);
                    dao.insert(user3);
                    List<User> users = dao.find();
                    for (int i = 0; i < users.size(); i++) {
                        Toast.makeText(this, "插入数据" + users.get(i), Toast.LENGTH_LONG).show();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

realm删除:

try {
                    List<User> users = dao.find();
                    if (users != null && users.size() > 0) {
                        User user = users.get(0);
                        String id = user.getId();
                        dao.delete(id);
                        Toast.makeText(this, "删除数据", Toast.LENGTH_LONG).show();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

realm更新

List<User> users = null;
                try {
                    users = dao.find();
                    if (users != null && users.size() > 0) {
                        NormalUser user = users.get(0).toNormalUser();
                        user.setName("userChange");
                        dao.update(user.toDBUser());
                        Toast.makeText(this,"更新数据"+user, Toast.LENGTH_LONG).show();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

realm查找

try {
                    List<User> users = dao.find();
                    for(User user:users){
                        Toast.makeText(this,user.toString(), Toast.LENGTH_LONG).show();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

GreenDao

greenDao优点:可和Sqlcipher连用【一直要用sqlcipher,感激】,entity的get,set和构造器自动生成,封装了dao方法。
缺点:
1.不能继承!【确切说是不能继承字段,继承字段不会成为表字段,如果有抽象方法还是可以继承的】
2.没有主键的时候删除和更新失败,不过还好也可以用SQL代替,勉强忍受。必须sql这点太奇怪了,sqlite本身都没这样要求啊。对于短的sql语句,操作不方便,还不如直接sql。
3.我用了3+的版本,惊讶的是居然不能升级。。。只能建立临时表,好无奈,身为数据库居然不能升级(升级后数据被删除),只能临时表拷贝。不过这方法不容易出现数据库升级失败的奇怪问题,或许可以沿用。

为什么都不能继承字段呢?完全不懂啊。。。同事用的greendao介绍给我,看到他用的抽象父类抽象公共get,set方法感觉好无奈。。。不然就只能做个适配器了,一样的麻烦。实在不行就只能自己想办法写一个封装了,自己写的只能简化sql调用过程,其他的应该做不到。。。有空再解决吧。

数据库初始化

ublic class DBManager {
    private static final String PWD = "123";

    private static DaoSession encryptedSession;
    private static final String DB_NAME = "my.db";
    public static DaoSession getSession(){
        if(encryptedSession == null){
            DBHelper dbHelper = new DBHelper(CacheForAndorid.getSuperContext(),DB_NAME,null);
            encryptedSession = new DaoMaster(dbHelper.getEncryptedWritableDb(PWD)).newSession();
        }
        return encryptedSession;
    }

    private static DBUserDao userDao;
    public static DBUserDao getMyDBDao(){
        if(userDao == null){
            userDao = getSession().getDBUserDao();
        }
        return userDao;
    }

    private static DBUserNoKeyDao noKeyDao;
    public static DBUserNoKeyDao getNoKeyDao(){
        if(noKeyDao == null){
            noKeyDao = getSession().getDBUserNoKeyDao();
        }
        return noKeyDao;
    }
}

数据库更新

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;
    }

    public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {

        generateTempTables(db, daoClasses);
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
        restoreData(db, daoClasses);
    }

    /**
     * 生成临时列表
     *
     * @param db
     * @param daoClasses
     */
    private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);

            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) {
                        exception.printStackTrace();
                    }

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

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

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

            db.execSQL(createTableStringBuilder.toString());

            StringBuilder insertTableStringBuilder = new StringBuilder();

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

            db.execSQL(insertTableStringBuilder.toString());

        }
    }

    /**
     * 存储新的数据库表 以及数据
     *
     * @param db
     * @param daoClasses
     */
    private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
        for (int i = 0; i < daoClasses.length; i++) {
            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
            String tableName = daoConfig.tablename;
            String tempTableName = daoConfig.tablename.concat("_TEMP");
            ArrayList<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);
                }
            }

            StringBuilder insertTableStringBuilder = new StringBuilder();

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

            StringBuilder dropTableStringBuilder = new StringBuilder();
            dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
            db.execSQL(insertTableStringBuilder.toString());
            db.execSQL(dropTableStringBuilder.toString());
        }
    }

    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";
        }

        Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
        exception.printStackTrace();
        throw exception;
    }

    private 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;
    }
}
public class DBHelper extends DaoMaster.OpenHelper {

    public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    /**
     * 数据库升级
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        //操作数据库的更新 有几个表升级都可以传入到下面
        MigrationHelper.getInstance().migrate(db,DBUserDao.class);
    }

}

bean

有主键

@Entity
public class DBUser {
    @Id(autoincrement = true)
    private Long id;
    private String name;
}

无主键

@Entity
public class DBUserNoKey {
    private String name;
    private String password;
}

添加数据(dao层不用写,点击build自动生成)

有无主键相同

DBManager.getMyDBDao().insert(user);
        ToastUtil.shorts("保存成功");

删除

有主键

DBManager.getMyDBDao().delete(user);

无主键(必须sql,否则失败)

DBManager.getSession().getDatabase().execSQL("delete from DBUSER_NO_KEY where name='"+userName+"'");

修改

有主键

DBManager.getMyDBDao().update(oldUser);

无主键(一样必须SQL,不sql就bug)

DBManager.getSession().getDatabase()
                    .execSQL("update DBUSER_NO_KEY set password=? where name=?"
                            ,new Object[]{newUser.getPassword(),newUser.getName()});

查询

有无主键相同

Query<DBUserNoKey> query= DBManager.getNoKeyDao().queryBuilder().build();
        List<DBUserNoKey> dbUsers = query.list();
        for(DBUserNoKey dbUser:dbUsers){
            ToastUtil.longs("id="+dbUser.getName()+"\nname="+dbUser.getPassword());
        }

补充,greendao的版本配置在app的build.gradle里面
greendao {
schemaVersion 3//此处为版本号
daoPackage ‘生成dao等数据库文件包名’
targetGenDir ‘src/main/java’
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐