Android ORM数据库框架之-greenDao(四)

本篇是greenDao的最后一篇,这一篇带大家看下greenDao的源码。

  • dao的初始化过程
    这一过程非常的复杂,容易绕晕,那么我就来带大家梳理一下。首先看看我们初始化dao的方法。
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this,"persons-db",null);
        db = helper.getWritableDatabase();
        Log.e("tag","this is db version ->"+db.getVersion());
        // 该数据库连接属于DaoMaster,所以多个Session指的是想用的数据库连接
        daoMaster = new DaoMaster(db);
        daoSession =daoMaster.newSession();
        return daoSession.getPersonDao();

我在这里返回的是PersionDao。首先看下helper的初始化 过程。

public DevOpenHelper(Context context, String name, CursorFactory factory) {
            super(context, name, factory);
        }

调用父类的构造方法。

public static abstract class OpenHelper extends SQLiteOpenHelper {

        public OpenHelper(Context context, String name, CursorFactory factory) {
            super(context, name, factory, SCHEMA_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
            createAllTables(db, false);
        }
    }

在父类中完成数据表的创建。

public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
        PersonDao.createTable(db, ifNotExists);
        PeopleDao.createTable(db, ifNotExists);
        IdCardDao.createTable(db, ifNotExists);
        OrderDao.createTable(db, ifNotExists);
        CourseDao.createTable(db, ifNotExists);
    }
public static void createTable(SQLiteDatabase db, boolean ifNotExists) {
        String constraint = ifNotExists? "IF NOT EXISTS ": "";
        db.execSQL("CREATE TABLE " + constraint + "\"PERSON\" (" + //
                "\"_id\" INTEGER PRIMARY KEY ," + // 0: id
                "\"NAME\" TEXT NOT NULL ," + // 1: name
                "\"AGE\" INTEGER NOT NULL ," + // 2: age
                "\"CARD\" TEXT);"); // 3: card
    }

这么一来,表的创建过程就理清楚了。接下来看DaoMaster的初始化。

public DaoMaster(SQLiteDatabase db) {
        super(db, SCHEMA_VERSION);
        registerDaoClass(PersonDao.class);
        registerDaoClass(PeopleDao.class);
        registerDaoClass(IdCardDao.class);
        registerDaoClass(OrderDao.class);
        registerDaoClass(CourseDao.class);
    }

显示调用父类的构造方法,接着registDaoClass()

public AbstractDaoMaster(SQLiteDatabase db, int schemaVersion) {
        this.db = db;
        this.schemaVersion = schemaVersion;

        daoConfigMap = new HashMap<Class<? extends AbstractDao<?, ?>>, DaoConfig>();
    }

    protected void registerDaoClass(Class<? extends AbstractDao<?, ?>> daoClass) {
        DaoConfig daoConfig = new DaoConfig(db, daoClass);
        daoConfigMap.put(daoClass, daoConfig);
    }

看到,上面的一句很关键。new DaoConfig();

public DaoConfig(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>> daoClass) {
        this.db = db;
        try {
            this.tablename = (String) daoClass.getField("TABLENAME").get(null);
            Property[] properties = reflectProperties(daoClass);
            this.properties = properties;

            allColumns = new String[properties.length];

            List<String> pkColumnList = new ArrayList<String>();
            List<String> nonPkColumnList = new ArrayList<String>();
            Property lastPkProperty = null;
            for (int i = 0; i < properties.length; i++) {
                Property property = properties[i];
                String name = property.columnName;
                allColumns[i] = name;
                if (property.primaryKey) {
                    pkColumnList.add(name);
                    lastPkProperty = property;
                } else {
                    nonPkColumnList.add(name);
                }
            }
            String[] nonPkColumnsArray = new String[nonPkColumnList.size()];
            nonPkColumns = nonPkColumnList.toArray(nonPkColumnsArray);
            String[] pkColumnsArray = new String[pkColumnList.size()];
            pkColumns = pkColumnList.toArray(pkColumnsArray);

            pkProperty = pkColumns.length == 1 ? lastPkProperty : null;
            statements = new TableStatements(db, tablename, allColumns, pkColumns);

            if (pkProperty != null) {
                Class<?> type = pkProperty.type;
                keyIsNumeric = type.equals(long.class) || type.equals(Long.class) || type.equals(int.class)
                        || type.equals(Integer.class) || type.equals(short.class) || type.equals(Short.class)
                        || type.equals(byte.class) || type.equals(Byte.class);
            } else {
                keyIsNumeric = false;
            }

        } catch (Exception e) {
            throw new DaoException("Could not init DAOConfig", e);
        }
    }

