sqlite简介
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至2015年已经有15个年头,SQLite也迎来了一个版本 SQLite 3已经发布。
效果图:
以下为工程结构:
以下Layout:
'''
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/txtInput"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/btnAdd"
android:text="add"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/btnViewAll"
android:text="select"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/viewALl"
/>
</LinearLayout>
'''
以下为DBHelper:
''' java
package com.loweir.sqlitedemo;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
/**
- 数据库操作工具类
- @author daguangspecial@gmail.com
*/
public class DBHelper {
private static final String TAG = "DBDemo_DBHelper";
// 调试标签
private static final String DATABASE_NAME = "dbdemo.db";
// 数据库名
SQLiteDatabase db;
Context context;// 应用环境上下文 Activity 是其子类DBHelper(Context _context) {
/**
context = _context;
// 开启数据库
db = context.openOrCreateDatabase(DATABASE_NAME, Context.MODE_APPEND,
null);
CreateTable();
Log.v(TAG, "db path=" + db.getPath());
}-
- 建表 * 列名 区分大小写? * 都有什么数据类型? * SQLite 3 * TEXT 文本 NUMERIC 数值 INTEGER 整型
- REAL 小数 NONE 无类型 * 查询可否发送select ?
*/
public void CreateTable() {
try {
db.execSQL("CREATE TABLE t_user ("
+ "_ID INTEGER PRIMARY KEY autoincrement," + "NAME TEXT"
+ ");");
Log.v(TAG, "Create Table t_user ok");
} catch (Exception e) {
Log.v(TAG, "Create Table t_user err,table exists.");
}
}
/** * 增加数据 * @param id * @param uname * @return */
public boolean save(String uname) {
String sql = "";
try {
sql = "insert into t_user values(null,'" + uname + "')";
db.execSQL(sql);
Log.v(TAG, "insert Table t_user ok");
return true;
} catch (Exception e) {
Log.v(TAG, "insert Table t_user err ,sql: " + sql);
return false;
}
}/** * 查询所有记录 * * @return Cursor 指向结果记录的指针,类似于JDBC 的 ResultSet */
public Cursor loadAll() {
if (db == null) {
Log.e(TAG, " loadall db is null");
return null;
}
Cursor cur = null;
try {
cur = db.query("t_user", new String[] { "_ID", "NAME" }, null,
null, null, null, null);
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "61");
}
if (cur == null) {
Log.e(TAG, " loadall cur is null");
return null;
}
System.out.println("loadall is ok");
return cur;
}public void close() {
db.close();
}
}-
'''
以下为 MainActivity.java
''' java
package com.loweir.sqlitedemo;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
/**
*/
public class MainActivity extends Activity {
EditText inputTxt;
Button btnAdd;
Button btnViewAll;
TextView viewAll;
DBHelper db;@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_main);
// 初始化UI
btnAdd = (Button) findViewById(R.id.btnAdd);
btnViewAll = (Button) findViewById(R.id.btnViewAll);
viewAll = (TextView) findViewById(R.id.viewALl);
inputTxt = (EditText) findViewById(R.id.txtInput);
// 初始化DB
db = new DBHelper(this);
// 初始化监听
OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
if (v.getId() == R.id.btnAdd) {
// 增加
db.save(inputTxt.getText().toString());
viewAll.setText("input success");//这里的db.close() 必须注释掉以下有解释 //db.close(); } else if (v.getId() == R.id.btnViewAll) { // 浏览所有数据 if( db == null) { viewAll.setText("db is null"); return ; } Cursor cur = null; try { cur = db.loadAll(); } catch(Exception e) { Log.i("Main", "58"); return ; } Log.i("Main", "61"); StringBuffer sf = new StringBuffer(); cur.moveToFirst(); Log.i("Main", "64"); while (!cur.isAfterLast()) { Log.i("Main", "60"); sf.append(cur.getInt(0)).append(" : ") .append(cur.getString(1)).append("\n"); cur.moveToNext(); } db.close(); viewAll.setText(sf.toString()); } } }; btnAdd.setOnClickListener(listener); btnViewAll.setOnClickListener(listener);
}
}
'''
*因为在MainActivity中有句db.close() 没有注释掉 导致在查询数据库的时候出现错误。为此我在代码中加了很多Log语句用来查看程序运行状况 比如说上面的Log.i("Main","58");其中58为行数。
每次运行的时候都是只能插入而无法查询。
首先我想到的是Cursor 是否为空,经过断点调试确实为空
这样,我想到是不是数据库是空。查了一下adb的命令
adb shell 可以进入shell
然后 通过ls cd rm 命令
找到 并删除创建的数据库 重新测试一下
结果仍然报错
于是在ddms视图 用File explorer 将数据库导出 并用sqlite expert 查看 结果有值
这时我看到一个异常 因为一开始 我只try了异常 并没有e.print
这时看到 e 的值为
java.lang.IllegalStateException: attempt to re-open an already-closed object
百度结果为:
http://blog.csdn.net/zhufuing/article/details/14455823
这个错误出现的原因是因为我在一个数据库查询方法中调用了另一个数据库查询方法,我的数据库查询方法都是在开始的时候获取SQLiteDatabase对 象,在结束的时候关闭SQLiteDabse对象,结果内部的数据库查询方法在结束的时候直接关闭了SQLiteDatabase对象,导致外面的数据库 查询操作报错,在这里大家不要以为多获取了几个SQLiteDatabase对象就可以了,每个线程只能使用一个SQLiteOpenHelper,也就 使得每个线程使用一个SQLiteDatabase对象(多线程操作数据库会报错);
解决办法就是我不再关闭内部数据库查询方法的SQLiteDatbase对象或者将那个方法直接集成到外面的查询方法中,当然,要确保这个查询方法只会出 现其他数据库查询方法中,要是单独用这个方法,反而会因为SQLiteDatabase对象没有关闭而报错;
然后 我就将上面的那个db.close() 注释掉
结果ok