问题一:使用GreenDao如何实现创建表、关联表(一对一,一对多,多对多)?
第一种: 使用SharedPreferences存储数据
1).跨进程调用
2).SharedPreferences 的commit和apply的区别
3).优缺点,使用场景
适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码等
核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data//shared_prefs目录下。
Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。
Context.MODE_WORLD_READABLE: 指定该SharedPreferences数据能被其他应用程序读,但不能写。
Context.MODE_WORLD_WRITEABLE: 指定该SharedPreferences数据能被其他应用程序读,写
SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。无法进行条件查询,只能在不复杂的存储需求下使用,比如保存配置信息等。
SharedPreferences 的commit和apply的区别
public void SaveData() {
//指定操作的文件名称
SharedPreferences share = context.getSharedPreferences(SILENAME, MODE_PRIVATE);
SharedPreferences.Editor edit = share.edit(); //编辑文件
edit.putInt("age", 22); //根据键值对添加数据
edit.putString("name", "LJie");
edit.commit(); //保存数据信息
}
public void LoadData() {
//指定操作的文件名称
SharedPreferences share = getSharedPreferences(SILENAME, MODE_PRIVATE);
tv1.setText("作者:"+share.getString("name", "信息为空..."));
tv2.setText("年龄:"+share.getInt("age", 0));
}
commit是原子提交到数据库,所以从提交数据到存在Disk中都是同步过程,中间不可打断。
apply方法的原子操作是原子提交的内存中,而非数据库,所以在提交到内存中时不可打断,之后再异步提交数据到数据库中,因此也不会有相应的返回值。
所有commit提交是同步过程,效率会比apply异步提交的速度慢,但是apply没有返回值,永远无法知道存储是否失败。
在不关心提交结果是否成功的情况下,优先考虑apply方法。
第二种: 文件存储数据
应用场景:
一。录音文件,图片
二。服务器的json和网络请求json数据
1)。权限问题
2)。存储的路径,内部和外部
1.使用内部存储 : 文件默认存储位置:/data/data/包名/files/文件名
2.读取一个内部存储的私有文件:( /data/data/包名/cache )是一个应用专门来保存临时缓存文件的内存目录。
3.使用外部存储:0/
核心原理: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。具体有以下值可选:
第三种:SQLite存储数据(重点)
1.基本的语句
2.数据库迁移和数据库升级
3.数据库优化
4.数据库的位置和查看工具
5.多张表,内联和外联,greedao的学习
6.数据库实务操作
7.数据不能乱,同步原理
8.数据库加密
9.android 数据库islock解决方案
10.数据库备份
11.应用场景
防止张数据,其实就是为了同步,多线程访问带来的问题
1:多线程 单例 SQLiteOpenHelper 可以同时读和写。
2.多线程访问单列是否是安全的
对象是安全的,和写法有关,可以保证只生产一个对象,
2.多线程 多个对象 SQLiteOpenHelper 不能同时读写(可以同时读)。
SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧
应用场景:
1.天气预报
2.断点下载
3.手机资料备份
4.松鼠整理首页状态显示
Android sqlite3数据库管理工具
Android SDK的tools目录下提供了一个sqlite3.exe工具,这是一个简单的sqlite数据库管理工具。开发者可以方便的使用其对sqlite数据库进行命令行的操作。
程序运行生成的*.db文件一般位于"/data/data/项目名(包括所处包名)/databases/*.db",因此要对数据库文件进行操作需要先找到数据库文件:
1、进入shell 命令
adb shell
2、找到数据库文件
#cd data/data
#ls --列出所有项目
#cd project_name --进入所需项目名
#cd databases
#ls --列出现寸的数据库文件
3、进入数据库
#sqlite3 test_db --进入所需数据库
会出现类似如下字样:
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
至此,可对数据库进行sql操作。
4、sqlite常用命令
>.databases --产看当前数据库
>.tables --查看当前数据库中的表
>.help --sqlite3帮助
>.schema --各个表的生成语句
来源: https://www.cnblogs.com/ITtangtang/p/3920916.html
三、解决方案
1.将数据加密后再写入数据库:
http://blog.csdn.net/guolin_blog/article/details/11952409
1)优点:
a. 实现数据加密快速,只需添加两个方法
一是:对明文数据进行加密返回密文数据
二是:对密文数据进行解密返回明文数据
b. 程序无需进行太大变动,仅在对数据进行添加,修改,删除,查询时。针对指定的表字段进行修改进行加密,解密的字段即可。
2)不足:
a. 由于对数据进行了加密。所以为了看到明文,必须密文进行解密。因此会增加处理器的消耗。因终端手机的处理能力有限,可能会出现处理数据缓慢的现象发生。
b. 仅仅对数据进行了加密,还是可以看到数据表的sql语句,可能猜测到表的作用。另外,如果没有对一个表中的所有字段加密,则可以看没有加密的明文数据。
这种方式使用简单,在入库/出库只需要将字段做对应的加解密操作即可,一定程度上解决了将数据赤裸裸暴露的问题,这种只是靠存取数据库时通过自己的一些算法加密解密,一定程度上会影响性能。
这种方式并不是彻底的加密,因为数据库的表结构等信息还是能被查看到。另外写入数据库的内容加密后,搜索也是个问题。
2. 对数据库文件加密
将整个数据库整个文件加密,这种方式基本上能解决数据库的信息安全问题。目前已有的SQLite加密基本都是通过这种方式实现的。
目前流行的是一款开源的SQLite加密工具 SQLCipher ,微信也在使用。 SQLCipher是完全开源的,其代码托管在github上。SQLCipher使用256-bit AES加密,由于其基于免费版的SQLite,主要的加密接口和SQLite是相同的,也增加了一些自己的接口。它有一个缺点就是使用该库之后会导致Apk会变大6M左右。下面就是具体介绍SQLCipher的使用方法。
greenDAO 智能代码生成 10K+ 首选
GitHub
greenDAO与其他常见的ORM框架不同,其原理不是根据反射进行数据库的各项操作
,而是一开始就人工生成业务需要的Model和DAO文件
,业务中可以直接调用相应的DAO文件进行数据库操作,从而避免了因反射带来的性能损耗和效率低下。
以查询为例,其首先是创建数据库,然后在SQLiteOpenHelper.onCreate
方法中根据已生成的model创建所有的表,而db.query其实就是Android原生的查询操作
,只不过参数是经过DAO文件处理过的,无需手动匹配。
由于需要人工生成model和DAO文件,所以greenDAO的配置就略显复杂。
优点:效率高,速度快,文件较小,占用更少的内存,操作实体灵活
缺点:学习成本较高。
ORMLite 注解+反射 1.5K 通用
GitHub
基于注解和反射
的的方式,导致ormlite性能有着一定的损失(运行时注解其实也是利用了反射的原理)
OrmLite 不是 Android 平台专用的ORM框架,它是Java ORM
。支持JDBC连接,Spring以及Android平台。语法中广泛使用了运行时注解。
优点:文档较全面,社区活跃,有好的维护,使用简单,易上手。
缺点:基于反射,效率较低(GreenDAO比OrmLite要快几乎4.5倍)
LitePal 注解+反射 5K 最简单
GitHub
An Android library that makes developers use SQLite database extremely easy.
- LitePal通过LitePal.xml文件获取数据库的名称、版本号以及表,然后自动创建数据库和表,以及表数据类型和非空约束等。
- 要执行增删改查操作的数据model都会继承DataSupport,最后将查询得到的数据转换成List并返回。
- LitePal不管是创建数据库、表还是执行增删改查,都是根据Model的类名和属性名,每次都需要进行反射拼装,然后调用Android原生的数据库操作,或者直接执行sql语句,实现相应的功能。
特点
来源: https://www.cnblogs.com/baiqiantao/p/9492180.html#ORMLite注解+反射1.5K通用
- 根据反射进行数据库的各项操作(速度比GreenDAO要慢很多很多)
- 采用对象关系映射(ORM)的模式
- 很“轻”,jar包只有100k不到
- 使用起来比较简单
- 支持直接用sql原始语句实现查询的api方法
sugar 2.5K
GitHub
官网
Insanely easy way to work with Android Database.
SugarORM 是 Android 平台专用ORM。提供简单易学的APIs,可以很容易的处理1对1和1对多的关系型数据,并通过3个函数save(), delete() 和 find() (或者 findById()) 来简化CRUD基本操作。
第四种: 使用ContentProvider存储数据
1.和fileProvider的区别
2.怎么创建和共享数据给别人
3.优点:跨进程
Android这个系统和其他的操作系统还不太一样,我们需要记住的是,数据在Android当中是私有的,当然这些数据包括文件数据和数据库数据 以及一些其他类型的数据。那这个时候有读者就会提出问题,难道两个程序之间就没有办法对于数据进行交换?Android这么优秀的系统不会让这种情况发生 的。解决这个问题主要靠ContentProvider。一个Content Provider类实现了一组标准的方法接口,从而能够让其他的应用保存或读取此Content Provider的各种数据类型。也就是说,一个程序可以通过实现一个Content Provider的抽象接口将自己的数据暴露出去。外界根本看不到,也不用看到这个应用暴露的数据在应用当中是如何存储的,或者是用数据库存储还是用文件 存储,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和程序里的数据打交道,可以读取程序的数据,也可以删除程序的数 据,当然,中间也会涉及一些权限的问题。
一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProviders是以类似数据 库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基 本一样,只不过是采用URI来表示外界需要访问的“数据库”。
Content Provider提供了一种多应用间数据共享的方式,比如:联系人信息可以被多个应用程序访问。
Content Provider是个实现了一组用于提供其他应用程序存取数据的标准方法的类。 应用程序可以在Content Provider中执行如下操作: 查询数据 修改数据 添加数据 删除数据
标准的Content Provider: Android提供了一些已经在系统中实现的标准Content Provider,比如联系人信息,图片库等等,你可以用这些Content Provider来访问设备上存储的联系人信息,图片等等。
来源: http://www.cnblogs.com/pxsbest/p/5068482.html
第五种: 网络存储数据
前面介绍的几种存储都是将数据存储在本地设备上,除此之外,还有一种存储(获取)数据的方式,通过网络来实现数据的存储和获取。
总结:
偏好设置简单
哪些跨进程:文件,网络,contentprovider
不错的网站
http://www.360doc.com/content/11/0930/19/6938655_152478139.shtml
问题:
如何将图片存入数据库中,并从数据库中取出图片
内连接:
指连接结果仅包含符合连接条件的行,参与连接的两个表都应该符合连接条件。
外连接:
连接结果不仅包含符合连接条件的行同时也包含自身不符合条件的行。包括左外连接、右外连接和全外连接。
左外连接:
左边表数据行全部保留,右边表保留符合连接条件的行
右外连接:
右边表数据行全部保留,左边表保留符合连接条件的行
全外连接:
左外连接 union 右外连接
简单来讲,随便来个例子:
A表 B表
id name id name
1 a 1 b
2 b 3 c
4 c
内连接就是左表和右表相同的数据:交集
select * from A inner join B on A.id=B.id
id name id name
1 a 1 b
外连接分为:左外连接、右外连接、全外连接
左外连接就是以左表为准,去匹配右表,左表有多少条数据,结果就是多少条数据
select * from A left join B on A.id=B.id
id name id name
1 a 1 b
2 b null null
4 c null null
右外连接就是与左外连接反之,以右表为准,去匹配左表,右表有多少条数据,结果就是多少条数据
select * from A right join B on A.id=B.id
id name id name
1 a 1 b
null null 3 c
全外连接数据条数不一定,相当与是左外连接 和右外连接 的综合
select * from A full join B on A.id=B.id
id name id name
1 a 1 b
2 b null null
null null 3 c
4 c null null
希望你能明白!!!
来源:
好的网站:列子举例
http://blog.csdn.net/liuhe688/article/details/6715983
应用:
1.天气预报
2.车载记录仪
1.数据库基本法则:创建,打开和封装
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- //打开或创建test.db数据库
- SQLiteDatabase db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null);
- db.execSQL("DROP TABLE IF EXISTS person");
- //创建person表
- db.execSQL("CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT)");
- Person person = new Person();
- person.name = "john";
- person.age = 30;
- //插入数据
- db.execSQL("INSERT INTO person VALUES (NULL, ?, ?)", new Object[]{person.name, person.age});
-
- person.name = "david";
- person.age = 33;
- //ContentValues以键值对的形式存放数据
- ContentValues cv = new ContentValues();
- cv.put("name", person.name);
- cv.put("age", person.age);
- //插入ContentValues中的数据
- db.insert("person", null, cv);
-
- cv = new ContentValues();
- cv.put("age", 35);
- //更新数据
- db.update("person", cv, "name = ?", new String[]{"john"});
-
- Cursor c = db.rawQuery("SELECT * FROM person WHERE age >= ?", new String[]{"33"});
- while (c.moveToNext()) {
- int _id = c.getInt(c.getColumnIndex("_id"));
- String name = c.getString(c.getColumnIndex("name"));
- int age = c.getInt(c.getColumnIndex("age"));
- Log.i("db", "_id=>" + _id + ", name=>" + name + ", age=>" + age);
- }
- c.close();
-
- //删除数据
- db.delete("person", "age < ?", new String[]{"35"});
-
- //关闭当前数据库
- db.close();
-
- //删除test.db数据库
- // deleteDatabase("test.db");
- }
在执行完上面的代码后,系统就会在/data/data/[PACKAGE_NAME]/databases目录下生成一个“test.db”的数据库文件,如图:
2.SQLiteOpenHelper也就是所谓的SQLiteDBhelper目的主要是更好的封装性(处理数据库)
上面就是SQLite的基本应用,但在实际开发中,为了能够更好的管理和维护数据库
我们会封装一个继承自SQLiteOpenHelper类的数据库操作类,然后以这个类为基础,再封装我们的业务逻辑方法。
Cursor结果集需要注意些什么:一个最需要注意的是,在我们的结果集中必须要包含一个“_id”的列,否则SimpleCursorAdapter就会翻脸不认人,为什么一定要这样呢?因为这源于SQLite的规范,主键以“_id”为标准。解决办法有三:第一,建表时根据规范去做;第二,查询时用别名,例如:SELECT id AS _id FROM person;第三,在CursorWrapper里做文章:
下面我们先来看一下DBHelper:用于;创建数据库和更新打开数据库
[java] view plaincopy
- package com.scott.db;
-
- import android.content.Context;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
-
- public class DBHelper extends SQLiteOpenHelper {
-
- private static final String DATABASE_NAME = "test.db";
- private static final int DATABASE_VERSION = 1;
-
- public DBHelper(Context context) {
- //CursorFactory设置为null,使用默认值
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- //数据库第一次被创建时onCreate会被调用
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE IF NOT EXISTS person" +
- "(_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER, info TEXT)");
- }
-
- //如果DATABASE_VERSION值被改为2,系统发现现有数据库版本不同,即会调用onUpgrade
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("ALTER TABLE person ADD COLUMN other STRING");
- }
- }
来源:
我们需要一个DBManager,来封装我们所有的业务方法(增删改查),代码如下:
数据的添加
2种方式:ContentValue和直接的sql语句!
1.使用insert方法
1 2 3 |
ContentValues cv = new ContentValues(); //实例化一个ContentValues用来装载待插入的数据cv.put("username","Jack Johnson");//添加用户名 cv.put( "password" , "iLovePopMusic" ); //添加密码 db.insert( "user" , null ,cv); //执行插入操作 |
2.使用execSQL方式来实现
1 2 |
String sql = "insert into user(username,password) values ( 'Jack Johnson' , 'iLovePopMuisc' ); //插入操作的SQL语句 db.execSQL(sql); //执行SQL语句 |
数据的删除
同样有2种方式可以实现
1 2 3 |
String whereClause = "username=?" ; //删除的条件 String[] whereArgs = { "Jack Johnson" }; //删除的条件参数 db.delete( "user" ,whereClause,whereArgs); //执行删除 |
使用execSQL方式的实现
1 2 |
String sql = "delete from user where username='Jack Johnson'" ; //删除操作的SQL语句 db.execSQL(sql); //执行删除操作 |
数据修改
同上,仍是2种方式
1 2 3 4 5 |
ContentValues cv = new ContentValues(); //实例化ContentValues cv.put( "password" , "iHatePopMusic" ); //添加要更改的字段及内容 String whereClause = "username=?" ; //修改条件 String[] whereArgs = { "Jack Johnson" }; //修改条件的参数 db.update( "user" ,cv,whereClause,whereArgs); //执行修改 |
使用execSQL方式的实现
1 2 |
String sql = "update [user] set password = 'iHatePopMusic' where username='Jack Johnson'" ; //修改的SQL语句 db.execSQL(sql); //执行修改 来源: 注意事项 |
[java] view plaincopy实现代码用Cursor的moveToNext函数对查询到的结果集进行遍历。
查询的函数还有:
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, Stringlimit);
db.query(String distinct, String table, String[] columns, Stringselection, String[] selectionArgs, String groupBy, String having, StringorderBy, String
来源:
1 2 3 4 5 6 7 8 |
Cursor c = db.query( "user" , null , null , null , null , null , null ); //查询并获得游标 if (c.moveToFirst()){ //判断游标是否为空 for ( int i= 0 ;i c.move(i); //移动到指定记录 String username = c.getString(c.getColumnIndex( "username" ); String password = c.getString(c.getColumnIndex( "password" )); } } |
通过rawQuery实现的带参数查询
1 2 3 4 |
Cursor c = db.rawQuery( "select * from user where username=?" , new Stirng[]{ "Jack Johnson" }); if (cursor.moveToFirst()) { String password = c.getString(c.getColumnIndex( "password" )); } |
bt中的查询
- package com.scott.db;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import android.content.ContentValues;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
-
- public class DBManager {
- private DBHelper helper;
- private SQLiteDatabase db;
-
- public DBManager(Context context) {
- helper = new DBHelper(context);
- //因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory);
- //所以要确保context已初始化,我们可以把实例化DBManager的步骤放在Activity的onCreate里
- db = helper.getWritableDatabase();
- }
-
- /**
- * add persons
- * @param persons
- */
- public void add(List persons) {
- db.beginTransaction(); //开始事务
- try {
- for (Person person : persons) {
- db.execSQL("INSERT INTO person VALUES(null, ?, ?, ?)", new Object[]{person.name, person.age, person.info});
- }
- db.setTransactionSuccessful(); //设置事务成功完成
- } finally {
- db.endTransaction(); //结束事务
- }
- }
-
- /**
- * update person's age
- * @param person
- */
- public void updateAge(Person person) {
- ContentValues cv = new ContentValues();
- cv.put("age", person.age);
- db.update("person", cv, "name = ?", new String[]{person.name});
- }
-
- /**
- * delete old person
- * @param person
- */
- public void deleteOldPerson(Person person) {
- db.delete("person", "age >= ?", new String[]{String.valueOf(person.age)});
- }
-
- /**
- * query all persons, return list
- * @return List
- */
- public List query() {
- ArrayList persons = new ArrayList();
- Cursor c = queryTheCursor();
- while (c.moveToNext()) {
- Person person = new Person();
- person._id = c.getInt(c.getColumnIndex("_id"));
- person.name = c.getString(c.getColumnIndex("name"));
- person.age = c.getInt(c.getColumnIndex("age"));
- person.info = c.getString(c.getColumnIndex("info"));
- persons.add(person);
- }
- c.close();
- return persons;
- }
-
- /**
- * query all persons, return cursor
- * @return Cursor
- */
- public Cursor queryTheCursor() {
- Cursor c = db.rawQuery("SELECT * FROM person", null);
- return c;
- }
-
- /**
- * close database
- */
- public void closeDB() {
- db.close();
- }
- }
为了方便我们面向对象的使用数据,我们建一个Person类,对应person表中的字段,如下:
直接操作实体类
[java] view plaincopy
- package com.scott.db;
-
- public class Person {
- public int _id;
- public String name;
- public int age;
- public String info;
-
- public Person() {
- }
-
- public Person(String name, int age, String info) {
- this.name = name;
- this.age = age;
- this.info = info;
- }
- }
- public class MainActivity extends Activity {
-
- private DBManager mgr;
- private ListView listView;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- listView = (ListView) findViewById(R.id.listView);
- //初始化DBManager
- mgr = new DBManager(this);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- //应用的最后一个Activity关闭时应释放DB
- mgr.closeDB();
- }
-
- public void add(View view) {
- ArrayList persons = new ArrayList();
-
- Person person1 = new Person("Ella", 22, "lively girl");
- Person person2 = new Person("Jenny", 22, "beautiful girl");
- Person person3 = new Person("Jessica", 23, "sexy girl");
- Person person4 = new Person("Kelly", 23, "hot baby");
- Person person5 = new Person("Jane", 25, "a pretty woman");
-
- persons.add(person1);
- persons.add(person2);
- persons.add(person3);
- persons.add(person4);
- persons.add(person5);
-
- mgr.add(persons);
- }
-
- public void update(View view) {
- Person person = new Person();
- person.name = "Jane";
- person.age = 30;
- mgr.updateAge(person);
- }
-
- public void delete(View view) {
- Person person = new Person();
- person.age = 30;
- mgr.deleteOldPerson(person);
- }
-
- public void query(View view) {
- List persons = mgr.query();
- ArrayList
- for (Person person : persons) {
- HashMap map = new HashMap();
- map.put("name", person.name);
- map.put("info", person.age + " years old, " + person.info);
- list.add(map);
- }
- SimpleAdapter adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2,
- new String[]{"name", "info"}, new int[]{android.R.id.text1, android.R.id.text2});
- listView.setAdapter(adapter);
- }
-
- public void queryTheCursor(View view) {
- Cursor c = mgr.queryTheCursor();
- startManagingCursor(c); //托付给activity根据自己的生命周期去管理Cursor的生命周期
- CursorWrapper cursorWrapper = new CursorWrapper(c) {
- @Override
- public String getString(int columnIndex) {
- //将简介前加上年龄
- if (getColumnName(columnIndex).equals("info")) {
- int age = getInt(getColumnIndex("age"));
- return age + " years old, " + super.getString(columnIndex);
- }
- return super.getString(columnIndex);
- }
- };
- //确保查询结果中有"_id"列
- SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2,
- cursorWrapper, new String[]{"name", "info"}, new int[]{android.R.id.text1, android.R.id.text2});
- ListView listView = (ListView) findViewById(R.id.listView);
- listView.setAdapter(adapter);
- }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
实验说明:
Android中使用SQLite数据库时,需要用adb来辅助调试,如果想在windows下的cmd命令行中使用adb,
必须先配置环境变量,我这里是配的用户环境变量path: C:\Program Files\android-sdk\platform-tools;
数据库sqilte调试工具
SQLite Expert Professional(SQLite可视化管理工具)V3.4.34.2256...
问题:
在cmd命令中查询数据库,给数据库建立表格,…………等等!
知识:
Cursor的方法
注意:Cursor中游标的下一个,当前个可能为空
为了达到录音的自动话
一录完就看是播放,录制显示时间10秒
不用每次都存放在SD卡中,可以存放临时的文件
每个程序存放位置都有,在和偏好设置一样的,在data分区里面
================================================
问题:
插入数据库和添加数据库有什么区别
音乐播发器中查询的方法!
好的网站:列子举例
http://blog.csdn.net/liuhe688/article/details/6715983
重复的数据:高级语句
http://www.dedecms.com/knowledge/data-base/sql-server/2012/0821/10732.html
http://www.360doc.com/content/12/0328/14/8354145_198587857.shtml
查询重复的数据http://blog.csdn.net/a11085013/article/details/8549256
一:as可以作为别名的标志。
sql:select name as username form tablename;
解释:上面语句的意思就是查询出tablename表中字段name的所有记录,并且给name别名为username。
二:as可以作为连接语句的操作符。
sql:create table tablename as select * from tablename2;
解释:上面语句的意思就是先获取到tablename表中的所有记录,之后创建一张tablename表,结构和tablename2表相同,记录为后面语句的查询结果。
来源: https://zhidao.baidu.com/question/243815061.html
IN 操作符
IN 操作符允许我们在 WHERE 子句中规定多个值。
SQL IN 语法
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...)
原始的表 (在实例中使用:)
Persons 表:
Id |
LastName |
FirstName |
Address |
City |
1 |
Adams |
John |
Oxford Street |
London |
2 |
Bush |
George |
Fifth Avenue |
New York |
3 |
Carter |
Thomas |
Changan Street |
Beijing |
IN 操作符实例
现在,我们希望从上表中选取姓氏为 Adams 和 Carter 的人:
我们可以使用下面的 SELECT 语句:
SELECT * FROM Persons
WHERE LastName IN ('Adams','Carter')
结果集:
Id |
LastName |
FirstName |
Address |
City |
1 |
Adams |
John |
Oxford Street |
London |
3 |
Carter |
Thomas |
Changan Street |
Beijing 来源: http://www.w3school.com.cn/sql/sql_in.asp |
应用:
1.天气预报
2.车载记录仪
1.数据库基本法则:创建,打开和封装
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- //打开或创建test.db数据库
- SQLiteDatabase db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null);
- db.execSQL("DROP TABLE IF EXISTS person");
- //创建person表
- db.execSQL("CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT)");
- Person person = new Person();
- person.name = "john";
- person.age = 30;
- //插入数据
- db.execSQL("INSERT INTO person VALUES (NULL, ?, ?)", new Object[]{person.name, person.age});
-
- person.name = "david";
- person.age = 33;
- //ContentValues以键值对的形式存放数据
- ContentValues cv = new ContentValues();
- cv.put("name", person.name);
- cv.put("age", person.age);
- //插入ContentValues中的数据
- db.insert("person", null, cv);
-
- cv = new ContentValues();
- cv.put("age", 35);
- //更新数据
- db.update("person", cv, "name = ?", new String[]{"john"});
-
- Cursor c = db.rawQuery("SELECT * FROM person WHERE age >= ?", new String[]{"33"});
- while (c.moveToNext()) {
- int _id = c.getInt(c.getColumnIndex("_id"));
- String name = c.getString(c.getColumnIndex("name"));
- int age = c.getInt(c.getColumnIndex("age"));
- Log.i("db", "_id=>" + _id + ", name=>" + name + ", age=>" + age);
- }
- c.close();
-
- //删除数据
- db.delete("person", "age < ?", new String[]{"35"});
-
- //关闭当前数据库
- db.close();
-
- //删除test.db数据库
- // deleteDatabase("test.db");
- }
在执行完上面的代码后,系统就会在/data/data/[PACKAGE_NAME]/databases目录下生成一个“test.db”的数据库文件,如图:
2.SQLiteOpenHelper也就是所谓的SQLiteDBhelper目的主要是更好的封装性(处理数据库)
上面就是SQLite的基本应用,但在实际开发中,为了能够更好的管理和维护数据库
我们会封装一个继承自SQLiteOpenHelper类的数据库操作类,然后以这个类为基础,再封装我们的业务逻辑方法。
Cursor结果集需要注意些什么:一个最需要注意的是,在我们的结果集中必须要包含一个“_id”的列,否则SimpleCursorAdapter就会翻脸不认人,为什么一定要这样呢?因为这源于SQLite的规范,主键以“_id”为标准。解决办法有三:第一,建表时根据规范去做;第二,查询时用别名,例如:SELECT id AS _id FROM person;第三,在CursorWrapper里做文章:
下面我们先来看一下DBHelper:用于;创建数据库和更新打开数据库
[java] view plaincopy
- package com.scott.db;
-
- import android.content.Context;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
-
- public class DBHelper extends SQLiteOpenHelper {
-
- private static final String DATABASE_NAME = "test.db";
- private static final int DATABASE_VERSION = 1;
-
- public DBHelper(Context context) {
- //CursorFactory设置为null,使用默认值
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- //数据库第一次被创建时onCreate会被调用
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE IF NOT EXISTS person" +
- "(_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER, info TEXT)");
- }
-
- //如果DATABASE_VERSION值被改为2,系统发现现有数据库版本不同,即会调用onUpgrade
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("ALTER TABLE person ADD COLUMN other STRING");
- }
- }
来源:
我们需要一个DBManager,来封装我们所有的业务方法(增删改查),代码如下:
数据的添加
2种方式:ContentValue和直接的sql语句!
1.使用insert方法
1 2 3 |
ContentValues cv = new ContentValues(); //实例化一个ContentValues用来装载待插入的数据cv.put("username","Jack Johnson");//添加用户名 cv.put( "password" , "iLovePopMusic" ); //添加密码 db.insert( "user" , null ,cv); //执行插入操作 |
2.使用execSQL方式来实现
1 2 |
String sql = "insert into user(username,password) values ( 'Jack Johnson' , 'iLovePopMuisc' ); //插入操作的SQL语句 db.execSQL(sql); //执行SQL语句 |
数据的删除
同样有2种方式可以实现
1 2 3 |
String whereClause = "username=?" ; //删除的条件 String[] whereArgs = { "Jack Johnson" }; //删除的条件参数 db.delete( "user" ,whereClause,whereArgs); //执行删除 |
使用execSQL方式的实现
1 2 |
String sql = "delete from user where username='Jack Johnson'" ; //删除操作的SQL语句 db.execSQL(sql); //执行删除操作 |
数据修改
同上,仍是2种方式
1 2 3 4 5 |
ContentValues cv = new ContentValues(); //实例化ContentValues cv.put( "password" , "iHatePopMusic" ); //添加要更改的字段及内容 String whereClause = "username=?" ; //修改条件 String[] whereArgs = { "Jack Johnson" }; //修改条件的参数 db.update( "user" ,cv,whereClause,whereArgs); //执行修改 |
使用execSQL方式的实现
1 2 |
String sql = "update [user] set password = 'iHatePopMusic' where username='Jack Johnson'" ; //修改的SQL语句 db.execSQL(sql); //执行修改 来源: 注意事项 |
[java] view plaincopy实现代码用Cursor的moveToNext函数对查询到的结果集进行遍历。
查询的函数还有:
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, Stringlimit);
db.query(String distinct, String table, String[] columns, Stringselection, String[] selectionArgs, String groupBy, String having, StringorderBy, String
来源:
1 2 3 4 5 6 7 8 |
Cursor c = db.query( "user" , null , null , null , null , null , null ); //查询并获得游标 if (c.moveToFirst()){ //判断游标是否为空 for ( int i= 0 ;i c.move(i); //移动到指定记录 String username = c.getString(c.getColumnIndex( "username" ); String password = c.getString(c.getColumnIndex( "password" )); } } |
通过rawQuery实现的带参数查询
1 2 3 4 |
Cursor c = db.rawQuery( "select * from user where username=?" , new Stirng[]{ "Jack Johnson" }); if (cursor.moveToFirst()) { String password = c.getString(c.getColumnIndex( "password" )); } |
bt中的查询
- package com.scott.db;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import android.content.ContentValues;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
-
- public class DBManager {
- private DBHelper helper;
- private SQLiteDatabase db;
-
- public DBManager(Context context) {
- helper = new DBHelper(context);
- //因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory);
- //所以要确保context已初始化,我们可以把实例化DBManager的步骤放在Activity的onCreate里
- db = helper.getWritableDatabase();
- }
-
- /**
- * add persons
- * @param persons
- */
- public void add(List persons) {
- db.beginTransaction(); //开始事务
- try {
- for (Person person : persons) {
- db.execSQL("INSERT INTO person VALUES(null, ?, ?, ?)", new Object[]{person.name, person.age, person.info});
- }
- db.setTransactionSuccessful(); //设置事务成功完成
- } finally {
- db.endTransaction(); //结束事务
- }
- }
-
- /**
- * update person's age
- * @param person
- */
- public void updateAge(Person person) {
- ContentValues cv = new ContentValues();
- cv.put("age", person.age);
- db.update("person", cv, "name = ?", new String[]{person.name});
- }
-
- /**
- * delete old person
- * @param person
- */
- public void deleteOldPerson(Person person) {
- db.delete("person", "age >= ?", new String[]{String.valueOf(person.age)});
- }
-
- /**
- * query all persons, return list
- * @return List
- */
- public List query() {
- ArrayList persons = new ArrayList();
- Cursor c = queryTheCursor();
- while (c.moveToNext()) {
- Person person = new Person();
- person._id = c.getInt(c.getColumnIndex("_id"));
- person.name = c.getString(c.getColumnIndex("name"));
- person.age = c.getInt(c.getColumnIndex("age"));
- person.info = c.getString(c.getColumnIndex("info"));
- persons.add(person);
- }
- c.close();
- return persons;
- }
-
- /**
- * query all persons, return cursor
- * @return Cursor
- */
- public Cursor queryTheCursor() {
- Cursor c = db.rawQuery("SELECT * FROM person", null);
- return c;
- }
-
- /**
- * close database
- */
- public void closeDB() {
- db.close();
- }
- }
为了方便我们面向对象的使用数据,我们建一个Person类,对应person表中的字段,如下:
直接操作实体类
[java] view plaincopy
- package com.scott.db;
-
- public class Person {
- public int _id;
- public String name;
- public int age;
- public String info;
-
- public Person() {
- }
-
- public Person(String name, int age, String info) {
- this.name = name;
- this.age = age;
- this.info = info;
- }
- }
- public class MainActivity extends Activity {
-
- private DBManager mgr;
- private ListView listView;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- listView = (ListView) findViewById(R.id.listView);
- //初始化DBManager
- mgr = new DBManager(this);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- //应用的最后一个Activity关闭时应释放DB
- mgr.closeDB();
- }
-
- public void add(View view) {
- ArrayList persons = new ArrayList();
-
- Person person1 = new Person("Ella", 22, "lively girl");
- Person person2 = new Person("Jenny", 22, "beautiful girl");
- Person person3 = new Person("Jessica", 23, "sexy girl");
- Person person4 = new Person("Kelly", 23, "hot baby");
- Person person5 = new Person("Jane", 25, "a pretty woman");
-
- persons.add(person1);
- persons.add(person2);
- persons.add(person3);
- persons.add(person4);
- persons.add(person5);
-
- mgr.add(persons);
- }
-
- public void update(View view) {
- Person person = new Person();
- person.name = "Jane";
- person.age = 30;
- mgr.updateAge(person);
- }
-
- public void delete(View view) {
- Person person = new Person();
- person.age = 30;
- mgr.deleteOldPerson(person);
- }
-
- public void query(View view) {
- List persons = mgr.query();
- ArrayList> list = new ArrayList>();
- for (Person person : persons) {
- HashMap map = new HashMap();
- map.put("name", person.name);
- map.put("info", person.age + " years old, " + person.info);
- list.add(map);
- }
- SimpleAdapter adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2,
- new String[]{"name", "info"}, new int[]{android.R.id.text1, android.R.id.text2});
- listView.setAdapter(adapter);
- }
-
- public void queryTheCursor(View view) {
- Cursor c = mgr.queryTheCursor();
- startManagingCursor(c); //托付给activity根据自己的生命周期去管理Cursor的生命周期
- CursorWrapper cursorWrapper = new CursorWrapper(c) {
- @Override
- public String getString(int columnIndex) {
- //将简介前加上年龄
- if (getColumnName(columnIndex).equals("info")) {
- int age = getInt(getColumnIndex("age"));
- return age + " years old, " + super.getString(columnIndex);
- }
- return super.getString(columnIndex);
- }
- };
- //确保查询结果中有"_id"列
- SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2,
- cursorWrapper, new String[]{"name", "info"}, new int[]{android.R.id.text1, android.R.id.text2});
- ListView listView = (ListView) findViewById(R.id.listView);
- listView.setAdapter(adapter);
- }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
实验说明:
Android中使用SQLite数据库时,需要用adb来辅助调试,如果想在windows下的cmd命令行中使用adb,
必须先配置环境变量,我这里是配的用户环境变量path: C:\Program Files\android-sdk\platform-tools;
数据库sqilte调试工具
SQLite Expert Professional(SQLite可视化管理工具)V3.4.34.2256...
问题:
在cmd命令中查询数据库,给数据库建立表格,…………等等!
知识:
Cursor的方法
注意:Cursor中游标的下一个,当前个可能为空
为了达到录音的自动话
一录完就看是播放,录制显示时间10秒
不用每次都存放在SD卡中,可以存放临时的文件
每个程序存放位置都有,在和偏好设置一样的,在data分区里面
================================================
问题:
插入数据库和添加数据库有什么区别
音乐播发器中查询的方法!
1.在shell中找到路径
总的来说就是:
2.在run命令中用adb pull 表格,可以导出许多的表格
数据库就会导入在当前的路径中
============================================
sqlitespy==怎么用?
查询语句中记得:字符串
实际的表示:Tables
View是我们在操作中查询用到的表
右键,查看表的连接的状态!
作业:在工具中进程查询语句的练习
xml文件的备份和通话记录的备份
我们的数据库建了几张表
如果xml文件删除了的点,就会重写进行整理
一开始创建了3个目
在分析的时候先删除上一次清理的时候的,然后在生成contactinfo,保证是最新的
数据的备份:有sd卡是存放在SD卡里面 ,没有sd卡的话是存放在了data/data/目录下
一个是缓存,一个备份
从缓存目录拷贝一份到备份目录
缓存目录:huanji
获取备份数据目录 huanji/.backup/
缓存目录和一个备份目录
备份的流程
1.要删除的Id
2.通过id在系统数据库中出他们的所以状态和性质
3.通过ID删除系统数据库中的数据
4.把在2中查出的条目数据写到xml文件中
1).按时间查出文件,找出最新的一个
2).把内容写到xml中,其中创建了一个临时的目录
5.删除自己创建的临时数据
短信,联系人,通话记录在系统数据库中不同的地方
联系人(短信和通话记录是一样的,联系人不一样)
短信
通话记录
数据是怎么插入的
在分析的时候
自己建的表有4张,3张是电话本,还有一张是第三方电话的信息(表的建立也是有一个管理类)