Android核心基础-5.Android 数据存储与访问-3.使用Sqlite进行数据存储
来源:互联网 发布:淘宝小号用什么注册 编辑:程序博客网 时间:2024/05/22 01:34
续上一博文(Android核心基础-5.Android 数据存储与访问-2.使用SharedPreferences进行数据存储)
三、使用Sqlite进行数据存储
3.1Sqlite数据库简介
SQLite,是一款轻型的数据库,是遵守ACID(原子性、一致性、隔离性、持久性)的关联式数据库管理系统,多用于嵌入式开发中。
SQLite的数据类型:Typelessness(无类型), 可以保存任何类型的数据到你所想要保存的任何表的任何列中. 但它又支持常见的类型比如: NULL, VARCHAR, TEXT, INTEGER, BLOB, CLOB…等. 唯一的例外:integer primary key 此字段只能存储64位整数
3.2Android对Sqlite的支持
- 在Android系统,提供了一个SQLiteOpenHelper抽象类,该类用于对数据库版本进行管理.该类中常用的方法:
- onCreate 数据库创建时执行(第一次连接获取数据库对象时执行)
- onUpgrade 数据库更新时执行(版本号改变时执行)
- onOpen 数据库每次打开时执行(每次打开数据库时调用,在 onCreate,onUpgrade方法之后)
MyHelper.class
package net.dxs.sqlite.dao;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class MyHelper extends SQLiteOpenHelper {// 自定义类继承SQLiteOpenHelper public MyHelper(Context context) {// 由于父类没有无参构造函数, 定义一个构造函数调用父类有参的构造函数 /* * 参数1: Context代表应用程序的环境, 用来确定数据库文件的位置 * 参数2: 数据文件的名字 * 参数3: 用来创建Cursor(结果集)的工厂, 默认传null就可以 * 参数4: 数据库的版本, 后期用来更新数据库, 从1开始 */ super(context, "dxs.db", null, 1); } @Override public void onCreate(SQLiteDatabase db) {// 在数据库文件创建之后执行 System.out.println("onCreate"); db.execSQL("CREATE TABLE account(_id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20))");// 执行SQL语句, 创建表 db.execSQL("ALTER TABLE account ADD balance INTEGER"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// 在数据库版本提升之后执行 System.out.println("onUpgrade"); db.execSQL("ALTER TABLE account ADD balance INTEGER"); }}
3.3Android操作Sqlite的API
Android提供了一个名为SQLiteDatabase的类,该类封装了一些操作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作(这些操作简称为CRUD)。对SQLiteDatabase的学习,我们应该重点掌握execSQL()和rawQuery()方法。 execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句; rawQuery()方法用于执行select语句。
3.3.1execSQL()方法使用
execSQL()方法的使用例子:SQLiteDatabase db = ....;db.execSQL("insert into person(name, age) values('深情小建', 4)");db.close();
执行上面SQL语句会往person表中添加进一条记录,在实际应用中, 语句中的“深情小建”这些参数值会由用户输入界面提供,如果把用户输入的内容原样组拼到上面的insert语句, 当用户输入的内容含有单引号时,组拼出来的SQL语句就会存在语法错误。要解决这个问题需要对单引号进行转义,也就是把单引号转换成两个单引号。有些时候用户往往还会输入像“ & ”这些特殊SQL符号,为保证组拼好的SQL语句语法正确,必须对SQL语句中的这些特殊SQL符号都进行转义,显然,对每条SQL语句都做这样的处理工作是比较烦琐的。 SQLiteDatabase类提供了一个重载后的execSQL(String sql, Object[] bindArgs)方法,使用这个方法可以解决前面提到的问题,因为这个方法支持使用占位符参数(?)。
使用例子如下:
SQLiteDatabase db = ....;db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"深情小建", 4}); db.close();
execSQL(String sql, Object[] bindArgs)方法的第一个参数为SQL语句,第二个参数为SQL语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。
3.3.2rawQuery()方法使用
SQLiteDatabase的rawQuery() 用于执行select语句,
使用例子如下:
SQLiteDatabase db = ....;Cursor cursor = db.rawQuery(“select * from person”, null);while (cursor.moveToNext()) { int personid = cursor.getInt(0); //获取第一列的值,第一列的索引从0开始 String name = cursor.getString(1);//获取第二列的值 int age = cursor.getInt(2);//获取第三列的值}cursor.close();db.close();
rawQuery()方法的第一个参数为select语句;第二个参数为select语句中占位符参数的值,如果select语句没有使用占位符,该参数可以设置为null。
带占位符参数的select语句使用例子如下:
Cursor cursor = db.rawQuery("select * from person where name like ? and age=?", new String[]{"%小建%", "4"});
Cursor是结果集游标,用于对结果集进行随机访问,如果大家熟悉jdbc, 其实Cursor与JDBC中的ResultSet作用很相似。
使用moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。
另外Cursor 还有常用的moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true )。
moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true )和moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true ) 。
3.3.3其他封装好的方法
除了execSQL()和rawQuery()方法, SQLiteDatabase还专门提供了对应于添加、删除、更新、查询的操作方法:
insert() 增加数据delete() 删除数据update() 修改数据query() 查询数据
这些方法实际上是给那些不太了解SQL语法的开发者使用的,对于熟悉SQL语法的程序员而言,直接使用execSQL()和rawQuery()方法执行SQL语句就能完成数据的添加、删除、更新、查询操作。
3.3.4事务
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。
使用例子如下:
SQLiteDatabase db = ....;db.beginTransaction();//开始事务try { db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"深情小建", 4}); db.execSQL("update person set name=? where personid=?", new Object[]{"小建", 1}); db.setTransactionSuccessful();//调用此方法会在执行到endTransaction() 时提交当前事务,如果不调用此方法会回滚事务} finally { db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务} db.close();
上面两条SQL语句在同一个事务中执行。
AccountDao.class
package net.dxs.sqlite.dao;import java.util.ArrayList;import java.util.List;import net.dxs.sqlite.bean.Account;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;public class AccountDao { private MyHelper helper; public AccountDao(Context context) { helper = new MyHelper(context); } public void insert(Account a) { // 获取SQLiteDatabase对象 SQLiteDatabase db = helper.getWritableDatabase(); // 执行一条SQL语句 db.execSQL("insert into account(name,balance) values(?,?)", new Object[] { a.getName(), a.getBalance() }); // 关闭 db.close(); } public void delete(int id) { // 获取SQLiteDatabase对象 SQLiteDatabase db = helper.getWritableDatabase(); //执行删除语句 db.execSQL("delete from account where _id=?", new Object[] { id }); // 关闭 db.close(); } public void update(Account a) { // 获取SQLiteDatabase对象 SQLiteDatabase db = helper.getWritableDatabase(); //执行删除语句 db.execSQL("update account set name=?,balance=? where _id=?", new Object[] { a.getName(), a.getBalance(), a.getId() }); // 关闭 db.close(); } public Account query(int id) { // 先调用getWriteableDatabse(), 如果出了异常, 就开一个只读的 SQLiteDatabase db = helper.getReadableDatabase(); // 执行查询语句, 得到结果集 Cursor c = db.rawQuery("select name,balance from account where _id=?", new String[] { String.valueOf(id) }); Account a = null; if (c.moveToNext()) {// 判断结果集是否包含下一条数据, 如果包含, 指针自动向后移动 String name = c.getString(0);// 从结果集中获取数据(根据列的索引获取) int balance = c.getInt(c.getColumnIndex("balance"));// 从结果集中获取数据(先根据列名获取索引, 再根据索引获取数据) a = new Account(id, name, balance);// 创建对象, 把数据设置到对象中 return a; } // 关闭 c.close(); db.close(); return null;// 返回对象 } public List<Account> queryAll() { SQLiteDatabase db = helper.getReadableDatabase(); Cursor c = db.rawQuery("select * from account", null);// 查询表中所有数据 List<Account> list = new ArrayList<Account>(); while (c.moveToNext()) { int id = c.getInt(0);// 获取表中的第一列(索引从0开始) String name = c.getString(1); int balance = c.getInt(2); list.add(new Account(id, name, balance));// 把表中的数据封装成对象 } c.close(); db.close(); return list; } public Cursor queryCursor() { SQLiteDatabase db = helper.getReadableDatabase(); return db.rawQuery("select * from account order desc balance", null); } /** * * @param pageSize 每页显示多少条 * @param pageNum 要第几页的数据 * @return */ public List<Account> queryPage(int pageSize, int pageNum) { String index = (pageNum - 1) * pageSize + ""; // 翻页时的起始索引 String count = pageSize + ""; // 查询多少条数据 List<Account> list = new ArrayList<Account>(); SQLiteDatabase db = helper.getReadableDatabase(); Cursor c = db.rawQuery("select * from account limit ?,?", new String[]{index,count});// Cursor c = db.query("account", null, null, null, null, null, null, index + "," + count); while (c.moveToNext()) { int id = c.getInt(0); String name = c.getString(1); int balance = c.getInt(2); list.add(new Account(id, name, balance)); } c.close(); db.close(); return list; } public int queryCount() { SQLiteDatabase db = helper.getReadableDatabase(); Cursor c = db.rawQuery("select count(*) from account", null); c.moveToNext(); int count = c.getInt(0); c.close(); db.close(); return count; } public void remit(int fromId, int toId, int amount) { SQLiteDatabase db = helper.getReadableDatabase(); try { db.beginTransaction(); //开启事务 db.execSQL("update account set balance=balance-? where _id=?", new Object[] { amount, fromId }); db.execSQL("update account set balance=balance+? where _id=?", new Object[] { amount, toId }); db.setTransactionSuccessful();// 设置事务成功标记 } finally { db.endTransaction();//结束事务 db.close(); } }}
3.4Android sqlite3工具的使用
这里提供下我百度网盘的下载链接(SQLiteExpert)
sqlite3 <数据库名称> 进入数据库操作模式 eg: sqlite3 contacts.dbtables 查看所有的表 eg: tableschema 查看查看库中所有表的DDL语句 eg: schema help 查看帮助 eg: helpheaders on/off 显示表头 默认off eg: headers onmode list|column|insert|line|tabs|tcl|csv 改变输出格式 eg: mode columnnullValue NULL空值数据显示问题 eg: nullValue NULLdump <表名> 生成形成表的SQL脚本 eg: dump persondump 生成整个数据库的SQL脚本 eg: dumpexit 退出sqlite操作模式 eg: exit
3.5写在最后
一.SQLite数据库** 1.SQLite数据库的特点 安卓手机自带, 小巧, 适合在手机中使用 不区分数据类型(主键除外) SQL语句和MySQL几乎相同 SQLite不使用JDBC连接, 使用的是Android自有的API 每个数据库对应一个文件 * 2.创建数据库 定义类继承SQLiteOpenHelper, 实现onCreate(), onUpgrade() 创建该类对象, 调用getWritableDatabse()或者getReadableDatabse() 情况1: 数据库文件不存在, 创建文件, 打开数据库连接(得到SQLiteDatabase对象), 执行onCreate()方法 情况2: 数据库文件存在, 版本号没变, 打开数据库连接 情况3: 数据库文件存在, 版本号提升, 升级数据库, 打开数据库连接,执行onUpgrade()方法 情况4: 数据库文件存在, 版本号降低, 执行onDowngrade()方法, 方法中默认会抛出一个异常 * 3.创建表或修改表 SQLiteDatabase类的execSQL()方法可以执行一条SQL语句 如果希望创建数据库的时候就创建一些表, 那么这个操作就可以在onCreate()方法中执行 如果希望在数据库升级的时候做类似修改表添加表的操作, 可以在onUpgrade()方法中执行*** 4.增删改查 execSQL()方法可以进行增删改操作 rawQuery()执行查询操作, 得到Cursor, 调用moveToNext()判断是否包含数据, 调用getString(), getInt()等方法获取数据 insert(), delete(), update(), query() 四个方法内部也是调用execSQL()和rawQuery()的, 它们在ContentProvider中使用更方便(另一篇博文讲) * 5.事务管理 beginTransaction() 开启事务 setTransactionSuccessful() 设置事务成功标记 endTransaction() 结束事务. 事务结束的时候, 会把最后一个成功标记之前的操作提交, 成功标记之后的操作回滚
Account.class
package net.dxs.sqlite.bean;public class Account { private Integer id; private String name; private Integer balance; public Account() { } public Account(String name, Integer balance) { super(); this.name = name; this.balance = balance; } public Account(Integer id, String name, Integer balance) { super(); this.id = id; this.name = name; this.balance = balance; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getBalance() { return balance; } public void setBalance(Integer balance) { this.balance = balance; } @Override public String toString() { return "Account [id=" + id + ", name=" + name + ", balance=" + balance + "]"; }}
SQLiteTest.class
package net.dxs.sqlite.test;import java.util.List;import java.util.Random;import net.dxs.sqlite.bean.Account;import net.dxs.sqlite.dao.AccountDao;import net.dxs.sqlite.dao.MyHelper;import android.test.AndroidTestCase;public class SQLiteTest extends AndroidTestCase { // 测试类中的Context对象是在测试类创建之后(构造函数执行之后), 虚拟机自动调用setContext()传入的, 如果在成员变量位置就getContext()则拿不到 private AccountDao dao; @Override protected void setUp() throws Exception {// 测试方法执行之前执行 dao = new AccountDao(getContext()); } @Override protected void tearDown() throws Exception {// 测试方法执行之后执行 } public void testCreateDB(){ new MyHelper(getContext()).getWritableDatabase();// 获取数据库对象 /* * 情况1: 数据库文件不存在, 创建文件, 打开数据库连接(得到SQLiteDatabase对象), 执行onCreate()方法 * 情况2: 数据库文件存在, 版本号没变, 打开数据库连接 * 情况3: 数据库文件存在, 版本号提升, 升级数据库, 打开数据库连接,执行onUpgrade()方法 * 情况4: 数据库文件存在, 版本号降低, 执行onDowngrade()方法, 方法中默认会抛出一个异常 */ } public void testInsert(){ for (int i = 0; i < 100; i++) { dao.insert(new Account("深情小建"+i, new Random().nextInt(10000))); } } public void testDelete(){ dao.delete(20); } public void testUpdate(){ dao.update(new Account(1,"深情小建", 12000)); dao.update(new Account(2,"刘德华", 12000)); dao.update(new Account(3,"武状元", 12000)); } public void testQuery(){ System.out.println(dao.query(1)); System.out.println(dao.query(3)); System.out.println(dao.query(4)); System.out.println(dao.query(5)); } public void testQueryAll(){ List<Account> list = dao.queryAll(); for (Account account : list) { System.out.println(account); } } public void testQueryPage(){ List<Account> list = dao.queryPage(20, 1); for (Account account : list) { System.out.println(account); } } public void testQueryCount(){ System.out.println(dao.queryCount()); } public void testRemit(){ dao.remit(2, 1, 200); }}
- Android核心基础-5.Android 数据存储与访问-3.使用Sqlite进行数据存储
- Android核心基础-5.Android 数据存储与访问-2.使用SharedPreferences进行数据存储
- Android核心基础-5.Android 数据存储与访问-1.使用文件进行数据存储
- Android核心基础-5.Android 数据存储与访问-4.ContentProvider 内容提供者
- [Android SQLite]数据存储与访问 - SharedPreferences
- Android核心基础-5.Android 数据存储与访问-4.ContentProvider 内容提供者-示例(监听短信)
- Android核心基础-5.Android 数据存储与访问-4.ContentProvider 内容提供者-示例(操作联系人)
- [Android SQLite]数据存储与访问 - 内部存储
- [Android SQLite]数据存储与访问 - 外部存储
- android基础---使用文件进行数据存储
- android使用sqlite存储数据
- Android 数据存储 &SQLite使用,
- Android使用SQLite存储数据
- Android数据存储与访问之使用SharedPreferences进行数据存储
- Android开发之数据存储与访问(3)-SQLite数据库
- Android开发之数据存储与访问(4)-SQLite数据库
- android数据存储--SQLite
- Android数据存储---SQLite
- JAVA 学习第3天(2)
- javascript学习实录 之二(数组操作等等utils)
- android looper
- Dijskra(有误)
- 移动Web前端开发_横向UL以及自适应屏幕_div定位的方式居中
- Android核心基础-5.Android 数据存储与访问-3.使用Sqlite进行数据存储
- UVa 1556 - Disk Tree
- javascript学习实录 之一 -
- 极限方程式程序和27级存档_android
- OC 数字对象和字符串对象
- json-lib 的maven dependency
- Android模仿微信语音聊天功能
- 2015年阿里实习生面试总结
- 数据结构 - 哈希函数