android Xutils 数据库操作源码分析

本文详细解析了XUtils中数据库操作的过程,从初始化配置到执行SQL查询和插入操作,包括数据库连接池管理、表结构检查及创建、事务处理等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

XUtils下载地址 http://www.oschina.net/p/xutils


以下是对demo的分析


进入DbFragment


首先看到的是

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. DbManager.DaoConfig daoConfig = new DbManager.DaoConfig()  
  2.            .setDbName("test")  
  3.            .setDbDir(new File("/sdcard")) // "sdcard"的写法并非最佳实践, 这里为了简单, 先这样写了.  
  4.            .setDbVersion(2)  
  5.            .setDbUpgradeListener(new DbManager.DbUpgradeListener() {  
  6.                @Override  
  7.                public void onUpgrade(DbManager db, int oldVersion, int newVersion) {  
  8.                    // TODO: ...  
  9.                    // db.addColumn(...);  
  10.                    // db.dropTable(...);  
  11.                    // ...  
  12.                }  
  13.            });  

此代码大致写了关于数据库名称、版本、路径以及更新操作


所以可以进入 new DbManager.DaoConfig() 中去查看具体信息

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <pre name="code" class="java">public interface DbManager extends Closeable   
数据库接口访问 此接口定义了关于数据增、删、查、改、版本相关操作

 

