Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 1343|回复: 0

代码:Android笔记 SQLite总结 ,字带数据库,附记事本,字典小

[复制链接]

该用户从未签到

发表于 2011-10-23 19:47:44 | 显示全部楼层 |阅读模式
SELECT password FROM user_accounts WHERE username = 'John';
复制代码SQLite Database
SQLite is an embedded relational database engine. Its developers call it a self-contained, serverless, zero-configuration and transactional SQL database engine. 其实只需要记住SQLite不需要数据库服务器,不需要额外配置,其数据库本身就是一个文件的一个小型数据库。 通常情况下在android中创建数据库,系统会在"DATA/data/APP_NAME/databases".目录为我们创建数据库文件。
SQLite BasicDataTypes
SQLite支持的数据类型有很多,但他们总共可以分为以下几类:
desc <table> //查看表结构

select * from <table> //查询所有更

select , from table ;//查看指定列

select distinct , from table ;//非重复查询

insert into users(_id,username,password) select * from users;//复制

select username from users where username like 'S%' ;//非重名字首字母为大写S的用户

select username from users where username like '__S%' ;//非重名字第三个字母为大写S的用户

select * from users where _id in(001,220,230);

select * from user order by _id;//以id的顺序排列

select * from user order by _id desc;//以id反的顺序排
复制代码
常用Select语句 desc <table> //查看表结构

select * from <table> //查询所有更

select , from table ;//查看指定列

select distinct , from table ;//非重复查询

insert into users(_id,username,password) select * from users;//复制

select username from users where username like 'S%' ;//非重名字首字母为大写S的用户

select username from users where username like '__S%' ;//非重名字第三个字母为大写S的用户

select * from users where _id in(001,220,230);

select * from user order by _id;//以id的顺序排列

select * from user order by _id desc;//以id反的顺序排
复制代码
图形环境
很少有人直接在程序当中直接编写SQL语句,麻烦且容易出错。所以最好应该先在一个图形化的环境把SQL语句写好,测试好再加入到代码当中。 而且,SQLite数据库本身就是一个独立的文件,很容易从模拟器上抓取出来。可以使用图形化界面进行分析,和修改 etc.
SQLite expert 是个简单小巧的SQLite数据库管理软件,有免费版和,收费版两种,一般来讲免费版足以应付我们需求。
sqliteexpert官方网址
软件界面截图

使用SQLite expert 创建一张table,并让它为我们生成所需的sql语句
下面的例子,我们创建一张表用来存储用户的用户名和密码;数据库名"users",表名"user_accounts",有三个列:row_id INTEGER自增类型的主键,usernameTEXT类型 用来保存用户名,passwordTEXT类型,用来保存用户密码;
创建表格
为了创建一张table 首先要有一个数据库文件,点击"File"->""New Database然后选择文件的路径,点击OK便创建了一个数据库文件 创建完数据库之后创建表格,右击数据库文件名选择"New Table"如下图所示:


这时我们便进入了"设计状态",填写表名(user_accounts),点击"Add",在Name中填写"row_id",Type选择Integer,如下图所示:

因为row_id这个列比较特殊是我们的索引的主键,所以还要点击"Index",之后会看到下图:

左边的Available Fields 中有我们刚刚创建的row_id,点击"Add"把row_id加入右边的Index Fields当中。这时上面的Primary和AutoIncrement会变成可先状态 ,勾选Primary和AutoIncrement点击OK;

再回到Field当中创建其它两列,分别为username类型为TEXT,password类型也为TEXT,但不需要创建Index; 完成之后点击Apply,这样我们便使用SQLite expert创建一张表格,点击DDL,我们可以看到SQLite expert已经为我们生成好了生成这张表格所需的SQL语句:

在android中需要代码生成表格时,只要把这段代码复制过去,就可以了。
增加用户
点击SQL,执行以下SQL语句,为表格增加一个用户:
INSERT INTO user_accounts(row_id,username,password) VALUES(001,'John','abcdef');
复制代码

点击Data会发现数据库里边增加了一个用户名为John的用户。为了练习,我们不妨再增加两个用户,David和Sarah
INSERT INTO user_accounts(row_id,username,password) VALUES(002,'David','123456');



INSERT INTO user_accounts(row_id,username,password) VALUES(003,'Sarah','00000000');
复制代码删除用户
执行下面的语句删除用户David:
DELETE FROM user_accounts WHERE username = 'David';
复制代码修改密码
执行以下语句修改Sarah的密码:
update user_accounts SET password='666666' WHERE username = 'Sarah';
复制代码查看所用户信息可以使用如下语句查看表内所有用户的信息: SELECT * FROMM user_accounts;
复制代码
一般来讲select * 的语句只在测试的时候时候,在正式代码中不推荐使用。
查看指定列的内容执行以下语句查看所有用户的用户名和密码: SELECT username,password FROM user_accounts;
复制代码
这时个就发现row_id列没有显示出来。
查询特定条件的信息
SQL可以通过给定查询条件进行精确查找,比如我们只需要John的密码。就可以使用这样的语句
SELECT password FROM user_accounts WHERE username = 'John';
复制代码
以下流程图,来源于SQLite官方文档
Create Table Statement

