Android多线程操作sqlite数据库连接池框架的一种设计思路
来源:互联网 发布:淘宝卡dnf称号 编辑:程序博客网 时间:2024/04/30 08:58
我们在Android应用程序开发当中经常会用到数据库,一般在有两种主要开发思路。
第一种:每次需要对数据库操作的时候建立连接,操作完成后,马上关闭连接。
这个方式一般用于不怎么频繁操作数据库的情况,用完后马上关闭达到节省系统资源的目的。
第二种:应用程序一启动或在第一次使用数据库建立连接后,就始终保持数据库的连接而不关闭,知道退出该应用程序 。
这个方式一般常用频繁操作数据库,因为频繁的打开关闭数据库会影响程序的性能。
我们这博客主要是介绍第二种设计思路,即Sqlite数据库连接池的设计方案。
1》继承SQLiteOpenHelper类,实现它的相关重写方法,伪代码如下
public class XxxHelper extends SQLiteOpenHelper{ public void onCreate(SQLiteDatabase db) { } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
2》定义一个封装类,用于维护SQLiteDatabase对象和其对数据库的所有操作(增,删,改,查等),伪代码如下:
public class XxxSQLiteDatabase{ private SQLiteDatabase mSQLiteDatabase = null; private XxxHelper mDatabaseHelper = null; public SQLiteDatabase openDatabase(){ mSQLiteDatabase = mDatabaseHelper.getReadableDatabase(); return mSQLiteDatabase; } public void insert(){} public void query(){} public void updat(){} public void delete(){}}
3》定义数据库连接池类,也是最关键的一个类,代码如下:
public class XxxSQLiteDatabasePool{ private int initialSQLiteDatabase = 2; // 连接池的初始大小 private int incrementalSQLiteDatabase = 2;// 连接池自动增加的大小 private int maxSQLiteDatabase = 10; // 连接池最大的大小 private Vector<PooledSQLiteDatabase> pSQLiteDatabases = null; // 存放连接池中数据库连接的向量 public static TASQLiteDatabasePool getInstance() { return mSQLiteDatabasePool; } public synchronized void createPool() { // 确保连接池没有创建 // 如果连接池己经创建了,保存连接的向量 sqLiteDatabases 不会为空 if (pSQLiteDatabases != null) { return; // 如果己经创建,则返回 } // 创建保存连接的向量 , 初始时有 0 个元素 pSQLiteDatabases = new Vector<PooledSQLiteDatabase>(); // 根据 initialConnections 中设置的值,创建连接。 createSQLiteDatabase(this.initialSQLiteDatabase); } private void createSQLiteDatabase(int numSQLiteDatabase) { // 循环创建指定数目的数据库连接 for (int x = 0; x < numSQLiteDatabase; x++) { // 是否连接池中的数据库连接的数量己经达到最大?最大值由类成员 maxSQLiteDatabase // 指出,如果 maxSQLiteDatabase 为 0 或负数,表示连接数量没有限制。 // 如果连接数己经达到最大,即退出。 if (this.maxSQLiteDatabase > 0 && this.pSQLiteDatabases.size() >= this.maxSQLiteDatabase) { break; } try { // 增加一个XxxSQLiteDatabase到连接池中 pSQLiteDatabases.addElement(new PooledSQLiteDatabase( newSQLiteDatabase())); } catch (Exception e) { } } } /** * 创建一个新的数据库连接并返回它 * * @return 返回一个新创建的数据库连接 */ private XxxSQLiteDatabase newSQLiteDatabase() { // 创建一个数据库连接 XxxSQLiteDatabase sqliteDatabase = new XxxSQLiteDatabase(context, params); sqliteDatabase.openDatabase(); return sqliteDatabase; // 返回创建的新的数据库连接 } /** * 通过调用 getFreeSQLiteDatabase() 函数返回一个可用的数据库连接 , * 如果当前没有可用的数据库连接,并且更多的数据库连接不能创 建(如连接池大小的限制),此函数等待一会再尝试获取。 * * @return 返回一个可用的数据库连接对象 */ public synchronized XxxSQLiteDatabase getSQLiteDatabase() { // 确保连接池己被创建 if (pSQLiteDatabases == null) { return null; // 连接池还没创建,则返回 null } XxxSQLiteDatabase sqliteDatabase = getFreeSQLiteDatabase(); // 获得一个可用的数据库连接 // 如果目前没有可以使用的连接,即所有的连接都在使用中 while (sqliteDatabase == null) { // 等一会再试 wait(250); sqliteDatabase = getFreeSQLiteDatabase(); // 重新再试,直到获得可用的连接,如果 // getFreeConnection() 返回的为 null // 则表明创建一批连接后也不可获得可用连接 } return sqliteDatabase;// 返回获得的可用的连接 } /** * 本函数从连接池向量 pSQLiteDatabases 中返回一个可用的的数据库连接,如果 当前没有可用的数据库连接,本函数则根据 * incrementalSQLiteDatabase 设置 的值创建几个数据库连接,并放入连接池中。 如果创建后,所有的连接仍都在使用中,则返回 * null * * @return 返回一个可用的数据库连接 */ private XxxSQLiteDatabase getFreeSQLiteDatabase() { // 从连接池中获得一个可用的数据库连接 XxxSQLiteDatabase sqLiteDatabase = findFreeSQLiteDatabase(); if (sqLiteDatabase == null) { // 如果目前连接池中没有可用的连接 // 创建一些连接 createSQLiteDatabase(incrementalSQLiteDatabase); // 重新从池中查找是否有可用连接 sqLiteDatabase = findFreeSQLiteDatabase(); if (sqLiteDatabase == null) { // 如果创建连接后仍获得不到可用的连接,则返回 null return null; } } return sqLiteDatabase; } /** * 查找连接池中所有的连接,查找一个可用的数据库连接, 如果没有可用的连接,返回 null * * @return 返回一个可用的数据库连接 */ private XxxSQLiteDatabase findFreeSQLiteDatabase() { XxxSQLiteDatabase sqliteDatabase = null; PooledSQLiteDatabase pSQLiteDatabase = null; // 获得连接池向量中所有的对象 Enumeration<PooledSQLiteDatabase> enumerate = pSQLiteDatabases .elements(); // 遍历所有的对象,看是否有可用的连接 while (enumerate.hasMoreElements()) { pSQLiteDatabase = (PooledSQLiteDatabase) enumerate.nextElement(); if (!pSQLiteDatabase.isBusy()) { // 如果此对象不忙,则获得它的数据库连接并把它设为忙 sqliteDatabase = pSQLiteDatabase.getSqliteDatabase(); pSQLiteDatabase.setBusy(true); // 测试此连接是否可用 if (!testSQLiteDatabase(sqliteDatabase)) { // 如果此连接不可再用了,则创建一个新的连接, // 并替换此不可用的连接对象,如果创建失败,返回 null sqliteDatabase = newSQLiteDatabase(); pSQLiteDatabase.setSqliteDatabase(sqliteDatabase); } break; // 己经找到一个可用的连接,退出 } } return sqliteDatabase;// 返回找到到的可用连接 }} /** * 此函数返回一个数据库连接到连接池中,并把此连接置为空闲。 所有使用连接池获得的数据库连接均应在不使用此连接时返回它。 * * @param 需返回到连接池中的连接对象 */ public void releaseSQLiteDatabase(TASQLiteDatabase sqLiteDatabase) { // 确保连接池存在,如果连接没有创建(不存在),直接返回 if (pSQLiteDatabases == null) { return; } PooledSQLiteDatabase pSqLiteDatabase = null; Enumeration<PooledSQLiteDatabase> enumerate = pSQLiteDatabases .elements(); // 遍历连接池中的所有连接,找到这个要返回的连接对象 while (enumerate.hasMoreElements()) { pSqLiteDatabase = (PooledSQLiteDatabase) enumerate.nextElement(); // 先找到连接池中的要返回的连接对象 if (sqLiteDatabase == pSqLiteDatabase.getSqliteDatabase()) { // 找到了 , 设置此连接为空闲状态 pSqLiteDatabase.setBusy(false); break; } } } /** * 内部使用的用于保存连接池中连接对象的类 此类中有两个成员,一个是数据库的连接,另一个是指示此连接是否 正在使用的标志。 */ class PooledSQLiteDatabase { XxxSQLiteDatabase sqliteDatabase = null;// 数据库连接 boolean busy = false; // 此连接是否正在使用的标志,默认没有正在使用 // 构造函数,根据一个 XxxSQLiteDatabase 构告一个 PooledSQLiteDatabase 对象 public PooledSQLiteDatabase(XxxSQLiteDatabase sqliteDatabase) { this.sqliteDatabase = sqliteDatabase; } // 返回此对象中的连接 public XxxSQLiteDatabase getSqliteDatabase() { return sqliteDatabase; } // 设置此对象的,连接 public void setSqliteDatabase(XxxSQLiteDatabase sqliteDatabase) { this.sqliteDatabase = sqliteDatabase; } // 获得对象连接是否忙 public boolean isBusy() { return busy; } // 设置对象的连接正在忙 public void setBusy(boolean busy) { this.busy = busy; } }}
为了解释下上面代码的思路,我们先来看看我们如何去调用这个数据库连接池的。
XxxSQLiteDatabasePool pool = TASQLiteDatabasePool.getInstance(); pool.createPool(); XxxSQLiteDatabase sqliteDatabase = pool.getSQLiteDatabase(); sqliteDatabase.insert(); pool.releaseSQLiteDatabase(sqliteDatabase);
1.连接池的结构,连接池主要由一个线程安全的vector集合实现,并指定该集合的最大连接数,也就是代码中的maxSQLiteDatabase成员变量。在调用createPool方法时,会初始化这个vecotr集合,并默认创建任意条连接。
2.获取数据库对象的过程,调用getSQLiteDatabase()方法去vector集合中获取数据库对象,如果当前集合中有未锁定的数据库对象,那简单了,直接取出使用就行,并给该数据库对象加锁,以防止其他线程使用该连接对象。如果当前集合中的数据库对象都已锁定的话,首先判断集合中的对象有没有超过最大连接数 ,没超过则重新生成一个连接对象,超过最大连接数的话,就线程等待,直到其他线程释放数据库连接对象。
至此,设计的思路完成
扩展话题:
Sqlite3数据库目前之支持一个线程同一时间对它的写,读可以多线程同时进行。这样就会引发一个问题,如果出现2条以上的线程对数据库的同时写操作,系统就会抛出异常 “database is locked“。
碰到这种问题,怎么解决呢?
目前我所知道的方式只能做到规避不能彻底解决这个问题。如果你的应用程序只是对数据库的读操作频繁,写不是太频繁,这个你可以将最大连接数设置大于1。
如果你的程序存在多线程频繁的写数据库的操作时,将最大连接书设置1,这样的目的很明显,就是当一条线程在写数据库时,其他线程只能等待,当写完释放连接后,才能继续访问数据库
- Android多线程操作sqlite数据库连接池框架的一种设计思路
- 操作配置文件的一种设计思路
- 一种数据库连接池的设计与实现
- Qt+SQLite数据加密的一种思路
- 简单的Android SQLite应用设计框架
- 设计框架的思路
- 数据库连接池的设计思路及java实现
- 数据库连接池的设计思路及java实现 .
- 一种Web UI 的代码设计思路
- 一种值得借鉴的设计思路
- 一种API代码结构的设计思路
- Android 开源框架Universal-Image-Loader的设计思路
- 又一种设计思路
- Android原生SQLite操作以及greenDao框架操作SQLite
- Android sqlite数据库连接池连接异常分析
- android用jdbc多线程操作sqlite小结
- android关于多线程操作sqlite知识点
- 关于Sqlite数据库连接Android
- iOS runtime的应用实例
- HDU3062
- hibernate+oracle+servlet实现插入数据的时候,不立马显示!!
- 448. Find All Numbers Disappeared in an Array
- POJ 2456 Aggressive cows
- Android多线程操作sqlite数据库连接池框架的一种设计思路
- 设计模式笔记二十一:状态模式
- PAT A1113 integer set partition (25)
- Java 内存区域与内存溢出异常
- 18_使用canvas元素
- VUWE——又一个移动端Vue2组件库
- 19_使用canvas元素
- Java集合框架(上)
- 20_使用拖放