关于android中数据库连接的问题

今天上午讨论的时候,提到数据库连接的问题。我今天调研了一下,然后分享一下。

第一个问题:如何创建数据库?
网上有两种说法,一种是调用openOrCreateDatabase来创建,一种是继承SQLiteOpenHelper,然后重写onCreate()方法,进行数据库创建。
哪种正确呢?都正确,只不过SQLiteOpenHelper中包含了openOrCreateDatabase(),即是对数据库创建以及获取连接的一个封装类。因此,对于程序员而言,应该使用帮助类,而不是直接使用更底层的方法。

第二个问题:getWritableDatabase与getReadableDatabase有啥区别?
这个从名字上看起来很混淆,下面是API的解释:

Create and/or open a database. This will be the same object returned by
{@link #getWritableDatabase} unless some problem, such as a full disk,
requires the database to be opened read-only. In that case, a read-only
database object will be returned. If the problem is fixed, a future call
to {@link #getWritableDatabase} may succeed, in which case the read-only
database object will be closed and the read/write object will be returned
in the future.
大体意思是,在一般情况下,这两个函数返回的是一个对象,只有当比如内存资源不足啊等情况下,getReadableDatabase会返回一个只读的数据库连接,而一旦问题修复,然后调用getWriteableDatabase时,会重新返回一个读写连接,而前面的只读连接将会关闭。一般情况下,可以放心大胆的用getWriteableDatabase。
不过API里面也提到,这个过程耗时比较长,应该放到一个单独线程中操作。

3、调用getWriteableDatabase之后,发生了什么?
当第一次调用这个函数时,会检查是否存在数据库连接,如果没有,就去创建一个数据库连接,然后将连接缓存起来,之后再调用这个函数的时候,会直接返回这个缓存的数据库连接。
举例来说,比如我实现了一个SQLiteOpenHelper类LocalDBHelper.
在客户端,调用helper = new LocalDBHelper(context);然后调用SQLiteDatabase database = helper.getWritableDatabase();这个是创建数据库连接的过程;那假如说某个线程或者多个线程调用helper.getWritableDatabase()那都无所谓,都是一个连接。

4、承接上一个问题,那怎样创建多个连接?
很简单,只要每次都new LocalDBHelper(context),即使传入的是同一个context,再调用getWritableDatabase时就会返回新的连接,跟上一个没有关系。

5、应该创建多个连接吗?
前面也说过,创建连接的过程是很慢的,如果频繁的创建连接会相当消耗资源,最糟糕的是,数据库一旦建立连接,就要维护这个连接,维护是有代价的。因此,在使用完毕之后要记得关闭连接,以免内存泄露。有点想C语言里面,每次new完之后,都要delete掉。而我们经常会忘记关闭连接。因此,如果能不关闭连接就好了。
这就产生了下面的问题。是用数据库连接池还是用单例模式?

6、数据库连接池 VS 单例模式
数据库连接池的产生是为了尽最大可能复用数据库连接,每次从数据库连接池中获取一个连接,每次用完之后,都将连接放回到连接池中。而连接是始终存在的。
单例模式是指这个程序运行期间只存在一个数据库连接,所有的操作都通过这个连接来完成。

我个人认为使用单例模式更好:
理由如下:
第一:简单
第二:网上有如下说法,

// Thread 1
Context context = getApplicationContext();
DatabaseHelper helper = new DatabaseHelper(context);
SQLiteDatabase database = helper.getWritableDatabase();
database.insert(…);
database.close();

// Thread 2
Context context = getApplicationContext();
DatabaseHelper helper = new DatabaseHelper(context);
SQLiteDatabase database = helper.getWritableDatabase();
database.insert(…);
database.close();

在你的logcat中将会得到下面的输出信息,并且有一个写操作将不会成功
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)

发生这种情况是因为你每次都创建了一个新的SQLiteOpenHelper,实际上你每次都创建了一个数据库的连接。如果你在同一时间用不同的数据库连接来对同一的数据库进行写操作的话,那么其中一个会失败。
第三:是我个人想法,未经证实。我总觉得对于数据库连接池而言,更多的场合是用在应用与数据库分离的情况,通过网络连接(耗时),这样当数据库满负荷运行时,多个网络连接可以同时传输更多的数据,但是这样对单机并没有什么效果。【个人想法,欢迎拍砖】

7、如果决定使用单例模式,如何使用?
首先,要使用数据库,需要找一个context,context的作用,我并不十分清楚,但是我觉得应该要有一个全局的context,最全局的莫过于应用的context。
所以,新建一个MyApplication extends Application,然后重写onCreate方法,赋值给一个静态的context属性,这样,就可以使用global application的context,这个context是无论如何不会被销毁的,除非是挂了。然后在DBManager里面就可以使用了。【注意,重写application之后,需要在AnroidManifest.xml文件中注册】

8、其他
理论上,这样就可以结束了,但是有网友说,一定要主动去关闭数据库连接,因为这也是API要求的。
但是如果有多个线程在使用这个连接,某个线程调用close,其他线程要获取连接,就会发生错误。
解决方案是:在DBManager中维护一个引用计数,即每次有请求获取连接时,引用计数+1,当关闭时,首先,引用计数-1,如果为0时,就关闭数据库。
这个解决方案应该说很巧妙。

但是我总觉得没有太大必要,应用关闭之后,自然的连接也就关闭了。所以,见仁见智把。

参考连接:
参考1
参考2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值