数据库的特点及作用:
1.一个数据库中可以存储多张数据表
2.每一张数据表的作用。类似于excel中表格的作用,即用于存储n多计较复杂的数据
如:存储学生信息
3.数据库的种类:
MySql 多用于处理电脑端,网页端的数据库
Oracle 与MySql作用类似,只不过能够比MySql存储更多数据,处理更复杂的数据
SQLite 轻量级数据库,多用于负责处理手机端或者平板电脑端的数据库操作
SQLite简介
是一款微型数据库,它用在嵌入式系统中,比如Android系统。它跟传统的数据库有比较大的差别。省略了大多数的功能,比如权限,管理、触发器、存储过程等。只保留对数据库最常用到的增删改查操作。(弱类型的数据库)。
使用方式:
1、自产自销方向(在本工程内创建数据库并使用,不使用别人工程中的数据库,也不让别人使用自身创建的数据库)
创建SQLiteOpenHelper的子类,并按照报错要求添加重写方法和构造方法
private SQLiteDatabase db;
/**
* 构造方法
* @param context 上下文环境,此处的作用:通过此环境获取到程序包名,可以确定数据库文件的存储位置
* 默认位置: data/data/程序包名/databases文件内
*
* @param name 设置数据库文件的名称
* @param factory 传参时填null即可
* @param version 设置数据库的版本号
*/
public MyHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
// TODO Auto-generated constructor stub
db = getReadableDatabase();
}
//通常会将上方的构造方法,直接修改为以下样式
public MyHelper(Context context) {
super(context, "ayy", null, 3);
// TODO Auto-generated constructor stub
db = getReadableDatabase();
}
/**
* 当第一次创建数据库文件时运行此方法,通常情况下会在此方法中进行创建表的操作
* 参数:数据库对象,可以通过此对象调用方法实现创建表,或者针对表中数据进行增删改查操作
*/
@Override
public void onCreate(SQLiteDatabase db) {
Log.i("oye", "============onCreate");
/**
* 通过执行创建表的sql语句实现创建表的需求
* execSQL方法用于执行方法参数中设置的sql语句
*
* 创建表的sql语句的格式为:
* create table if not exists 表名 (列名1 列类型 primary key autoincrement, 列名2 列类型。。。。 )
*/
db.execSQL("create table if not exists stu (_id integer primary key autoincrement,name text, age integer)");
}
/*
* 当new MyHelper对象时,如果传递的版本号发生改变,就会运行此方法
* 注意:版本号改变时只能上调,不能下调
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
Log.i("oye", "===== onUpgrade "+oldVersion+" "+newVersion);
// 执行删除原有表的操作
db.execSQL("drop table if exists stu");
onCreate(db);
}
onCreate方法的运行特点:
// 调用构造方法不会造成onCreate方法的运行
helper = new MyHelper(this, "ayy", null, 3);
/*
* 当通过helper对象调用getReadableDatabase或者getWriteableDatabase方法时
* 先判断默认路径是否有数据文件,如没有,则运行onCreate方法,如已存在数据库文件,则不运行onCreate方法
*
* 两者的区别在于:基本是一样的,只有一种情况两者不同
* 当数据库已经达到最大存储上限了,如果getWriteableDatabase方法得到SqliteDatabase对象
* ,并且通过db对象还要添加数据,此时会崩溃,但是如果用getReadableDatabase方法,则不会崩溃,顶多添加失败
*/
// helper.getReadableDatabase();
通过sql语句实现增删改查操作
增
//增加数据
public void add (String name,int age) {
/**
* 执行添加数据的sql语句
* insert into 表名 (列名1,列名2.。。) values (值1,值2.。。。)
* ? 用于代表占位符,稍后可以有参数二指定的数据中的内容替代?的内容
*/
db.execSQL("insert into stu (name,age) values(?,?)",new Object[]{name,age});
}
删
//删除数据
public void delete (int id) {
/**
* 执行删除的sql语句
* delete from 表名 删除表中所有的数据
*
* delete from 表名 where 条件表达式 , 按指定条件删除内容
*/
db.execSQL("delete from stu where _id = "+id);
}
改
//修改数据
public void update (String name,int age,int id) {
/**
* 执行修改的sql语句
* update 表名 set 列1 = 值1,列2 = 值2.。。。 修改表中所有的数据
* update 表名 set 列1 = 值1,列2 = 值2.。。。 where 条件表达式 修改符合条件表达式的内容
*/
db.execSQL("update stu set name= ?, age = ? where _id = ?", new Object[]{name,age,id});
}
查
//查询所有数据
public ArrayList<Studeng> getAllData(){
ArrayList<Studeng> list = new ArrayList<Studeng>();
/**
* 执行查询的sql语句
* select * from 表名
* 通过rawQuery方法执行sql语句,原因为:通过该方法的返回值可以取出查询到的结果
* 返回值:Cursor对象,游标对象
*/
Cursor cursor = db.rawQuery("select * from stu", null);
//moveToNext:让Cursor向下挪动一行,并在挪动后将该行的所有数据存储到Cursor对象中
//一旦返回值为false,则代表没有下一行了,即所有数据读取完毕
while (cursor.moveToNext()) {
String n = cursor.getString(cursor.getColumnIndex("name"));
int a = cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Studeng(n, a));
}
return list;
}
如查询id为3到5之间的数据
public ArrayList<Studeng> getData (int startId,int endId) {
ArrayList<Studeng> list = new ArrayList<Studeng>();
Cursor cursor = db.rawQuery("select * from stu where _id >= ? and _id <= ?", new String[]{startId+"",endId+""});
while (cursor.moveToNext()) {
String n = cursor.getString(cursor.getColumnIndex("name"));
int a = cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Studeng(n, a));
}
return list;
}
如查询id为2或者为5的数据
public ArrayList<Studeng> getDataOr (int startId,int endId) {
ArrayList<Studeng> list = new ArrayList<Studeng>();
Cursor cursor = db.rawQuery("select * from stu where _id = ? or _id = ?", new String[]{startId+"",endId+""});
while (cursor.moveToNext()) {
String n = cursor.getString(cursor.getColumnIndex("name"));
int a = cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Studeng(n, a));
}
return list;
}
模糊查询,(如查找所有姓李的)
public ArrayList<Studeng> getDataLike (String s) {
ArrayList<Studeng> list = new ArrayList<Studeng>();
Cursor cursor = db.rawQuery("select * from stu where name like ?", new String[]{"%"+s+"%"});
while (cursor.moveToNext()) {
String n = cursor.getString(cursor.getColumnIndex("name"));
int a = cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Studeng(n, a));
}
return list;
}
通过系统方法实现增删改查:
增
//通过db中封装好的方法实现增加数据的操作
public void addByMethod(String name,int age){
/**
* 1. String table 用于设置表名
* 3. ContentValues对象, 用于设置要添加的数据
* 特点:专门用于封装数据库数据的类,可以存储多组键值对,键必须是表的表名,值为想要添加的数据
* 2. 随便写一个表中的列名即可
* 参数二作用: 当参数二和三都为null时,在执行添加方法时程序会崩溃
* 如果参数二不为null,参数三为null是,执行添加操作时不会崩溃,只会给表的列中添加值:NULL
*/
ContentValues values = new ContentValues();
values.put("name", name);
values.put("age", age);
/*
* 当insert方法的返回值为-1时,代表添加失败
* 当返回值不为-1时,该数字代表的是新添加的数据在表中对应的id的值
*/
long id = db.insert("stu", "_id", values);
Log.i("oye", "insert id "+id);
}
删
public void deleteByMethod(int id){
/*
* String table 设置表名
* String whereClause 删除条件
* whereArgs 删除条件中如果有?的占位符时,通过此参数替代?的值
*
* 返回值: 根据指定的删除条件成功删除了几条数据
*/
int num = db.delete("stu", "_id="+id, null);
Log.i("oye", "delete num "+num);
}
改
public void updateByMethod (int id,String name) {
/**
* table 表名
* values ContentValues 用于设置修改后的数据
* whereClause 修改的条件
* whereArgs 用于替换条件中的?的值
*/
ContentValues values = new ContentValues();
values.put("name", name);
//根据指定条件,修改的条数
int num = db.update("stu", values, "_id = ?", new String[]{id+""});
}
查
public ArrayList<Studeng> getDataByMethod(){
ArrayList<Studeng> list = new ArrayList<Studeng>();
/**
* 1. table 表名
* 2. String[] 设置要查询的列名,查询所有列填null即可
* 3. seletion 查询条件
* 4. String[] selectionArgs 数组中的值用于替代条件中?的值
* 5,6 合起来构成分组条件起始就是变相的where查询条件
* 7. order by 排序 列名 asc或desc asc升序 desc 降序
*/
Cursor cursor = db.query("stu", null, null, null, null, null, "age desc");
while (cursor.moveToNext()) {
String n = cursor.getString(cursor.getColumnIndex("name"));
int a = cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Studeng(n, a));
}
return list;
}
2 进货方向(先获得别人的数据库文件,然后直接使用此文件)
1. 先拥有别人的数据库文件,然后将该文件放置在本机的sd卡或者机身内存中
/*
* 参数:通过openDatabase方法可直接打开准备好的数据库文件
* 1. 要打开的数据库文件对应的存储路径
* 2. CursorFactory,填null即可
* 3. flag标识,用于设置数据库打开特点
* 如:SQLiteDatabase.OPEN_READONLY 以只读方式打开数据库
* SQLiteDatabase.OPEN_READWRITE 以读写方式打开数据库
* SQLiteDatabase.CREATE_IF_NECESSARY 当指定路径下存在数据库文件时,则直接打开该文件
* 当指定路径下不存在数据库文件时,会自动创建一个数据库文件,然后再打开该文件
*
* 备注:如果flag设置的为 SQLiteDatabase.CREATE_IF_NECESSARY ,那么此时openDatabase方法的作用与openOrCreateDatabase方法一致
* */
db = SQLiteDatabase.openDatabase("/mnt/sdcard/home", null, SQLiteDatabase.CREATE_IF_NECESSARY);
2.SimpleCursorAdapter适配器的一种,专门用于结合数据库使用
(1)获取查询结果Cursor对象
cursor = db.rawQuery("select * from person", null);
(2)初始化并设置适配器
/**
* 1. Context
* 2. 列表中每一个item显示的布局
* 3. 数据源,此时数据源的类型是一个Cursor对象,并且此适配器,支持数据源传递为null
* 4. 数据从哪来 ,写查询的数据表中对应的列名
* 5. 数据到哪去 int[] ,用于填写item布局中控件的id
* 6. flag标识,固定为:SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
*
* 使用SimpleCursorAdapter时注意:
*1. 表中主键列的名字必须是_id
* 2.数据源的Cursor中查询时必须查询主键列
*/
adapter = new SimpleCursorAdapter(this, R.layout.item, cursor,
new String[]{"_id","name"}, new int[]{R.id.textView1,R.id.textView2},
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv.setAdapter(adapter);
(3)适配器刷新方式:
// 重新读取表中所有数据
Cursor c = db.rawQuery("select * from person", null);
//刷新适配器
adapter.swapCursor(c); // 交换数据源
adapter.notifyDataSetChanged();
数据库的事务:
作用:
1. 加速,如:使用了事务操作添加30000条数据的时间要远远少于不使用事务的
2. 提供回滚功能,用于确保数据要么完全完成操作,要么一条都不加
回滚效果如: 要添加10000条数据,但是当添加第2001条数据时,代码写错了,发生异常,才是事务会将原有已添加的2000条数据回滚删除掉.
使用方式:
public void addByTrans () {
long start = System.currentTimeMillis();
//1. 在数据库操作执行前,启动事务
db.beginTransaction();
//2. 将数据库操作部分通过try--catch包裹起来,
try {
for (int i = 0; i < 10000; i++) {
//if部分用于测试事务的回滚效果
// if (i == 2000) {
// db.execSQL("insert into acs (name,age) values (?,?)",new Object[]{"姓名 "+i,i+1});
// } else {
db.execSQL("insert into ac (name,age) values (?,?)",new Object[]{"姓名 "+i,i+1});
// }
}
//3. 在try语句块的末尾添加事务成功标识
db.setTransactionSuccessful();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//4. try catch语句的外面结束事务操作
db.endTransaction();
long end = System.currentTimeMillis();
Log.i("oye", "通过事务添加耗时的毫秒值为: "+(end-start));
}
实现截取数据库中指定条数据的方式:
public Cursor getData(int start){
/*
* limit 后面跟2个数字
* 数字1: 从第几行开始读取数据(行数从0开始)
* 数字2: 总共截取出多少条数据
* */
return db.rawQuery("select * from pr limit ?, ?", new String[]{start+"","20"});
}
创建能够存储图片的数据库的方式:
/**
* blob 是SQLite中支持存储的数据类型的一种,用于存储图片对象
* 实际类型就是byte[]
*/
db.execSQL("create table if not exists img (_id integer primary key autoincrement,name text,icon blob)");
向数据库中添加图片的方式:
//存入图片数据
public void addBitmap(String name, Bitmap bitm) {
//根据Bitmap对象得到对应的byte数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitm.compress(CompressFormat.PNG, 100, bos);
//数组b中存储的就是图片数据
byte[] b = bos.toByteArray();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("icon", b);
db.insert("img", "_id", values);
}
从数据库中取出图片的方式:
//取出图片数据方法
public Bitmap getBitmap (int id) {
Cursor cursor = db.rawQuery("select * from img where _id = "+id, null);
if (cursor.moveToFirst()) {
byte[] b = cursor.getBlob(cursor.getColumnIndex("icon"));
return BitmapFactory.decodeByteArray(b, 0, b.length);
}
return null;
}