Android ORM数据库框架之-greenDao(四)
最后更新于:2022-04-01 15:49:11
本篇是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;
}
~~~
看到上面会判断是否在当前线程,不在的话会开启事务。总之,还是很安全的。就这么多吧,更多的源码还是大家自己看吧。真的感觉这个牛,坐等更新+上数据库更新