10分钟理解Android数据库的创建与使用(附详解和示例代码)
来源:互联网 发布:算法设计与分析pdf下载 编辑:程序博客网 时间:2024/06/05 07:59
1.Android数据库简介.
Android系统的framework层集成了Sqlite3数据库,我们知道Sqlite3是一种轻量级的高效存储的数据库。
Sqlite数据库具有以下优点:
(1)零配置,无需安装和配置;
(2)储存在单一磁盘文件中的一个完整的数据库;
(3)数据库文件可以在不同字节顺序的机器间自由共享;
(4)支持数据大小至2TB;
(5)足够小,全部源代码大致3万行C代码,250KB;
(6)比目前流行的大多数数据库的操作要快;
(7)开源。
2.Sqlite 基本操作语句和重要概念
(1)创建数据库
创建数据库实际上并非通过SQL语句来创建,创建数据库可以通过sqlite3 新数据库名 来创建,比如创建一个名为school.db的数据库,在命令行下输入“sqlite3 school.db;”即可。
(2)创建表
创建表的SQL语法为:
create table 表名(字段1 数据约束类型,…,字段n 数据约束类型);
注意:每一条SQL语句都以分号结尾
Sqlite数据库支持的数据库类型大致分为5种,分别是:
NUll 数据值为空
INTEGER 整型
REAL 浮点型数据
TEXT 字符类型,使用数据库编码(UTF-8等)存放
BLOB 只是一个数据块,完全按照输入存放
注意:SQLite3数据库中任何列,除了整形主键列,可以用于存储任何一个存储列的值,SQLite没有单独的布尔存储类型,你可以使用INTEGER的0和1表示true和false,另外,SQLite也没有代表时间和日期的数据类型,可以转化为TEXT或者INTEGER来存储
常用的数据库约束包括以下几种:
PRIMARY KEY 主键 它是非空且唯一的
NOT NULL 非空
UNIQUE 唯一
FOREIGN KEY 外键
CHECK 条件检查
DEFAULT 字段的默认值
下面举例说明创建一个班级表,表中有3个字段,分别是自增的主键id、专业、年份。创建表的SQL语句如下图所示
(3)插入数据
SQL语句插入数据的关键字为insert,完整的格式如下图所示
例如在classes表中插入一条数据,这里我只插入了一条数据中的2个字段,写法如下图
注意:插入的这些数据在表中一定要有对应的字段,不然就会报错!
insert语句支持批量插入数据,比如我要把students表中的数据都导入表stu中,SQL语句为
insert into stu select * from students;
(4)查询语句
Select语句的通用格式如下:
这段语句简单解释一下,columns是要查询的字段,tables表示从哪张表里面查询,where是查询过滤的条件,group by是指按照某个字段分组查询,order by是排序,limit是限制数量语句,下面我会一一解释每个语句需要注意的地方。
1.字段与表的别名
多表查询时查询条件相对复杂,表之间可能会产生相同的字段,这个时候字段前面可以加上表名以区分,别名就是我们可以将classes的表名设置为cls,将classes表中的major字段显示为cmj字段以简化SQL语句。
2.where条件过滤
where语句中常用的逻辑操作符有and、or、not,分别代表与、或、非。
注意where中有一个较为重要的关系操作符叫做like。它是模糊匹配。例如要找到students表中以t开头的所有学生,那么对应的SQL为:
select * from students where name like “t%”;
3.Group by 分组
聚合中有一个重要的功能就是分组。分组就是将得到的结果集按照一定的规则划分为多个组。
由于该功能不常使用,想要了解的朋友自行查阅资料。
4.排序
select结果集的排序使用的是order by字句,排序有升序和降序两种,分别对应asc和desc,order by后面紧跟一个或者多个字段,多个字段间用逗号隔开。
5.数量限定
数量限定需要使用limit语句,数量限定的标准格式如下:
limit 返回的数量 offset 偏移量
例如我们希望从students中索引为3的记录开始索引并且只返回一条语句,SQL如下:
select * from students limit 1 offset 2;
6.distinct去重
distinct用于去除select语句中重复的行,它紧跟在select之后。
(5)update 语句
update 语句用于更新表中的数据,它的格式为:
update table set update_list where predicate;
update_list是要修改的字段以及值,其实就是一个字段赋值语句,形式为:字段名 = 字段值,每个字段赋值语句通过逗号分隔开。后续我会在具体的示例代码中举例,在这就不过多阐述。
(6)delete语句
delete语句的格式如下:
//当满足where的条件时,删除表table中的数据,table是表名delete from table where predicate;
(7)修改表
我们知道,随着项目的演化,最初建立的表可能会面临修改的情况。修改表的SQL语句命令为alter。SQLite中的alter命令并没有实现标准SQL中的所有功能,**它只有修改表名和添加字段两个功能**,**删除字段等功能只能通过重新创建表来实现**。
alter的语法格式为:
alter table tableName {rename to newName | add column 新的字段};
上述的语法表示alter table之后要操作先跟表名,然后rename to newName 和add column 新的字段两者2选1。rename to 是重命名,add column是添加新的字段。
(8)drop 命令
drop命令用于删除物理存储介质。例如删除表、视图、索引、触发器等。drop的语法格式为:
drop {table | view |index |trigger} name;
(9)数据库事务的介绍
事务是一个数据库操作的执行单元。它定义了一条或多条SQL语句,这些语句要么被全部执行,要么全部不执行,它保证了SQL语句的原子性。事务有begin、commit、rollback3个命令,begin表示开始一个事务,commit表示整个事务操作成功,rollback表示回滚到begin之前。格式为:
begin;//SQL语句[commit | rollback];
注意:事务提供了一种保证多条SQL语句能够被执行或者不执行,很大程度上保证了数据库操作的安全性。而在Android中使用事务,也会提升SQL的执行效率。
事务的运用简单举个例子,张三给李四转账400元,银行的数据库中张三的存款金额要减400,李四的存款金额要加400,我们要保证张三扣钱的通过李四收到钱,这个时候就需要用到数据库事务,要么两条SQL语句同时成功,要么同时失败。
(10)Android中封装的数据库帮助接口
我们知道Android的SQLite数据库是由C和C++实现,因此Android在FrameWork层封装了一层Java接口,使得开发人员能够更方便的操作数据库。主要的类型为SQLiteOpenHelper、SQLiteDatabase以及Cusor,不管如何封装,本质上都是通过构建SQL语句并且提交到SQLite中执行。下面详细介绍,Android中创建数据库创建表的所有方法。
3.使用Android的接口创建和操作数据库
一般来说,在Android中创建数据库只需要以下几步:
(1)创建一个Java类继承SQLiteOpenHelper
(2)实现SQLiteOpenHelper的onCreate和onUpdate方法以及构造方法。
(3)通过构造方法创建数据库,需要传入数据库的名称,Context和数据库的版本号。
(4)在onCreate中完成创建表和字段的操作,onUpdate中完成升级操作
(5)通过帮助类的openOrCreateDatabase()方法或者getReadableDatabase()或者getWriteableDatabase()获取到数据库完成数据的操作。
下面附上我的写的一个示例代码,其中封装了判断数据库是否存在某个表,是否存在某个字段的方法
数据库的帮助类,完成了创建数据库,创建表
package com.geocompass.gisdatacollection.database;import android.content.Context;import android.database.Cursor;import android.database.DatabaseErrorHandler;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.os.Environment;import com.geocompass.gisdatacollection.CollectionApplication;import java.io.File;/** * Created by liuxu on 2017/4/7. * 数据库的操作的帮助类 */public class ComplexDatabaseSqlHelper extends SQLiteOpenHelper { private static final String TAG = "ComplexDatabaseSqlHelper"; //数据库的版本号 private static final int DB_VERSION = 1; public SQLiteDatabase getDb() { return db; } private SQLiteDatabase db; //数据库db文件的路径,由调用者传入 private static String mDBPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "giscoll.db"; private static ComplexDatabaseSqlHelper mDBSqlHelper; public ComplexDatabaseSqlHelper(Context context, String DBpath) { super(context, DBpath, null, DB_VERSION); mDBPath = DBpath; if (db == null) { db = SQLiteDatabase.openOrCreateDatabase(DBpath, null); } onCreate(db); } public ComplexDatabaseSqlHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } public ComplexDatabaseSqlHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) { super(context, name, factory, version, errorHandler); } @Override public void onCreate(SQLiteDatabase db) { String CREATE_POINT = "create table tab_point (" + "id integer primary key autoincrement," + "lon double, " + "lat double, " + "type integer) "; String CREATE_INTERSECTION = "create table tab_intersection (" + "inter_id integer primary key autoincrement," + "interLon double, " + "interLat double, " + "interRouteID text) "; String CREATE_ROUTE = "create table tab_route (" + "route_name text," + "startPointID integer, " + "endPointID integer, " + "geometryID text, " + "Geometry text) "; ; //如果不存在该表,则创建该表 if (!tableIsExist("tab_point")) { db.execSQL(CREATE_POINT); } if (!tableIsExist("tab_intersection")) { db.execSQL(CREATE_INTERSECTION); } if (!tableIsExist("tab_route")) { db.execSQL(CREATE_ROUTE); } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } /** * 获取数据库的帮助类 * * @return */ public static ComplexDatabaseSqlHelper getDBSqlHelper() { if (mDBSqlHelper == null) { synchronized (ComplexDatabaseSqlHelper.class) { if (mDBSqlHelper == null) { mDBSqlHelper = new ComplexDatabaseSqlHelper(CollectionApplication.getmContext(), mDBPath); } } } return mDBSqlHelper; } /** * 根据sql查询数据库的方法 * * @param sql * @return */ public Cursor query(String sql) { return db.rawQuery(sql, null); } /** * 执行Sql语句 * * @param sql */ public void execSQL(String sql) { db.execSQL(sql); } /** * 判断表格是否存在 * * @param tableName * @return */ public boolean tableIsExist(String tableName) { boolean result = false; if (tableName == null) { return false; } Cursor cursor = null; try { //db = SQLiteDatabase.openDatabase(this.mDBPath,null,SQLiteDatabase.OPEN_READONLY); String sql = "select count(*) as c from Sqlite_master where type ='table' and name ='" + tableName.trim() + "' "; cursor = db.rawQuery(sql, null); if (cursor.moveToNext()) { int count = cursor.getInt(0); if (count > 0) { result = true; } } cursor.close(); } catch (Exception e) { // TODO: handle exception result = false; } return result; } /** * 判断表中是否包含某个字段 * * @param tableName * @param columnName * @return */ public boolean columnIsExistsInTable(String tableName, String columnName) { boolean result = false; Cursor cursor = null; try { // db = SQLiteDatabase.openDatabase(this.mDBPath, null, SQLiteDatabase.OPEN_READONLY); cursor = db.rawQuery("select * from sqlite_master where name = ? and sql like ?" , new String[]{tableName, "%" + columnName + "%"}); result = null != cursor && cursor.moveToFirst(); } catch (Exception ignored) { } finally { if (null != cursor && !cursor.isClosed()) { cursor.close(); } } return result; } private void open() { if (db != null && !db.isOpen()) db = SQLiteDatabase.openOrCreateDatabase(mDBPath, null); }}
数据库的操作类,完成了对数据库表中数据的插入和查询
package com.geocompass.gisdatacollection.database.manage;import android.database.Cursor;import android.database.SQLException;import android.database.sqlite.SQLiteDatabase;import com.geocompass.gisdatacollection.model.Intersection;import com.geocompass.gisdatacollection.model.Point;import com.geocompass.gisdatacollection.model.Route;import java.util.ArrayList;import java.util.List;/** * Created by liuxu on 2017/4/10. * 封装了对数据库表的增删改查方法 */public class ComplexDBDao { private SQLiteDatabase db; public ComplexDBDao(SQLiteDatabase db) { this.db = db; } /** * 插入一个点到tab_point表 * @param point * @return */ public boolean insert(Point point){ String INSERT_POINT = "INSERT INTO tab_point(lon,lat,type) VALUES (" + point.lon + "," + point.lat + "," + point.point_type + ")"; try{ db.execSQL(INSERT_POINT); }catch(SQLException e){ e.printStackTrace(); return false; } return true; } /** * 插入一个节点到tab_intersection表中 * @param intersection * @return */ public boolean insert(Intersection intersection){ String INSERT_INTERSECTION = "insert into tab_intersection(interLon,interLat,interRouteID) values ("+intersection.interLon+","+intersection.interLat+",'"+ intersection.inter_route_id+"')"; try{ db.execSQL(INSERT_INTERSECTION); }catch(SQLException e){ e.printStackTrace(); return false; } return true; } /** * 插入一条Route到tab_route表中 * @param route * @return */ public boolean insert(Route route){ String INSERT_ROUTE = "insert into tab_route (route_name,startPointID,endPointID,geometryID,Geometry) values('"+route.route_name+ "',"+route.startPointID+","+route.endPointID+",'"+route.geometryID+"','"+route.Geometry+"')"; try{ db.execSQL(INSERT_ROUTE); }catch(SQLException e){ e.printStackTrace(); return false; } return true; } /** * 查询出数据库中所有的Points * @return */ public List<Point> findAllTabPoint(){ String sql_select = "select * from tab_point order by id"; //请补充sql执行语句 Cursor cursor = db.rawQuery(sql_select,null); int IDIndex = cursor.getColumnIndex("id"); int lonIndex = cursor.getColumnIndex("lon"); int latIndex = cursor.getColumnIndex("lat"); int typeIndex = cursor.getColumnIndex("type"); List<Point> list = new ArrayList<>(); while (cursor.moveToNext()) { Point point = new Point(); point.id = cursor.getInt(IDIndex); point.lon = cursor.getDouble(lonIndex); point.lat = cursor.getDouble(latIndex); point.point_type = cursor.getInt(typeIndex); list.add(point); } return list; } /** * 查询出数据库中所有的Intersection * @return */ public List<Intersection> findAllTabIntersection(){ String sql_select = "select * from tab_intersection order by inter_id"; //请补充sql执行语句 Cursor cursor = db.rawQuery(sql_select,null); int interIdIndex = cursor.getColumnIndex("inter_id"); int interLonIndex = cursor.getColumnIndex("interLon"); int interLatIndex = cursor.getColumnIndex("interLat"); int interRouteIDIndex = cursor.getColumnIndex("interRouteID"); List<Intersection> list = new ArrayList<>(); while (cursor.moveToNext()) { Intersection intersection = new Intersection(); intersection.inter_id = cursor.getInt(interIdIndex); intersection.interLon = cursor.getDouble(interLonIndex); intersection.interLat = cursor.getDouble(interLatIndex); intersection.inter_route_id = cursor.getString(interRouteIDIndex); list.add(intersection); } return list; } /** * 查询出数据库中所有的Route * @return */ public List<Route> findAllTabRoute(){ String sql_select = "select * from tab_route "; //请补充sql执行语句 Cursor cursor = db.rawQuery(sql_select,null); int routeNameIndex = cursor.getColumnIndex("route_name"); int startPointIDIndex = cursor.getColumnIndex("startPointID"); int endPointIDIndex = cursor.getColumnIndex("endPointID"); int geometryIDIndex = cursor.getColumnIndex("geometryID"); int geometryIndex = cursor.getColumnIndex("Geometry"); List<Route> list = new ArrayList<>(); while (cursor.moveToNext()) { Route route = new Route(); route.route_name = cursor.getString(routeNameIndex); route.startPointID = cursor.getInt(startPointIDIndex); route.endPointID = cursor.getInt(endPointIDIndex); route.geometryID = cursor.getString(geometryIDIndex); route.Geometry = cursor.getString(geometryIndex); list.add(route); } return list; }}
这些知识都是数据库的基础知识,当然复杂的知识也是在基础知识的基础上拼接起来的,先学好了基础才能谈复杂项目中多个表多个字段数据库的运用!我很喜欢的一句话,不积跬步无以至千里,一直陪伴着我的学习和工作!
不足之处请指正,谢谢!
- 10分钟理解Android数据库的创建与使用(附详解和示例代码)
- 【转】用Fragment创建动态的界面布局(附Android示例代码) - 小吉吉
- Android Fragments 使用详解附代码实例
- java中volatile和transient关键字详解附代码示例
- Android模糊示例-RenderScript-附效果图与代码
- 一分钟理解乐观锁和悲观锁,附深入理解乐观锁与悲观锁
- Android中数据库的创建和使用
- WebView使用与JavaScript交互详解(附完整Demo代码)
- Android创建和使用数据库
- Android surfaceview双缓冲机制和闪屏的解决方法内附代码详解
- 二叉树的创建和遍历(附代码已测试)
- 10 分钟理解 PyTorch 代码
- 线程池、函数指针、 pthread_cond_signal和pthread_cond_wait融合示例详解(附代码)
- android_mvp理解与代码示例
- thinkphp5 10分钟快速理解数据库类和模型
- degegate的理解和使用示例
- degegate的理解和使用示例
- 两分钟理解Android中SP与DP的区别
- 富文本属性 -- NSMutableParagraphStyle与NSParagraphStyle的使用
- 关于在activity中使用popuwindow关闭后引起崩溃的解决方法。
- 区别pointer和references
- openssl堆栈
- openssl内存分配
- 10分钟理解Android数据库的创建与使用(附详解和示例代码)
- 数字签名图文并茂
- Arranging Coins
- 游戏开发从需求出发,注重新趋势变化发展
- MySQL NULL 值处理
- markdown数学公式
- JESD79-4 第4章 SDRAM命令描述与操作(4.25)
- Delphi容器类之---Tlist,TStringlist,THashedStringlist的效率比较
- POJ 2828 Buy Tickets(线段树 )