column-def

type-name

column-constraint

table-constraint

foriegn-key-clause

Insert Statement

Delete Statement

qualified-table-name

Update Statement

qualified-table-name

Select Statement

select-core

result-column

join-source

single-source

join-op

join-constraint

ordering-term

compound-operator

Dealing with large amount of data分页当数据库数据量很大时,分页显示是个很简单且符合人们习惯的一种处理方法。
获取数据行总数:
最简单的方法是:SELECT所有的行,再调用curosr.getCount() ;取得行数,但这样效率会很低。 SQLite为我们提供了一个函数很容易查出总共有多少行。有个名为cet6_table的表格,我们想知道总共有多少行的word;可以使用如下 语句来完成:
SELECT count(word) AS number FROM cet6_table;
复制代码


count()函数为我们返回一个Int整形,代表有多少行数据。返回的列的名字叫count(word),为了方便阅读和处理用as number给这个列取个 别名number;
SELECT [word],[explanation] FROM cet6_table ORDER BY word LIMIT 100 OFFSET 200"
复制代码
上语句,返回自第200行的最多100条数据。分页时我们只要修改offset 后面的数据即可取得对应页面的数据。
详情见示例程序!
多线程自带数据库
有些程序比如,字典,输入法等程序会在apk中带有数据库。思路很简单,把预先准备好的数据库放入asset或者raw目录当中 使用时复制到对应的手机目录上;再打开。以下代码会把raw目录中的名为cet6的数据库文件写入sd卡根目录并打开。 对于一些常用或者比较重要的数据建议放在程序的私有目录当中。
public void init(Context context) {

    try {

        String databasePath = Environment.getExternalStorageDirectory().getAbsolutePath();

        String databaseFilename = databasePath + "/" + DATABASE_FILENAME;

        File dir = new File(databasePath);

        if (!dir.exists()){

            dir.mkdir();

        }

        if (!(new File(databaseFilename)).exists()) {

            InputStream is = context.getResources().openRawResource(

                    R.raw.cet6);

            FileOutputStream fos = new FileOutputStream(databaseFilename);

            byte[] buffer = new byte[1024];

            int count = 0;

            while ((count = is.read(buffer)) > 0) {

                fos.write(buffer, 0, count);

            }

            fos.flush();

            fos.close();

            is.close();

        }

        mCet6Db = SQLiteDatabase.openOrCreateDatabase(databaseFilename,

                null);

    } catch (Exception e) {

        e.printStackTrace();

    }

}
复制代码单词提示,IME使用AutoCompleteText + SQLite很容易实现类似于baidu ,Google等搜索时出现的提示文字。 输入法也是同样的原理,以拼音或五笔等作为索引,非常容易实现。可以加一个列标明一个字被选择的次数, 在select的时候可以按照这个列来排序,这样可以保存用户的习惯;作出来的输入法将更人性化。因为输入法的查询量比较大 可以考虑把数据库文件放入内存当中,SQLite本身是支持内存数据库的。但android中封装上没有提供这一功能,而且SQLiteDataBase类 很多核心功能都是通过JNI实现的,所以要把数据库搬入内存还需编写c/c++的代码。也可以考虑使用Lucene的全文搜索功能来实现。Date
SQLite有很多函数支持日期的方便处理。
%d         day of month: 00

%f         fractional seconds: SS.SSS

%H         hour: 00-24

%j         day of year: 001-366

%J         Julian day number

%m         month: 01-12

%M         minute: 00-59

%s         seconds since 1970-01-01

%S         seconds: 00-59

%w         day of week 0-6 with Sunday==0

%W         week of year: 00-53

%Y         year: 0000-9999

%%         %
复制代码
SQLite支持以下格式的日期:
YYYY-MM-DD

YYYY-MM-DD HH:MM

YYYY-MM-DD HH:MM:SS

YYYY-MM-DD HH:MM:SS.SSS

YYYY-MM-DDTHH:MM   //T 就是字母T,用于分开日期和时间

YYYY-MM-DDTHH:MM:SS

YYYY-MM-DDTHH:MM:SS.SSS

HH:MM

HH:MM:SS

HH:MM:SS.SSS

now

DDDDDDDDDD //is the Julian day number expressed as a floating point value.
复制代码
strftime('%Y-%m-%d', column_name)方法可以很方便的对日期进行格式化,而不用java对String进行再处理。
ContentValues 不支持直接把datetime('now')之类函数作为值插入数据库。 比如想把当前系统时间插件数据库使用ContentValues:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

Date date = new Date();

ContentValues initialValues = new ContentValues();

initialValues.put("date_created", dateFormat.format(date));

long rowId = mDb.insert(DATABASE_TABLE, null, initialValues);
复制代码
或者如附带程序记事本程序一样使用exeSQL(sql);
SqliteOpenHelper

