Android SQLite 使用总结,androidsqlite
以下内容转载自:Android中SQLite应用详解 为了个人理解,有改动部分。
另附 Sqlite 介绍: 同样也是上面那位博主写的,很详细
通常使用方法
//打开或创建数据库
SQLiteDatabase db=openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null);
db.execSQL("DROP TABLE IF EXISTS person");
//创建表
db.execSQL(CREATE_TABLE_PERSON);
Person person=new Person("小白",11);
//带占位符的插入语句
db.execSQL("insert into person values(?,?)", new Object[]{person.getName(), person.getAge()});
person.setValue("小黑", 16);
ContentValues cv=new ContentValues();
cv.put("name", person.getName());
cv.put("age", person.getAge());
//通过ContentValues 插入数据
db.insert("person", null, cv);
ContentValues updateCV=new ContentValues();
updateCV.put("age", 19);
//通过ContentValues 修改数据
db.update("person", updateCV, "name=?", new String[]{"小白"});
//查询整行数据
Cursor cursor=db.rawQuery("SELECT * FROM person",null);
while(cursor.moveToNext()){
//通过获取列的索引获取数据
String name=cursor.getString(cursor.getColumnIndex("name"));
int age=cursor.getInt(cursor.getColumnIndex("age"));
Log.d("my","name = :"+name+" age = : "+age);
}
cursor.close();
//删除
db.delete("person", "name=?", new String[]{"小黑"});
//如果数据库存在且已打开则将它关闭
if(db!=null&&db.isOpen())
db.close();
对于建立表,插入,删除,修改等可以使用通用的语法:
db.executeSQL(String sql);
db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集
统一操作外对应的方法:
db.insert(String table, String nullColumnHack, ContentValues values);
db.update(String table, Contentvalues values, String whereClause, String whereArgs);
db.delete(String table, String whereClause, String whereArgs);
以上语句的第一个参数都为需要操作的表。insert 中第二个参数 nullColumnHack 表示当行中的数据都为空时,指定该行的某一列的值为null,防止出错.
values 参数为 Contentvalues 类型 为键值对组成的 Map , key 为列名,value为要插入的值
whereClause 表示为 WHERE 表达式 ,如 "WHERE NAME = ?" , whereArgs 为实际占位符表示的值
丰富的查询方法:
db.rawQuery(String sql, String[] selectionArgs);
db.query(String table, String[] columns, String selection, String[] selectionArgs,
String groupBy, String having, String orderBy);
db.query(String table, String[] columns, String selection, String[] selectionArgs,
String groupBy, String having, String orderBy, String limit);
db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs,
String groupBy, String having, String orderBy, String limit);
第一种最简单, sql 参数为实际的整个 SELEC 语句, selectionArgs 为实际占位符表示的值
其余参数:
table: 表名
colums: 查询的列所有名称集
selectionArgs: WHER 语句后面的内容,可用占位符
groupBy: 指定分组的列名
having: 指定分组条件
orderBy: 指定排序列名
limit: 指定分页参数
distinct: 指定 true 或 false 表示要不要过滤重复值
selection,groupB,having,orderBy,limit这几个参数中
不包括 “WHERE”、“GROUP BY”、“HAVING”、“ORDER BY”、“LIMIT”等SQL关键字。
Cursor 常用方法:
Cursor 常用方法:
c.move(int offset); //以当前位置为参考,移动到指定行
c.moveToFirst(); //移动到第一行
c.moveToLast(); //移动到最后一行
c.moveToPosition(int position); //移动到指定行
c.moveToPrevious(); //移动到前一行
c.moveToNext(); //移动到下一行
c.isFirst(); //是否指向第一条
c.isLast(); //是否指向最后一条
c.isBeforeFirst(); //是否指向第一条之前
c.isAfterLast(); //是否指向最后一条之后
c.isNull(int columnIndex); //指定列是否为空(列基数为0)
c.isClosed(); //游标是否已关闭
c.getCount(); //总数据项数
c.getPosition(); //返回当前游标所指向的行数
c.getColumnIndex(String columnName);//返回某列名对应的列索引值
c.getString(int columnIndex); //返回当前行指定列的值
c.getColumnName() //从给定的索引返回列名
c.getColumnCount() //返回所有列的总数
正如上面所述,数据库第一次创建时onCreate方法会被调用,我们可以执行创建表的语句,当系统发现版本变化之后,会调用onUpgrade方法,我们可以执行修改表结构等语句。
然而每次这样使用数据库,会显得非常繁琐,所以需要把相应的方法封装起来,操作更加方便。首先定义一个DbOpenHelper 的类方便数据库的创建,更新
public class DbHelper extends SQLiteOpenHelper {
public static String DATABASE_NAME="m.db3";
private static int DATABASE_VERSION=1;
private static String CREATE_TABLE_PERSON=
"CREATE TABLE IF NOT EXISTS person ("
+"_id INTEGER PRIMARY KEY ,"
+ "name char(20) ,"
+ "age int )";
//重新建表
public void resetTable(){
getWritableDatabase().execSQL("DROP TABLE IF EXISTS person");
getWritableDatabase().execSQL(CREATE_TABLE_PERSON);
}
public DbHelper(Context context, int version) {
super(context, DATABASE_NAME, null, version);
}
//数据库创建时会调用 onCreate
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_PERSON);
}
//如果数据库版本不同,将会调用 onUpgrade
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//db.execSQL("ALTER TABLE person ADD COLUMN sex char(2)");
}
}
然后为了能够面向对象操作数据,需要把数据封装到一个 Person 类中
public class Person
{
private String name;
private int age;
public Person(){
name="小明";
age=1;
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(int age) {
this.age=age;
}
public void setValue(String name,int age){
this.name=name;
this.age=age;
}
}
接下来需要一个 DbManager 来把需要的方进行封装:
public class DbManager {
private DbHelper dbHelper;
private SQLiteDatabase db;
public DbManager(Context context){
dbHelper=new DbHelper(context,1);
db=dbHelper.getWritableDatabase();
}
public void resetTable(){
dbHelper.resetTable();
}
public void add(List<Person> lists){
//开启一个事务
db.beginTransaction();
try {
for (Person person:lists)
db.execSQL("INSERT INTO person VALUES(?,?,?)",
new Object[]{null,person.getName(),person.getAge()});
db.setTransactionSuccessful();//设置事务完成
}
finally {
db.endTransaction();//事务结束
}
}
public void updateAge(Person person){
ContentValues contentValues=new ContentValues();
contentValues.put("age",person.getAge());
db.update("person", contentValues, "name=?", new String[]{person.getName()});
}
public void deletePerson(Person person){
db.delete("person", "name=?", new String[]{person.getName()});
}
public ArrayList<Person>query(){
ArrayList<Person> lists=new ArrayList<Person>();
Cursor cursor=db.rawQuery("SELECT * FROM person",null);
while(cursor.moveToNext()){
Person person=new Person();
person.setName(cursor.getString(cursor.getColumnIndex("name")));
person.setAge(cursor.getInt(cursor.getColumnIndex("age")));
lists.add(person);
}
cursor.close();
return lists;
}
public Cursor queryTheCursor(){
Cursor cursor=db.rawQuery("SELECT * FROM person",null);
return cursor;
}
public void closeDatabase(){
db.close();
}
}
使用示范
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
TextView textView;
EditText nameEdit,ageEdit;
DbManager dbManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getView();
dbManager=new DbManager(MainActivity.this);
}
@Override
public void onClick(View v) {
String name=nameEdit.getText().toString();
String age=ageEdit.getText().toString();
if(age.equals(""))age="0";
Person person=new Person(name,Integer.parseInt(age));
switch (v.getId()){
case R.id.createButton:
dbManager.resetTable();
break;
case R.id.insertButton:
ArrayList<Person>lists=new ArrayList<Person>();
lists.add(person);
dbManager.add(lists);
break;
case R.id.deleteButton:
dbManager.deletePerson(person);
break;
case R.id.updateButton:
dbManager.updateAge(person);
break;
case R.id.queryButton:
query();
/*显示在TextView 中
ArrayList<Person>persons=dbManager.query();
StringBuffer stringBuffer=new StringBuffer();
for(int i=0;i<persons.size();i++){
Person per=persons.get(i);
stringBuffer.append(per.getName()+"\t"+per.getAge()+"\n");
}
textView.setText(stringBuffer);
*/
break;
}
}
//把查询结果 显示在 ListView 中
public void query(){
Cursor cursor= dbManager.queryTheCursor();
startManagingCursor(cursor);
//托付给activity根据自己的生命周期去管理Cursor的生命周期
CursorWrapper cursorWrapper=new CursorWrapper(cursor){
@Override
public String getString(int columnIndex){
return super.getString(columnIndex);
}
};
SimpleCursorAdapter adapter=new SimpleCursorAdapter(
this,android.R.layout.simple_list_item_2,
cursorWrapper,new String []{"name","age"},
new int[]{android.R.id.text1,android.R.id.text2});
ListView listView=(ListView)findViewById(R.id.list);
listView.setAdapter(adapter);
}
//获得界面中的组件
private void getView(){
textView=(TextView)findViewById(R.id.text);
nameEdit=(EditText)findViewById(R.id.nameEdit);
ageEdit=(EditText)findViewById(R.id.ageEdit);
Button createButton=(Button)findViewById(R.id.createButton);
Button insertButton=(Button)findViewById(R.id.insertButton);
Button deleteButton=(Button)findViewById(R.id.deleteButton);
Button updateButton=(Button)findViewById(R.id.updateButton);
Button queryButton=(Button)findViewById(R.id.queryButton);
createButton.setOnClickListener(this);
insertButton.setOnClickListener(this);
deleteButton.setOnClickListener(this);
updateButton.setOnClickListener(this);
queryButton.setOnClickListener(this);
}
//关闭数据库
@Override
public void onDestroy(){
super.onDestroy();
dbManager.closeDatabase();
}
}
这里需要注意的是SimpleCursorAdapter的应用,当我们使用这个适配器时,我们必须先得到一个Cursor象,
这里面有几个问题:如何管理Cursor的生命周期,如果包装Cursor,Cursor结果集都需要注意什么。如果手动去管
理Cursor的话会非常的麻烦,还有一定的风险,处理不当的话运行期间就会出现异常,幸好Activity为我们提供
了startManagingCursor(Cursor cursor)方法,它会根据Activity的生命周期去管理当前的Cursor对象,下面是该
方法的说明:
/**
* This method allows the activity to take care of managing the given
* {@link Cursor}'s lifecycle for you based on the activity's lifecycle.
* That is, when the activity is stopped it will automatically call
* {@link Cursor#deactivate} on the given Cursor, and when it is later restarted
* it will call {@link Cursor#requery} for you. When the activity is
* destroyed, all managed Cursors will be closed automatically.
*
* @param c The Cursor to be managed.
*
* @see #managedQuery(android.net.Uri , String[], String, String[], String)
* @see #stopManagingCursor
*/
中提到,startManagingCursor方法会根据Activity的生命周期去管理当前的Cursor对象的生命周期,就是说当Activity停止时他会自动调用Cursor的deactivate方法,禁用游标,当Activity重新回到屏幕时它会调用Cursor的requery方法再次查询,当Activity摧毁时,被管理的Cursor都会自动关闭释放。
如何包装Cursor:我们会使用到CursorWrapper对象去包装我们的Cursor对象,实现我们需要的数据转换工作,这个CursorWrapper实际上是实现了Cursor接口。我们查询获取到的Cursor其实是Cursor的引用,而系统实际返回给我们的必然是Cursor接口的一个实现类的对象实例,我们用CursorWrapper包装这个实例,然后再使用SimpleCursorAdapter
将结果显示到列表上。
Cursor结果集需要注意些什么:一个最需要注意的是,在我们的结果集中必须要包含一个“_id”的列,
否则SimpleCursorAdapter就会翻脸不认人,为什么一定要这样呢?因为这源于SQLite的规范,主键以“_id”为标准。
解决办法有三:
第一,建表时根据规范去做;
第二,查询时用别名,例如:SELECT id AS _id FROM person;
第三,在CursorWrapper里做文章:
CursorWrapper cursorWrapper = new CursorWrapper(c) {
@Override
public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException {
if (columnName.equals("_id")) {
return super.getColumnIndex("id");
}
return super.getColumnIndexOrThrow(columnName);
}
};
如果试图从CursorWrapper里获取“_id”对应的列索引,我们就返回查询结果里“id”对应的列索引即可