DbManager中的内部类定义了相关数据库配置、更新信息

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static class DaoConfig {  
  2.       private File dbDir;  
  3.       private String dbName = "xUtils.db"// default db name  
  4.       private int dbVersion = 1;  
  5.       private boolean allowTransaction = true;  
  6.       private DbUpgradeListener dbUpgradeListener;  
  7.       private TableCreateListener tableCreateListener;  

此处注意对象的==与equals的不同

DaoConfig包含如下代码

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public boolean equals(Object o) {  
  3.     if (this == o) return true;  
  4.     if (o == null || getClass() != o.getClass()) return false;  
  5.   
  6.     DaoConfig daoConfig = (DaoConfig) o;  
  7.   
  8.     if (!dbName.equals(daoConfig.dbName)) return false;  
  9.     return dbDir == null ? daoConfig.dbDir == null : dbDir.equals(daoConfig.dbDir);  
  10. }  
  11.   
  12. @Override  
  13. public int hashCode() {  
  14.     int result = dbName.hashCode();  
  15.     result = 31 * result + (dbDir != null ? dbDir.hashCode() : 0);  
  16.     return result;  
  17. }  

接口分析大致结束


然后回到DbFragment查看数据库具体操作

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void onTestDbClick(View view) {  
  2.   
  3.      // 一对多: (本示例的代码)  
  4.      // 自己在多的一方(child)保存另一方的(parentId), 查找的时候用parentId查parent或child.  
  5.      // 一对一:  
  6.      // 在任何一边保存另一边的Id并加上唯一属性: @Column(name = "parentId", property = "UNIQUE")  
  7.      // 多对多:  
  8.      // 再建一个关联表, 保存两边的id. 查询分两步: 先查关联表得到id, 再查对应表的属性.  
  9.   
  10.      String temp = "";  
  11.   
  12.      try {  
  13.   
  14.          DbManager db = x.getDb(daoConfig);  

此处真正的调用了数据库然后进入org.xutils.x;去查看具体实现

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Created by wyouflf on 15/6/10. 
  3.  * 任务控制中心, http, image, db, view注入等接口的入口. 
  4.  * 需要在在application的onCreate中初始化: x.Ext.init(this); 
  5.  */  
  6. public final class x {  
  7.   
  8.     private x() {  
  9.     }  

此处可以看出是所有模块的封装类



[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static DbManager getDb(DbManager.DaoConfig daoConfig) {  
  2.      return DbManagerImpl.getInstance(daoConfig);  
  3.  }  

此处可以看到DbManagerImpl类


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public final class DbManagerImpl implements DbManager {  
  2.   
  3.     //*************************************** create instance ****************************************************  
  4.   
  5.     /**  
  6.      * key: dbName  
  7.      */  
  8.     private static HashMap<DaoConfig, DbManagerImpl> daoMap = new HashMap<DaoConfig, DbManagerImpl>();  
  9.   
  10.     private SQLiteDatabase database;  
  11.     private DaoConfig daoConfig;  
  12.     private boolean allowTransaction;  
  13.   
  14.     private DbManagerImpl(DaoConfig config) {  
  15.         if (config == null) {  
  16.             throw new IllegalArgumentException("daoConfig may not be null");  
  17.         }  
  18.         this.database = createDatabase(config);  
  19.         this.daoConfig = config;  
  20.         this.allowTransaction = config.isAllowTransaction();  
  21.     }  
  22.   
  23.     public synchronized static DbManager getInstance(DaoConfig daoConfig) {  
  24.   
  25.         if (daoConfig == null) {//使用默认配置  
  26.             daoConfig = new DaoConfig();  
  27.         }  
  28.   
  29.         DbManagerImpl dao = daoMap.get(daoConfig);  
  30.         if (dao == null) {  
  31.             dao = new DbManagerImpl(daoConfig);  
  32.             daoMap.put(daoConfig, dao);  
  33.         } else {  
  34.             dao.daoConfig = daoConfig;  
  35.         }  
  36.   
  37.         // update the database if needed  
  38.         SQLiteDatabase database = dao.database;  
  39.         int oldVersion = database.getVersion();  
  40.         int newVersion = daoConfig.getDbVersion();  
  41.         if (oldVersion != newVersion) {  
  42.             if (oldVersion != 0) {  
  43.                 DbUpgradeListener upgradeListener = daoConfig.getDbUpgradeListener();  
  44.                 if (upgradeListener != null) {  
  45.                     upgradeListener.onUpgrade(dao, oldVersion, newVersion);  
  46.                 } else {  
  47.                     try {  
  48.                         dao.dropDb();  
  49.                     } catch (DbException e) {  
  50.                         LogUtil.e(e.getMessage(), e);  
  51.                     }  
  52.                 }  
  53.             }  
  54.             database.setVersion(newVersion);  
  55.         }  
  56.   
  57.         return dao;  
  58.     }  

注意public final class DbManagerImpl 为final 并且private DbManagerImpl(DaoConfig config) 私有构造函数

上述代码创建了database 并保存到HashMap<DaoConfig, DbManagerImpl> daoMap = new HashMap<DaoConfig, DbManagerImpl>();


创建database代码

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private SQLiteDatabase createDatabase(DaoConfig config) {  
  2.        SQLiteDatabase result = null;  
  3.   
  4.        File dbDir = config.getDbDir();  
  5.        if (dbDir != null && (dbDir.exists() || dbDir.mkdirs())) {  
  6.            File dbFile = new File(dbDir, config.getDbName());  
  7.            result = SQLiteDatabase.openOrCreateDatabase(dbFile, null);  
  8.        } else {  
  9.            result = x.app().openOrCreateDatabase(config.getDbName(), 0null);  
  10.        }  
  11.        return result;  
  12.    }  

如果数据库路径不存在那么使用默认路径并但会database


返回DbFragment继续往下走

看到关于数据库表的操作

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Parent test = db.selector(Parent.class).where("id""in"new int[]{136}).findFirst();  


关于

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public final class Selector<T> 与  public class WhereBuilder    
  2. db.selector(Parent.class).where("id""in"new int[]{136})  产生sql语句  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. </pre>此处代码是为了封装sql数据<p>一下是具体分析</p><p></p><pre name="code" class="java"@Override  
  2.     public <T> Selector<T> selector(Class<T> entityType) throws DbException {  
  3.         return Selector.from(TableEntity.get(this, entityType));  
  4.     }  


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public final class TableEntity<T> {  
  2.   
  3.     private final DbManager db;  
  4.     private final String name;  
  5.     private final String onCreated;  
  6.     private ColumnEntity id;  
  7.     private Class<T> entityType;  
  8.     private Constructor<T> constructor;  
  9.   
  10.     /** 
  11.      * key: columnName 
  12.      */  
  13.     private final LinkedHashMap<String, ColumnEntity> columnMap;  
  14.   
  15.     /** 
  16.      * key: dbName#className 
  17.      */  
  18.     private static final HashMap<String, TableEntity<?>> tableMap = new HashMap<String, TableEntity<?>>();  
tableEntity对表结构和是否存在实现封装

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class WhereBuilder  
对sql语句的封装


最后执行findFirst

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public T findFirst() throws DbException {  
  2.     if (!table.tableIsExist()) return null;  
  3.   
  4.     this.limit(1);  
  5.     Cursor cursor = table.getDb().execQuery(this.toString());  
  6.     if (cursor != null) {  
  7.         try {  
  8.             if (cursor.moveToNext()) {  
  9.                 return CursorUtils.getEntity(table, cursor);  
  10.             }  
  11.         } catch (Throwable e) {  
  12.             throw new DbException(e);  
  13.         } finally {  
  14.             IOUtil.closeQuietly(cursor);  
  15.         }  
  16.     }  
  17.     return null;  
  18. }  

到此第一个操作语句结束


接着往下看进入第二个与数据库操作有关的方法

db.save(parent);

进入DbManagerImpl实现代码

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.   public void save(Object entity) throws DbException {  
  3.       try {  
  4.           beginTransaction();  
  5.   
  6.           if (entity instanceof List) {  
  7.               List<?> entities = (List<?>) entity;  
  8.               if (entities.isEmpty()) return;  
  9.               TableEntity<?> table = TableEntity.get(this, entities.get(0).getClass());  
  10.               createTableIfNotExist(table);  
  11.               for (Object item : entities) {  
  12.                   execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(table, item));  
  13.               }  
  14.           } else {  
  15.               TableEntity<?> table = TableEntity.get(this, entity.getClass());  
  16.               createTableIfNotExist(table);  
  17.               execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(table, entity));  
  18.           }  
  19.   
  20.           setTransactionSuccessful();  
  21.       } finally {  
  22.           endTransaction();  
  23.       }  
  24.   }  

此方法首先开启了事务,然后判断传入的对象是否是集合再进行数据操作、此处运用了instanceof去判断是否是集合

此方法中调用了createTableIfNotExist(table)和execNonQuery(SqlInfoBuilder.buildInsertSqlInfo(table, entity))首先判断表是否存在然后进行数据库操作


关于异常的处理程序中直接向外层抛出未做处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值