上流程图来自O'REILLY 视频公开课"Developing Android Applications with Java"中的视频截图
SqliteOpenHelper是android框架为我们提供的一个数据库助手类。对于数据库的操作一般都是从这个类继承。它主要负责数据库的创建,打开,更新 等一些操作。
Singleton DAO
很多有j2ee背景的开发者都喜欢建立一个单例模式的数据库操作类,专门处理数据库之间的交流。也有很多人把这个习惯带到的Android的开发当中。 而且我们也经常需要在几个Activity,Service同时访问一个数据库文件,所以经常能看到类似于这样的代码:
public class DbAccess {



    class DbHelper extends SQLiteOpenHelper {

    //此处代码被省略

    }

    private static DB_NAME = "users";

    private mDbHelper = null;

    private static mDbAccess;//to make sure there is only one instance exist;

   

    private DbAccess(Context context){

        //private constructer;

        if(mDbHelper == null){

            mDbHelper = new DbHelper(context,DB_NAME);

        }

    }

   

    public DbAccess getInstance(Context context){

        if(mDbAccess == null){

            mDbAccess = new DbAccess(context);

        }

        return mDbAccess;

    }

   

    //部分代码被省略

    //insert

    //delete

    //update

    //query

}



public class ActivityA extends Activity{

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        dao = DbAccess.getInstance(this);

        ////部分代码被省略

    }

    ////部分代码被省略

}
复制代码
程序的流程应该是这样的:

假设ActivityA创建了Dao的对象,又开启了ServiceA,A使用了一段时间再跳转到了ActivityB与B再接着使用同一个Dao对象。ActivityA创建Dao对象的时候 把自己的引用向上转型成一个Context对象,Dao又用这个context创建了SQLiteOpenHelper,所以SQLiteOpenHelper就持有了ActivityA的引用。当ActivityA被销毁 之后因为单例的Dao保留有ActivityA的引用,所以ActivityA不能被GC所回收,造成整个Acitivity内存的泄漏。
解决方案
1,最简单的,不使用单例模式,因为SQLiteOpenHelper保证了数据库的单例,所以实际上我们只是创建了多个SQLiteOpenHelper的对象,数据库 对象本身还是单例的。缺点:会有一些重复的代码,并生成多个SQLiteOpenHelper的子类对象。
2,把Dao对象放入Application当中,在Application的onCreate()中使用Application的Context进行初始化。优点,Application对象的创建在Activity和Service之前 所以保证了,Activity和Service等等使用时数据库已经准备好了。缺点:Application的生命周期是最长的,并且Android会尽量不让程序关闭,也就是尽量不 去销毁Application对象,所以数据库一直保持打开状态,依靠Application的onDestroy()关闭数据库,不确定的因素比较大,并且因为打开数据库的时候直接 影响程序启动时间。
3,先看一个问题,为什么SQLiteOpenHelper需要一个Context对象?查看SQLiteOpenHelper的源码发现如下代码:
SQLiteDatabase db = null;

try {

    mIsInitializing = true;

    String path = mContext.getDatabasePath(mName).getPath();

    db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);

    if (db.getVersion() != mNewVersion) {

        throw new SQLiteException("Can't upgrade read-only database from version " +

        db.getVersion() + " to " + mNewVersion + ": " + path);

    }

    onOpen(db);

    Log.w(TAG, "Opened " + mName + " in read-only mode");

    mDatabase = db;
复制代码
所以我们可以自己仿照SQLiteOpenHelper写一个不需要Context的助手类,大constructer当中把路径传进行,而不是一个context对象。缺点:需要考虑多线程同步等 很多因素,有一定的复杂度。
4,在创建Dao对象时,不使用Activity的引用作为Context,而是把Application作为Context传入Dao的构造函数中进行创建。优点,不会影响程序的启动时间。 缺点:对于数据库的关闭还是不确定。
5,在第四种方案的基础上加入计数器。第调用getInstance计数器自增,再加入一个release()方法,计数器自减,当计数器为0时,关闭数据库(或者当计数器为零且 过一段时间没有连接时关闭)。
Snippets
如果有什么疑问,发现bug或者有更好的想法或者建议,或者附件无法下载。请发邮件至arthurbrown@163.com
1,记事本,简单CRUID练习,以及日期处理。

2,分页显示和简单六级词汇查询(数据库来自"百度文库" )




ListViewSnippets.zip (124.35 KB, 下载次数: 29)
回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2011-10-23 19:47:54 | 显示全部楼层

Re:代码:Android笔记

恩, 很好的教程, 学习加收藏了
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-23 19:48:07 | 显示全部楼层

Re:代码:Android笔记

恩, 很好的教程, 学习加收藏了
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-23 19:48:15 | 显示全部楼层

Re:代码:Android笔记

回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-23 19:48:26 | 显示全部楼层

Re:代码:Android笔记

学习了。。。。收藏~
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-23 19:48:33 | 显示全部楼层

Re:代码:Android笔记

谢谢啦,很有用!













江油论坛群发
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-23 19:48:42 | 显示全部楼层

Re:代码:Android笔记

谢谢分享,虽然看不懂
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-23 19:48:49 | 显示全部楼层

Re:代码:Android笔记

谢谢分析
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-23 19:49:04 | 显示全部楼层

Re:代码:Android笔记

谢谢分析,谢谢了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-10 18:09 , Processed in 0.418814 second(s), 49 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表