这个方法就是完成DaoConfig的配置的,通过反射机制,获取到我们的Dao类,比如说PersonClass,具体的代码大家去看,就是通过反射,很好理解。注意statements是TableStatements类型的。

继续,newSession();

public DaoSession newSession() {
        return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
    }
public DaoSession(SQLiteDatabase db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
            daoConfigMap) {
        super(db);

        personDaoConfig = daoConfigMap.get(PersonDao.class).clone();
        personDaoConfig.initIdentityScope(type);

        peopleDaoConfig = daoConfigMap.get(PeopleDao.class).clone();
        peopleDaoConfig.initIdentityScope(type);

        idCardDaoConfig = daoConfigMap.get(IdCardDao.class).clone();
        idCardDaoConfig.initIdentityScope(type);

        orderDaoConfig = daoConfigMap.get(OrderDao.class).clone();
        orderDaoConfig.initIdentityScope(type);

        courseDaoConfig = daoConfigMap.get(CourseDao.class).clone();
        courseDaoConfig.initIdentityScope(type);

        personDao = new PersonDao(personDaoConfig, this);
        peopleDao = new PeopleDao(peopleDaoConfig, this);
        idCardDao = new IdCardDao(idCardDaoConfig, this);
        orderDao = new OrderDao(orderDaoConfig, this);
        courseDao = new CourseDao(courseDaoConfig, this);

        registerDao(Person.class, personDao);
        registerDao(People.class, peopleDao);
        registerDao(IdCard.class, idCardDao);
        registerDao(Order.class, orderDao);
        registerDao(Course.class, courseDao);
    }
public void initIdentityScope(IdentityScopeType type) {
        if (type == IdentityScopeType.None) {
            identityScope = null;
        } else if (type == IdentityScopeType.Session) {
            if (keyIsNumeric) {
                identityScope = new IdentityScopeLong();
            } else {
                identityScope = new IdentityScopeObject();
            }
        } else {
            throw new IllegalArgumentException("Unsupported type: " + type);
        }
    }

这个函数就是判断,类型范围的。一般我们不需要管。看到在DaoSession的构造函数中,根据在DaoMaster初始化的config,经过范围类型判断,在DaoSession中也初始化了。至此,初始化过程完毕。

  • CURD过程 我们以insert为例
dao.insert(person);

dao对象是我们初始化后得到的,person是一个Person实体对象。

public long insert(T entity) {
        return executeInsert(entity, statements.getInsertStatement());
    }

上面的一段代码是AbstractDao类,这是一个抽象类,我们的Persondao就是继承的他。

statements.getInsertStatement()

通过statments对象实例获取SQLiteStatement对象,在(TableStatements类中)

public SQLiteStatement getInsertStatement() {
        if (insertStatement == null) {
            String sql = SqlUtils.createSqlInsert("INSERT INTO ", tablename, allColumns);
            insertStatement = db.compileStatement(sql);
        }
        return insertStatement;
    }

这样我们就获取到了一个SQLiteStatement对象。继续,看插入数据的过程。

private long executeInsert(T entity, SQLiteStatement stmt) {
        long rowId;
        if (db.isDbLockedByCurrentThread()) {
            synchronized (stmt) {
                bindValues(stmt, entity);
                rowId = stmt.executeInsert();
            }
        } else {
            // Do TX to acquire a connection before locking the stmt to avoid deadlocks
            db.beginTransaction();
            try {
                synchronized (stmt) {
                    bindValues(stmt, entity);
                    rowId = stmt.executeInsert();
                }
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
        }
        updateKeyAfterInsertAndAttach(entity, rowId, true);
        return rowId;
    }

看到上面会判断是否在当前线程,不在的话会开启事务。总之,还是很安全的。就这么多吧,更多的源码还是大家自己看吧。真的感觉这个牛,坐等更新+上数据库更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值