android 数据库的使用使用数据库

请问,android上的app是怎么连接服务器,操作数据库,获得数据的。
[问题点数:20分]
请问,android上的app是怎么连接服务器,操作数据库,获得数据的。
[问题点数:20分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2010年12月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第二
2011年4月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第三2011年3月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第三2010年11月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第三2010年10月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。当前访客身份:游客 [
当前位置:
Android 提供了三种数据存储方式,第一种是文件存储;第二种是SharedPreferences存储;第三种就是数据库SQLiteDatabase存储。文件存储我就不用多说了,而SharedPreferences可以存取简单的数据(int,double,float.etc),它经常用于数据缓存,因为它读取存储简单。详细可以参见本系列。Android高手进阶教程(七)之----Android 中Preferences的使用!
今天我们将讲一下SQLiteDatabase的使用。而掌握SqliteDatabase,将会我们接下来掌握ContentProvider打下良好的基石。为了让大家更好的掌握,我们手把手完成该节的Demo。
第一步:新建一个Android工程,命名为SQLiteDatabaseDemo.
第二步:创建一个新的类BooksDB.java这个类要继承于android.database.sqlite.SQLiteOpenHelper抽象类,我们要实现其中两个方法:onCreate(),onUpdate.具体代码如下:
package com.android.
import android.content.ContentV
import android.content.C
import android.database.C
import android.database.sqlite.SQLiteD
import android.database.sqlite.SQLiteOpenH
public class BooksDB extends SQLiteOpenHelper {
private final static String DATABASE_NAME = &BOOKS.db&;
private final static int DATABASE_VERSION = 1;
private final static String TABLE_NAME = &books_table&;
public final static String BOOK_ID = &book_id&;
public final static String BOOK_NAME = &book_name&;
public final static String BOOK_AUTHOR = &book_author&;
public BooksDB(Context context) {
// TODO Auto-generated constructor stub
super(context, DATABASE_NAME, null, DATABASE_VERSION);
//创建table
public void onCreate(SQLiteDatabase db) {
String sql = &CREATE TABLE & + TABLE_NAME + & (& + BOOK_ID
+ & INTEGER primary key autoincrement, & + BOOK_NAME + & text, &+ BOOK_AUTHOR +& text);&;
db.execSQL(sql);
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String sql = &DROP TABLE IF EXISTS & + TABLE_NAME;
db.execSQL(sql);
onCreate(db);
public Cursor select() {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db
.query(TABLE_NAME, null, null, null, null, null, null);
//增加操作
public long insert(String bookname,String author)
SQLiteDatabase db = this.getWritableDatabase();
/* ContentValues */
ContentValues cv = new ContentValues();
cv.put(BOOK_NAME, bookname);
cv.put(BOOK_AUTHOR, author);
long row = db.insert(TABLE_NAME, null, cv);
//删除操作
public void delete(int id)
SQLiteDatabase db = this.getWritableDatabase();
String where = BOOK_ID + & = ?&;
String[] whereValue ={ Integer.toString(id) };
db.delete(TABLE_NAME, where, whereValue);
//修改操作
public void update(int id, String bookname,String author)
SQLiteDatabase db = this.getWritableDatabase();
String where = BOOK_ID + & = ?&;
String[] whereValue = { Integer.toString(id) };
ContentValues cv = new ContentValues();
cv.put(BOOK_NAME, bookname);
cv.put(BOOK_AUTHOR, author);
db.update(TABLE_NAME, cv, where, whereValue);
第三步:修改main.xml布局如下,由两个EditText和一个ListView组成,代码如下:
&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout xmlns:android=&/apk/res/android&
android:orientation=&vertical&
android:layout_width=&fill_parent&
android:layout_height=&fill_parent&
android:id=&@+id/bookname&
android:layout_width=&fill_parent&
android:layout_height=&wrap_content&
&/EditText&
android:id=&@+id/author&
android:layout_width=&fill_parent&
android:layout_height=&wrap_content&
&/EditText&
android:id=&@+id/bookslist&
android:layout_width=&fill_parent&
android:layout_height=&wrap_content&
&/ListView&
&/LinearLayout&
第四步:修改SQLiteDatabaseDemo.java代码如下:
package com.android.
import android.app.A
import android.content.C
import android.database.C
import android.os.B
import android.view.M
import android.view.MenuI
import android.view.V
import android.view.ViewG
import android.widget.AdapterV
import android.widget.BaseA
import android.widget.EditT
import android.widget.ListV
import android.widget.TextV
import android.widget.T
public class SQLiteDatabaseDemo extends Activity implements AdapterView.OnItemClickListener {
private BooksDB mBooksDB;
private Cursor mC
private EditText BookN
private EditText BookA
private ListView BooksL
private int BOOK_ID = 0;
protected final static int MENU_ADD = Menu.FIRST;
protected final static int MENU_DELETE = Menu.FIRST + 1;
protected final static int MENU_UPDATE = Menu.FIRST + 2;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setUpViews();
public void setUpViews(){
mBooksDB = new BooksDB(this);
mCursor = mBooksDB.select();
BookName = (EditText)findViewById(R.id.bookname);
BookAuthor = (EditText)findViewById(R.id.author);
BooksList = (ListView)findViewById(R.id.bookslist);
BooksList.setAdapter(new BooksListAdapter(this, mCursor));
BooksList.setOnItemClickListener(this);
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(Menu.NONE, MENU_ADD, 0, &ADD&);
menu.add(Menu.NONE, MENU_DELETE, 0, &DELETE&);
menu.add(Menu.NONE, MENU_DELETE, 0, &UPDATE&);
public boolean onOptionsItemSelected(MenuItem item)
super.onOptionsItemSelected(item);
switch (item.getItemId())
case MENU_ADD:
case MENU_DELETE:
case MENU_UPDATE:
public void add(){
String bookname = BookName.getText().toString();
String author = BookAuthor.getText().toString();
//书名和作者都不能为空,或者退出
if (bookname.equals(&&) || author.equals(&&)){
mBooksDB.insert(bookname, author);
mCursor.requery();
BooksList.invalidateViews();
BookName.setText(&&);
BookAuthor.setText(&&);
Toast.makeText(this, &Add Successed!&, Toast.LENGTH_SHORT).show();
public void delete(){
if (BOOK_ID == 0) {
mBooksDB.delete(BOOK_ID);
mCursor.requery();
BooksList.invalidateViews();
BookName.setText(&&);
BookAuthor.setText(&&);
Toast.makeText(this, &Delete Successed!&, Toast.LENGTH_SHORT).show();
public void update(){
String bookname = BookName.getText().toString();
String author = BookAuthor.getText().toString();
//书名和作者都不能为空,或者退出
if (bookname.equals(&&) || author.equals(&&)){
mBooksDB.update(BOOK_ID, bookname, author);
mCursor.requery();
BooksList.invalidateViews();
BookName.setText(&&);
BookAuthor.setText(&&);
Toast.makeText(this, &Update Successed!&, Toast.LENGTH_SHORT).show();
public void onItemClick(AdapterView&?& parent, View view, int position, long id) {
mCursor.moveToPosition(position);
BOOK_ID = mCursor.getInt(0);
BookName.setText(mCursor.getString(1));
BookAuthor.setText(mCursor.getString(2));
public class BooksListAdapter extends BaseAdapter{
private Context mC
private Cursor mC
public BooksListAdapter(Context context,Cursor cursor) {
mContext =
public int getCount() {
return mCursor.getCount();
public Object getItem(int position) {
public long getItemId(int position) {
public View getView(int position, View convertView, ViewGroup parent) {
TextView mTextView = new TextView(mContext);
mCursor.moveToPosition(position);
mTextView.setText(mCursor.getString(1) + &___& + mCursor.getString(2));
return mTextV
第五步:运行程序效果如下:
第六步:查看我们所建的数据库。有两种方法:第一种用命令查看:adb shell ls data/data/com.android.tutor/databases。
另一种方法是用DDMS查看,在data/data下面对应的应用程序的包名 下会有如下数据库,如图所示:
共有17个评论
<span class="a_vote_num" id="a_vote_num_
<span class="a_vote_num" id="a_vote_num_
如何用自已外部创建的数据库?
--- 共有 1 条评论 ---
外部数据库,你指的是手机上的数据库吗,还是服务器的?
(4年前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
有图有源码~~这样的代码分享看着才舒服
<span class="a_vote_num" id="a_vote_num_
楼主,下面三个键都没显示啊,效果只有两个edittext啊
--- 共有 2 条评论 ---
: 按menu那里才有的
(3年前)&nbsp&
运行后,我也是这样的效果,只有上面两个EditText,下面三个都没有,listview也没显示
(3年前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
bjhgjhgjgjhghj
<span class="a_vote_num" id="a_vote_num_
学习中,mark先
<span class="a_vote_num" id="a_vote_num_
引用来自“西瓜可乐”的答案学习中,mark先好
<span class="a_vote_num" id="a_vote_num_
谢谢分享!!!
<span class="a_vote_num" id="a_vote_num_
新同学。。学习中。。。谢谢大师们分享啊
<span class="a_vote_num" id="a_vote_num_
好像有错误啊
更多开发者职位上
有什么技术问题吗?
阿酷的其它问题
类似的话题android数据库操作demo - 下载频道 - CSDN.NET
&&&&android数据库操作demo
&android数据库操作demo
SQLite基本操作小demo,包含了增删改查等操作,加入sql语句直接操作数据库
若举报审核通过,可奖励20下载分
被举报人:
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
您可能还需要
Q.为什么我点的下载下不了,但积分却被扣了
A. 由于下载人数众多,下载服务器做了并发的限制。若发现下载不了,请稍后再试,多次下载是不会重复扣分的。
Q.我的积分不多了,如何获取积分?
A. 获得积分,详细见。
完成任务获取积分。
评价资源返积分。
论坛可用分兑换下载积分。
第一次绑定手机,将获得5个C币,C币可。
下载资源意味着您已经同意遵守以下协议
资源的所有权益归上传用户所有
未经权益所有人同意,不得将资源中的内容挪作商业或盈利用途
CSDN下载频道仅提供交流平台,并不能对任何下载资源负责
下载资源中如有侵权或不适当内容,
本站不保证本站提供的资源的准确性,安全性和完整性,同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
移动开发下载排行
积分不够下载该资源
如何快速获得积分?
你下载资源过于频繁,请输入验证码
如何快速获得积分?
你已经下载过该资源,再次下载不需要扣除积分
android数据库操作demo
所需积分:0
剩余积分:
VIP会员,免积分下载
会员到期时间:日
剩余下载次数:1000
VIP服务公告:Android+Jquery Mobile学习系列(5)-SQLite数据库 - 上善若水任方圆 - ITeye技术网站
博客分类:
SQLite是轻量级的、嵌入式的、关系型数据库,目前已经在iPhone、Android等手机系统中使用,SQLite可移植性好,很容易使用,很小,高效而且可靠。
因为Android已经集成了SQLite,所以开发人员无需引入任何JAR包,而且Android也针对SQLite封装了专属的API,调用起来非常快捷方便。
我也是第一次接触SQLite,感受到它的一些不同之处,作为一门简易实用的数据库,它的学习周期其实蛮短的。对于懂关系型数据库的人来说,使用SQLite应该是得心应手的。
Android支持很多类型的存储方式,比如File文件、sharedPreference和数据库等,因为我做的应用涉及到频繁的更新操作,而且数据组成较为复杂,所以最终选择了SQLite数据库作为应用的存储方式。但是听有经验的开发人员说,在Android上使用数据文件存储极其不好,只要有ROOT权限就可以随意删除文件,所以如果你的应用属于商业性质,我推荐你做一个网络站点将数据存储于网络服务器上最好。
不需要配置,不需要安装,也不需要管理员。SQLite不需要安装任何数据库相关的服务器,一个完整的数据库保存在磁盘上面一个文件,要想用数据库工具查看SQLite只需要将它指向那个数据库文件即可!
源代码开放, 代码95%有较好的注释。
完美支持大部分的标准SQL语句。如果你懂得MYSql、Oracle等关系型数据的使用,那么用SQLite也是得心应手。
SQLite最大的特点是,数据表中的字段是无类型的,这意味着你可以保存任何类型的数据到你所想要保存的任何表的任何列中(除了integer Primary Key)。我的理解是:一张表上的主键必须指定数据类型,而且存储更新时,主键的数据类型一定要对应;而其它的字段全部都是无类型的,你可以存字符串,也可以存int整数。
所以在建表的时候你可以这样写:
CREATE TABLE IF NOT EXISTS user_info (id INTEGER PRIMARY KEY,name,sex)
除了主键外,其它字段均不用定义数据类型,即使定义了数据类型,SQLite也会忽略掉。
但是很多人还是建议带上数据类型,一来尽量让建表语句标准化便于迁移,二来让后面维护的开发人员理解每个字段到底是什么类型。
CREATE TABLE IF NOT EXISTS user_info (id INTEGER PRIMARY KEY,name VARCHAR(99),sex INTEGER )
假设主键是自增的,当insert一条数据到数据库中,获取自增主键的值可以这样写:
SELECT last_insert_rowid()
新增数据库
任何数据库都要先从建库和建表开始,因为我是做Android应用,所以直接通过JAVA程序来建库和建表,以后表的更新也是通过程序实现,这些功能都基于Android SQLite的SQLiteOpenHelper实现,非常地方便。
首先要了解这个核心抽象类SQLiteOpenHelper,既然是抽象类,我们就要创建一个实体类继承并实现SQLiteOpenHelper。
import android.content.C
import android.database.sqlite.SQLiteD
import android.database.sqlite.SQLiteDatabase.CursorF
import android.database.sqlite.SQLiteOpenH
public class DBHelper extends SQLiteOpenHelper {
public SQLHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
public void onCreate(SQLiteDatabase sqlitedatabase) {
public void onUpgrade(SQLiteDatabase sqlitedatabase, int i, int j) {
构造方法四个参数:
Context指Android的上下文,Activity就继承了Context,所以在Activity中可以将对象传入构造方法中;
name指数据库名称,所以一个实体类操作一个数据库;
CursorFactory游标工厂,用于执行查询操作时控制Cursor游标对象的,传入null就表示使用系统默认游标工厂;
version当前数据库版本,这个很重要,涉及到后面的onCreate和onUpgrade方法调用,这个必须是一个整数,没有特别要求你一定必须是哪个值,我的个人建议是第一次创建时设置version为1,随后每次更新表和字段时+1。(这个下面会说怎么回事)
关于构造函数的实现,我的代码是这么做的(实例化对象时,直接调用DBHelper(Context context)这个构造函数):
private static final String DATABASE_NAME = "bless_crm.db";
private static final int DATABASE_VERSION = 1;
public DBHelper(Context context) {
//CursorFactory设置为null,使用默认值
super(context, DATABASE_NAME, null, DATABASE_VERSION);
public DBHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
要注意,并不是new DBHelper就创建了数据库,第一次创建表必须调用DBHelper的getWritableDatabase()或getReadableDatabase()方法。这个两个方法除了可以创建数据库以外,还可以更新数据库下数据表的信息,所以我建议每次打开Android应用实例化DBHelper时都调用下这个方法,这个不会对应用造成什么特殊影响。
下面是在主Activity上实例化DBHelper,启动Android应用,会首先执行这个Activity,所以在这个类里初始化SQLite数据库是最佳的。
public class MainActivity extends Activity{
DBHelper helper =
protected void onCreate(Bundle savedInstanceState) {
helper = new DBHelper(MainActivity.this);
//第一次使用时创建数据库
//后面使用时更新数据表信息
helper.getWritableDatabase();
注:最好是在onCreate方法中实例化DBHelper并调用getWritableDatabase()方法,如果在Activity构造函数或者其它地方调用getWritableDatabase()很可能会报错。我的理解是Context一定是在执行onCreate时才最完整,所以大家以后涉及到Context最好在onCreate中调用。
新增/更新数据表
完成数据库创建之后,就该做数据表的创建了。
接上面的DBHelper类,该类有两个必须实现的方法onCreate和onUpgrade,顾名思义,onCreate表示第一个数据库版本时执行的方法,onUpgrade表示随后每更新一次version版本就执行的方法。
之所以SQLiteOpenHelper构造函数中的version非常重要,就是因为它用来管理onCreate和onUpgrade的。我的理解是这样的:
当数据库创建时会设置当前数据库版本(比如我们第一次设置为version=1),这时Android就会同时执行onCreate方法,所以所有初始化表的SQL语句都得在onCreate中实现。
而假设你的Android应用有代码更新,数据库字段也需要更新,那么这时就要将更新字段的SQL写到onUpgrade中,同时要将version版本改变一下,这样SQLite就知道version有改变,去执行onUpgrade方法。
以前面SQL为例,我希望在最初版本创建一张user_info表,就可以这样写:
private static final String DATABASE_NAME = "bless_crm.db";
private static final int DATABASE_VERSION = 1;
public SQLHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
public void onCreate(SQLiteDatabase sqlitedatabase) {
String user_info = "CREATE TABLE IF NOT EXISTS user_info (id INTEGER PRIMARY KEY,name VARCHAR(99),sex INTEGER )";
sqlitedatabase.execSQL(user_info);
public void onUpgrade(SQLiteDatabase sqlitedatabase, int i, int j) {
onCreate方法什么时候执行呢?它会在new DBHelper(context)之后,通过getWritableDatabase()或getReadableDatabase()来执行。
那么随后在编写Android应用的时候,我可能会有一些数据库表字段更新,这时就要用到onUpgrade方法并且修改version值。
private static final String DATABASE_NAME = "bless_crm.db";
private static final int DATABASE_VERSION = 2;
public SQLHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
public void onCreate(SQLiteDatabase sqlitedatabase) {
String user_info = "CREATE TABLE IF NOT EXISTS user_info (id INTEGER PRIMARY KEY,name VARCHAR(99),sex INTEGER,update_time varchart(99) )";
sqlitedatabase.execSQL(user_info);
public void onUpgrade(SQLiteDatabase sqlitedatabase, int oldVersion, int newVersion) {
if(oldVersion == 1 && newVersion == 2){
sqlitedatabase.execSQL("ALTER TABLE user_info ADD update_time varchart(99) ");
注意上面代码三个点:
①version又原来的1变为2了,这个是我自己修改的,只要这样修改,你的Android应用重新安装到移动设备后(并启动应用),数据库版本就会更新,同时就会触发onUpgrade方法。
②注意onCreate方法,与上一段代码对比,你会发现onCreate方法中也同步更新了"update_time"字段,为什么这么做?这是为了兼容新移动设备而做的安排,如果一款手机从来没有安装过你的应用,而它第一次安装你的应该时version已经是2了,这时SQLite会把version=2当做第一个版本,只会执行onCreate方法,如果你onCreate方法不是完整的SQL,就会对功能造成影响。所以以后不论变更过什么数据库信息,都要把onCreate方法同步更新了。
③注意onUpgrade方法第二个、第三个参数,一个是旧的版本,一个是新版本值,当version改变后,Android会自动传入oldVersion和newVersion,这时就可以通过判断版本来执行对应的SQL更新操作。
这里有一个重要的逻辑场景需要考虑:
你有两部移动设备:[小米手机]和[华为手机](支持国产)。
你的Android应用中DBHelper为version=1时,两部手机都安装了你的应用,这个时候系统会知道version第一次出现,会执行onCreate方法,理论上会有一个user_info表,有字段id/name/sex。
然后你修改Android应用程序,DBHelper version=2,希望在user_info表增加一个字段update_time,这时候你只给小米手机安装了应用程序,理论上系统会检测到version变化并执行onUpgrade(xx,1,2)方法,那么小米手机的数据库有了新字段update_time,但是注意华为手机因为没安装,所以没有。
再往后,你又修改了应用程序,DBHelper version=3,希望在user_info表中增加一个字段delete_flag,这时候编写onUpgrade就要尤为注意了,你可能得这么写代码:
public void onUpgrade(SQLiteDatabase sqlitedatabase, int oldVersion, int newVersion) {
if(oldVersion & 2 && newVersion &= 2){
sqlitedatabase.execSQL("ALTER TABLE user_info ADD update_time varchart(99) ");
if(oldVersion & 3 && newVersion == 3){
sqlitedatabase.execSQL("ALTER TABLE user_info ADD delete_flag integer ");
为什么要这么写,你得考虑跨version的手机数据库同步的问题,比如华为手机,原本version为1,这时你直接给它安装version=3的应用(而跳过version=2),这时华为手机必须先执行version=2的SQL再执行version=3的SQL,这样才能保证数据库完整!
这个也是我在编写本节内容的时候突然想到的一个问题,希望引起大家的重视!
关于SQLite建库和建表就说到这里,文笔有限,表达得不是很清楚,如果想真正熟悉SQLite,我建议新手下载Android SQLite相关的教程视频来看,我一直觉得视频讲解比文档要来得直接、生动、详细!
Android还提供了数据库增删改查API,要执行增删改查操作首先要调用getWritableDatabase()或getReadableDatabase()方法,这俩方法的区别是:getWritableDatabase()支持数据库"读写"操作;getReadableDatabase()支持数据库"读"操作。
增删改推荐使用getWritableDatabase()方法,而查询操作推荐用getReadableDatabase(),因为当手机存储空间被占满的时候getWritableDatabase()就无法使用了,但是getReadableDatabase()还可以继续执行查询操作。
[注:本小节代码摘自《》这个博客]
进行增删改查操作可以使用传统的SQL语句来操作:
public void savePerson(Person person) {
// getWritableDatabase()如果磁盘空间满了,就只能以读的方式打开数据库,所以在磁盘空间满了的状态下调用该方法会出错
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.execSQL("insert into person(name) values(?)", new Object[] { person.getName() });// 后面的数组用来填充前面的占位符
↑增删改都调用execSQL,这里就以insert为例。
public Person findPerson(Integer personId) {
SQLiteDatabase db = dbHelper.getReadableDatabase();// 如果磁盘空间没满的话,该对象与上面的对象是相等的,如果满了,该方法会调用另一只读方法,那么他们就不相等了
Cursor cursor = db.rawQuery("select * from person where id=?", new String[] { personId.toString() });
if (cursor.moveToFirst()) {
Person person = new Person();
person.setId(cursor.getInt(cursor.getColumnIndex("id")));
person.setName(cursor.getString(cursor.getColumnIndex("name")));
↑查询操作通过rawQuery获取Cursor游标对象,然后通过操作游标遍历获取对应的数据,这个类似于JDBC的ResultSet。
除了使用传统的SQL来进行数据库操作外,SQLite还提供了insert/delete/update/query等自封装的增删改查操作。下面还是以新增和查询为例。
public void savePerson(Person person) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", person.getName());
db.insert("person", null, values);// 该方法自己构造sql语句 所以性能比execSQL
// 参数2表示;如果参数3为空的话,参数2将作为insert语句的字段名插入一个null值,除了主键 其他都为空值
// 例如 db.insert("person", "name", null);
// 等价于 insert into person(name) values(null);
public Person findPerson(Integer personId) {
SQLiteDatabase db = dbOpenHelp.getReadableDatabase();
* 2:查找表列名的组合 是一个字符串数组 如果为null的话 则表示全部
* 3:查询的条件,可用占位符
* 4:是参数3中占位符的值
* 5:分组依据
* 6:分组筛选语句
* 7:排序语句
Cursor cursor = db.query("person", new String[] { "id", "name" }, "id=?", new String[] { personId.toString() }, null, null, null);
// 上面语句等价于 Cursor cursor =
// db.rawQuery("select * from person where id=?", new
// String[] { personId.toString() });
if (cursor.moveToFirst()) {
Person person = new Person();
person.setId(cursor.getInt(cursor.getColumnIndex("id")));
person.setName(cursor.getString(cursor.getColumnIndex("name")));
Java项目做多之后,就总是会想到考虑将常用的对象单例化、将某些相似功能封装组件化,针对自己的SQLite应用,我也做了一定的封装。
①构建Javabean与数据表对应,一张表一个Javabean,Bean中所有属性与表字段对应。
②编写一个通用的增删改查操作,开发只需要传入表名和参数即可执行指定操作,减少开发工作量
③DBHelper、Manager对象通过工厂创建并保持单例
以user_info表为例,我的user_info表有如下字段:
public void onCreate(SQLiteDatabase db) {
StringBuilder user_info = new StringBuilder();
user_info.append("CREATE TABLE IF NOT EXISTS \"user_info\" (");
user_info.append("\"id\" INTEGER NOT NULL,");
user_info.append("\"name\"
varchar(99),");
user_info.append("\"sex\"
INTEGER,");
user_info.append("\"birthday\"
varchar(32),");
user_info.append("\"mobile_phone\"
varchar(32),");
user_info.append("\"email\"
varchar(99),");
user_info.append("\"delete_flag\"
INTEGER,");
user_info.append("\"user_type\"
INTEGER,");
user_info.append("\"update_time\"
varchart(99),");
user_info.append("\"id_number\"
varchart(99),");
user_info.append("\"qq_number\"
varchart(99),");
user_info.append("\"address\"
varchart(999),");
user_info.append("PRIMARY KEY (\"id\")");
user_info.append(");");
db.execSQL(user_info.toString());
对应的,它有一个UserInfo JavaBean:
public class UserInfo extends BasePO{
private static final long serialVersionUID = -8097731L;
private String mobile_
private String id_
private String qq_
private int delete_
private int user_
private String update_
UserInfo继承了BasePO,这个类重写了clone、toString方法,并且提供了toJSON方法方便与javascript交互,这些实用的方法都是为了方便使用。
public class BasePO implements Serializable, Cloneable {
private static final long serialVersionUID = -4893448L;
* @description : 生成UUID
* @return Long
public static Long uuid(){
return UUID.randomUUID().getMostSignificantBits();
* 重写克隆方法
protected Object clone() throws CloneNotSupportedException {
return BeanUtils.cloneBean(this);
} catch (Exception e) {
Log.e(MON.getKey(), "克隆对象异常", e);
public String toJSON() {
return ClassUtils.toJson(this);
* 重写toString方法
public String toString() {
return ReflectionToStringBuilder.toString(this);
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
/** javascript与Java对象映射,页面可使用javascript:javascriptUser.xx()来调用JavascriptUser的方法 */
webView.addJavascriptInterface(new JavascriptUser(MainActivity.this), "javascriptUser");
在Activity中定义一个与HTML页面Javascript交互的接口,到时候就可以在页面调用接口进行保存操作了。
public class JavascriptUser {
protected A
protected AppC
protected UserManager userM
public JavascriptUser(Activity activity) {
this.activity =
app = (AppContext) activity.getApplication();
userManager = (UserManager) BeanFactory.getDBManager(UserManager.class, activity);
public String saveUserInfo(String id_,String name,String sex,String birthday,String mobile_phone,String email,String deleteFlag_,String userType_,String id_number,String qq_number,String address){
boolean edit = StringUtils.isNotBlank(id_);
Long id = StringUtils.isNotBlank(id_) ? Long.valueOf(id_) : UserInfo.uuid();
Integer delete_flag = StringUtils.isNotBlank(deleteFlag_) ? Integer.valueOf(deleteFlag_) : Enums.DeleteEnum.AVAILABLE.getKey();
Integer user_type = StringUtils.isNotBlank(userType_) ? Integer.valueOf(userType_) : Enums.UserTypeEnum.USER.getKey();
String update_time = DateUtil.date2string(new Date(), DateUtil.yyyy_MM_dd_HH_mm_ss);
UserInfo user = new UserInfo(id, name, Integer.valueOf(sex), birthday, mobile_phone, id_number, qq_number, email, address, delete_flag, user_type, update_time);
userManager.update(user);
Log.i(MON.getKey(), "修改个人信息:"+user.toString());
userManager.save(user);
Log.i(MON.getKey(), "新增个人信息:"+user.toString());
// 初始化当前用户
app.setUser(new UserInfoBO(user));
return "true,"+user.getId();
} catch (Exception e) {
Log.e(MON.getKey(), "输入异常:"+e.getMessage(), e);
return "输入异常:"+e.getMessage();
代码中userManager.update(user)用于update用户信息(一定要有主键),userManager.save(user)用于新增一条用户信息。获取UserManager对象是通过Factory来实现的,所有增删改查逻辑与UserManager有关。
public class UserManager extends BaseManagerImpl&UserInfo&{
public UserManager(Context context) {
super(context);
super.TABLE = "user_info";
super.clazz = UserInfo.
其实我的UserManager很简单,只有一个构造函数,告诉父类:我这个类与哪张表对应,与哪个JavaBean对应。
而执行增删改的重要操作是在BaseManagerImpl:
public class BaseManagerImpl&T& implements BaseManager&T& {
protected String LOG_TAG = "BaseManagerImpl";
protected String TABLE =
protected DBHelper dbHelper =
protected Class clazz =
public BaseManagerImpl(Context context) {
dbHelper = BeanFactory.getDBHelper(context);
public void save(T t) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
long result = db.insert(TABLE, null, ClassUtils.getContentValues(t));
public void delete(Serializable id) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
int result = db.delete(TABLE, "id=?", new String[]{id.toString()});
public void update(T t) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.update(TABLE, ClassUtils.getContentValues(t), "id=?", new String[]{ClassUtils.getFieldValue(t, "id").toString()});
} catch (Exception e) {
Log.e(LOG_TAG, "反射无法找到对象的ID值", e);
public T get(Serializable id) {
String getSQL = "SELECT * FROM "+TABLE+" WHERE id=?";
List&T& list = this.findBySql(getSQL, new String[]{id.toString()}, 0, 0);
if(!ObjectUtils.isEmpty(list)){
return list.get(0);
public List&T& findBySql(String sql, String[] params,int pageSize,int pageNo) {
if(StringUtils.isBlank(sql)){
throw new RuntimeException("findBySql的sql不能为空!");
if(pageSize != 0 && pageNo != 0){//分页操作
int begin = (pageSize - 1)*pageNo;
sql = sql + " limit "+begin + ","+pageNo;
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery(sql, params);
List&T& tList =
tList = ClassUtils.getObject(cursor, clazz);
} catch (Exception e) {
Log.e(LOG_TAG, "反射创建对象失败,clazz:"+clazz.getName(), e);
cursor.close();
public void updateBySql(String sql, Object[] params) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.execSQL(sql, params);
public List&T& findAll() {
String findAllSql = "SELECT * FROM "+TABLE;
return this.findBySql(findAllSql, null, 0, 0);
最后看我的Factory类
public class BeanFactory {
* @description : 单例模式,获取DBHelper
* @param context
* @return DBHelper
private static DBHelper dbHelper =
public synchronized static DBHelper getDBHelper(Context context){
if(dbHelper == null){
dbHelper = new DBHelper(context);
//执行本语句是为了自动调用建表语句
dbHelper.getWritableDatabase();
} catch (Exception e) {
Log.e("BeanFactory", "创建表失败!", e);
return dbH
static Map&String, Object& dbMap = new HashMap&String, Object&();
@SuppressWarnings("rawtypes")
public static Object getDBManager(Class clazz,Context context){
if(clazz == null){
throw new RuntimeException("class can not be null!");
if(context == null){
throw new RuntimeException("object can not be null!");
if(!dbMap.containsKey(clazz.getName())){//第一次创建对象
Constructor con = clazz.getConstructor(Context.class);
Object object = con.newInstance(context);
dbMap.put(clazz.getName(), object);
} catch (Exception e) {
Log.e(MON.getKey(), "对象工厂创建DBManager失败:"+clazz.getName(), e);
return dbMap.get(clazz.getName());
在将JavaBean转换为数据库数据以及反向从数据库转为JavaBean时,我用了Java反射功能。但是我要检讨----我太偷懒了,在反射解析private属性时我是直接获取Field而不是通过setMethod来实现,这显然破坏了封装的原则!
public class ClassUtils {
public static ContentValues getContentValues(Object object){
Class clazz = object.getClass();
Field[] fields = ClassUtils.getAllFields(object);
Field.setAccessible(fields, true);
if(ArrayUtils.isNotEmpty(fields)){
ContentValues cv = new ContentValues();
for (Field field : fields) {
if(!"serialVersionUID".equals(field.getName())){//去掉serialVersionUID
Object value = field.get(object);
cv.put(field.getName(),value.toString());
} catch (Exception e) {
Log.e(MON.getKey(), "", e);
public static List getObject(Cursor cursor,Class clazz) throws Exception{
List list = new ArrayList();
while (cursor.moveToNext()) {
Object instance = clazz.newInstance();
Field[] fields = ClassUtils.getAllFields(instance);
Field.setAccessible(fields, true);
for (Field field : fields) {
if(!"serialVersionUID".equals(field.getName())){//去掉serialVersionUID
if(field.getType().equals(Integer.class) || field.getType().getName().equals("int")){
field.set(instance, cursor.getInt(cursor.getColumnIndex(field.getName())));
}else if(field.getType().equals(String.class)){
field.set(instance, cursor.getString(cursor.getColumnIndex(field.getName())));
}else if(field.getType().equals(Long.class) || field.getType().getName().equals("long")){
field.set(instance, cursor.getLong(cursor.getColumnIndex(field.getName())));
list.add(instance);
还有关于SQLite事务可以参考这个博客:《》,因为目前还没用到涉及事务的地方,所以我的代码中没做相关处理。
1、看下面这句LIKE模糊查询查询代码,按常理来说,这样编写的代码是没问题的,但是在Sqlite下面偏偏报错。
String sql = "SELECT * FROM user_info WHERE name like '%?%'";
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery(sql, new String[]{"张"});
编写了上面这段代码后,我在LogCat捕获到一个异常:Cannot bind argument at index 1 because the index is out of range.
The statement has 0 parameters.看意思感觉是参数不对,但实际是对的,问题的根本是单引号,这里不能有单引号:SELECT * FROM user_info WHERE name like %?%。
那么我去掉单引号后还是报错:near "%": syntax error (code 1)。
结果又去网上找了下,发现在SQL中用%是不行的,必须让%以参数的形式传过去,所以正确的代码应该这样写:
String sql = "SELECT * FROM user_info WHERE name like ?";
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery(sql, new String[]{"%张%"});
以上就是我在学习Android SQLite总结的经验,用得非常肤浅,但是基本满足应用需要了。
浏览: 1072910 次
来自: 成都
很好用! 问题解决!O(∩_∩)O谢谢
根号九加一 写道root的值是什么,是什么路径,能提供一下吗? ...
root的值是什么,是什么路径,能提供一下吗?
[url] [/url]
[*]& target=&_blank&q ...

我要回帖

更多关于 android 数据库查询 的文章

 

随机推荐