SQLite详解与数据库分页问题,指定获取多少条数据
Android 为了让我们能够更加方便地管理数据库,专门提供了一个 SQLiteOpenHelper 帮
助类,借助这个类就可以非常简单地对数据库进行创建和升级。既然有好东西可以直接使用,那我们自然要尝试一下了
数据库文件会存放在/data/data/<package name>/databases/目录下
SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,
getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。
注意:getWritableDatabase(),getReadableDatabase的区别是当数据库写满时,调用前者会报错,调用后者不会,所以如果不是更新数据库的话,最好调用后者来获得数据库连接。
1 package com.example.my_sqlite; 2 3 import android.content.ContentValues; 4 import android.content.Context; 5 import android.database.sqlite.SQLiteDatabase; 6 import android.database.sqlite.SQLiteDatabase.CursorFactory; 7 import android.database.sqlite.SQLiteOpenHelper; 8 9 public class MyDatabaseHelper extends SQLiteOpenHelper{ 10 //定义创建表的字符串 表:book(id,书名,价格,作者) 11 public static final String CREATE_BOOK="create table book(id integer primary key autoincrement,name text,price real,author text);"; 12 /*integer 表示整型, real 表示浮点型,text 表示文本类型,blob 表示二进制类型。另外,上述建表语句中我们还 13 使用了 primary key 将 id 列设为主键,并用 autoincrement关键字表示 id 列是自增长的。 14 */ 15 public MyDatabaseHelper(Context context, String name, 16 CursorFactory factory, int version) { 17 super(context, name, factory, version);//必须调用父类构造方法才能去创建数据库,但是执行此方法不会创建数据库 18 System.out.println("构造方法调用--我的数据库帮助类"); 19 } 20 21 //执行getReadableDatabase(),getWritableDatabase()时会调用此方法 22 //也就是创建了数据库对象才会调用此方法 但是: 23 //注意:onCreate()方法在初次生成数据库时才会被调用,在其他地方再次创建MyDatavaseHelper对象也不会执行该方法 24 @Override 25 public void onCreate(SQLiteDatabase db) { 26 System.out.println("调用oncreate"); 27 db.execSQL(CREATE_BOOK);//执行创建该表的语句 28 System.out.println("创建了book表"); 29 } 30 31 //onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号 32 @Override 33 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 34 System.out.println("数据库更新时调用此方法"); 35 ContentValues values=new ContentValues(); 36 values.put("name", "book3");//与表的数据类型一一对应 37 values.put("price", 52.3); 38 values.put("author", "book3_name"); 39 db.insert("book", null, values);//插入数据 40 } 41 42 }
对数据库进行操作的类:
1 package com.example.my_sqlite; 2 3 import android.app.Activity; 4 import android.content.ContentValues; 5 import android.database.Cursor; 6 import android.database.sqlite.SQLiteDatabase; 7 import android.os.Bundle; 8 import android.view.Menu; 9 import android.view.MenuItem; 10 import android.view.View; 11 import android.view.View.OnClickListener; 12 import android.widget.Button; 13 14 public class MainActivity extends Activity { 15 public static int version=1;//数据库的版本号 16 private MyDatabaseHelper myDatabase; 17 @Override 18 protected void onCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 Button creat=(Button) findViewById(R.id.button1);//创建数据库和表 22 Button add_Data=(Button) findViewById(R.id.button2);//添加数据 23 Button query_Data=(Button) findViewById(R.id.button3);//查询数据 24 Button update=(Button) findViewById(R.id.button4);//更新数据 25 Button delete_Data=(Button) findViewById(R.id.button5);//删除数据 26 Button updata_SQL=(Button) findViewById(R.id.button6);//更新数据库 27 myDatabase = new MyDatabaseHelper(this, "MySQL", null, version);//执行该语句是不会创建数据库的 28 /*说明: 29 * 当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法 30 * 获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,紧接着就会去调用onCreate方法 31 * 也就是说当调用了读或写的方法时就会先去判断有没有该数据库,有就不创建没有就创建,然后就会去调用onCreate方法 32 */ 33 creat.setOnClickListener(new OnClickListener() {//创建数据库 34 @Override 35 public void onClick(View v) { 36 System.out.println("creat"); 37 SQLiteDatabase db = myDatabase.getReadableDatabase();//创建数据库和调用onCreate方法 38 } 39 }); 40 add_Data.setOnClickListener(new OnClickListener() {//为表添加数据 41 @Override 42 public void onClick(View v) { 43 System.out.println("添加数据(id自增,书名,价格,作者)"); 44 SQLiteDatabase db = myDatabase.getWritableDatabase(); 45 ContentValues values=new ContentValues(); 46 values.put("name", "哈利波特");//与表的数据类型一一对应 47 values.put("price", 52.3); 48 values.put("author", "作者名"); 49 db.insert("book", null, values);//插入数据 50 values.clear();//清除数据 51 values.put("name", "book2");//与表的数据类型一一对应 52 values.put("price", 10.5); 53 values.put("author", "book2_name"); 54 db.insert("book", null, values);//插入数据 55 } 56 }); 57 query_Data.setOnClickListener(new OnClickListener() {//查询数据 58 @Override 59 public void onClick(View v) { 60 System.out.println("查询数据单击事件"); 61 SQLiteDatabase db = myDatabase.getReadableDatabase(); 62 Cursor cursor = db.query("book",null, null, null, null, null, null);//查询所有数据,返回一个游标 63 while(cursor.moveToNext()){ 64 int id=cursor.getColumnIndex("id"); 65 int name = cursor.getColumnIndex("name");//获得下标 66 int price = cursor.getColumnIndex("price"); 67 int author=cursor.getColumnIndex("author"); 68 System.out.print("id:"+cursor.getString(id)); 69 System.out.print(" 书名:"+cursor.getString(name));//通过下标获取值 70 System.out.print(" 价格:"+cursor.getString(price)); 71 System.out.println(" 作者:"+cursor.getString(author)); 72 } 73 } 74 }); 75 update.setOnClickListener(new OnClickListener() {//更新数据 76 @Override 77 public void onClick(View v) { 78 System.out.println("更新数据单击事件"); 79 SQLiteDatabase db = myDatabase.getWritableDatabase(); 80 ContentValues values=new ContentValues(); 81 values.put("price",52.2); 82 //db.update("book", values, "author=?", new String[]{"book2_name"});//将作者=book2_name的price改为20.2 83 db.update("book", values, "id=? or id=? ", new String[]{String.valueOf(5),"3"});//将id=5或id=3的price改为20.2 84 }//第二个参数是 ContentValues 对象,要把更新数据在这里组装进去。第三、第四个参数 85 });//用于去约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。 or and = 也可写> < 86 87 88 delete_Data.setOnClickListener(new OnClickListener() {//删除数据 89 @Override 90 public void onClick(View v) { 91 System.out.println("删除数据单击事件"); 92 SQLiteDatabase db = myDatabase.getWritableDatabase(); 93 db.delete("book", "name=?", new String[]{"哈利波特"});//删除name为哈利波特的数据 94 } 95 }); 96 updata_SQL.setOnClickListener(new OnClickListener() {//更新数据库 97 @Override 98 public void onClick(View v) { 99 System.out.println("更新数据库单击事件"); 100 version=2;//将版本号变大 101 myDatabase=new MyDatabaseHelper(MainActivity.this, "MySQL", null, version);//执行此方法不会调用更新方法onUpgrade 102 myDatabase.getWritableDatabase();//调用此方法就会更新数据 103 } 104 }); 105 } 106 107 }
根据指定路径打开数据库,手机内存的也能打开
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/person_db.db"; //根据数据库路径打开数据库,得到操作数据库的对象 SQLiteDatabase db = SQLiteDatabase.openDatabase(path, null,SQLiteDatabase.OPEN_READWRITE);
增删改查的参数可参考: 内容提供者基础(含有自己的例子) 以及sql语句 sqlite3的语句记录
使用事务
SQLite 数据库是支持事务的,事务的特性可以保证让某一系列的操
作要么全部完成,要么一个都不会完成。那么在什么情况下才需要使用事务呢?想象以下场
景,比如你正在进行一次转账操作,银行会将转账的金额先从你的账户中扣除,然后再向收
款方的账户中添加等量的金额。看上去好像没什么问题吧?可是,如果当你账户中的金额刚
刚被扣除,这时由于一些异常原因导致对方收款失败,这一部分钱就凭空消失了!当然银行
肯定已经充分考虑到了这种情况,它会保证扣钱和收款的操作要么一起成功,要么都不会成
功,而使用的技术当然就是事务了。
例如:
1 Button replaceData = (Button) findViewById(R.id.replace_data); 2 replaceData.setOnClickListener(new OnClickListener() { 3 @Override //按钮单击事件 4 public void onClick(View v) { 5 SQLiteDatabase db = dbHelper.getWritableDatabase();//获取对数据库的操作对象 6 db.beginTransaction(); // 开启事务 7 try { 8 db.delete("Book", null, null);//删除Book表的所有数据 9 if (true) {// 在这里手动抛出一个异常,让事务失败 10 throw new NullPointerException(); 11 } 12 ContentValues values = new ContentValues(); 13 values.put("name", "Game of Thrones"); 14 values.put("author", "George Martin"); 15 values.put("pages", 720); 16 values.put("price", 20.85); 17 db.insert("Book", null, values); 18 db.setTransactionSuccessful(); // 事务已经执行成功 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } finally { 22 db.endTransaction(); // 结束事务 23 } 24 }); 25 }
由于在删除数据之前开启了事务,所以抛出异常的时候执行不到 db.setTransactionSuccessful(); 也就是事务没有执行成功
在结束事务的时候,如果事务没有执行成功,那么开启事务之后的操作也就不会成功了,所以删除数据的操作也就没有成功
数据库的分页问题,获取数据库且指定数据的条数:
public class MainActivity extends Activity { private ListView lvPersons; private Context context; private List<Map<String, Object>> dataList; private int index = 1; private boolean isBottom = false; private SimpleAdapter simpleAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.context = MainActivity.this; dataList = new ArrayList<Map<String, Object>>(); // 获取第一页数据 List<Map<String, Object>> indexPageDataList = getIndexPageDataList(index); dataList.addAll(indexPageDataList); lvPersons = (ListView) findViewById(R.id.lv_persons); simpleAdapter = new SimpleAdapter(context, dataList, R.layout.listview_item_person, new String[]{"name","age"}, new int[]{R.id.tv_name,R.id.tv_age}); lvPersons.setAdapter(simpleAdapter); //分页 lvPersons.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if(isBottom && scrollState == SCROLL_STATE_IDLE){ //第二页 index +=1; List<Map<String, Object>> indexPageDataList2 = getIndexPageDataList(index); dataList.addAll(indexPageDataList2); //刷新 simpleAdapter.notifyDataSetChanged(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { isBottom = (firstVisibleItem + visibleItemCount == totalItemCount); } }); } private List<Map<String, Object>> getIndexPageDataList(int index) { ArrayList<Map<String, Object>> resultDatalist = new ArrayList<Map<String, Object>>(); // 打开数据库 // 查询index页数据,获得cursor // 在while循环中获得每一条数据,封装到map中,并添加到list中 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/person_db.db";//打开指定数据库 //根据数据库路径打开数据库,得到操作数据库的对象 SQLiteDatabase db = SQLiteDatabase.openDatabase(path, null,SQLiteDatabase.OPEN_READWRITE); // 设置分页查询的起始位置 int startIndex = (index - 1) * 15; String sql = "select * from person limit ?,15";//代表查询person表 15条数据 Cursor cursor = db.rawQuery(sql, new String[] {startIndex + ""} ); HashMap<String, Object> map; while (cursor.moveToNext()) { map = new HashMap<String, Object>(); String key = ""; Object value = null; String[] columnNames = cursor.getColumnNames(); for (int i = 0; i < columnNames.length; i++) { key = columnNames[i]; // 确定value int type = cursor .getType(cursor.getColumnIndex(columnNames[i])); //获得列的索引 int columnIndex = cursor.getColumnIndex(columnNames[i]); switch (type) { case Cursor.FIELD_TYPE_BLOB://大的二进制数据 value = cursor.getBlob(columnIndex); break; case Cursor.FIELD_TYPE_FLOAT://浮点类型 value = cursor.getFloat(columnIndex); break; case Cursor.FIELD_TYPE_INTEGER://整数 value = cursor.getInt(columnIndex); break; case Cursor.FIELD_TYPE_NULL://空 break; case Cursor.FIELD_TYPE_STRING://字符串 value = cursor.getString(columnIndex); break; default: break; } map.put(key, value); } resultDatalist.add(map); } return resultDatalist; } }