加载中...
加载中...
SQLite 数据库简介

SQLite 数据库简介 原创

SQLite 数据库简介

 实验环境
Android Studio 3.6.3
AVD: Nexus_5X_API_27 Android8.1 X86
SDK: BaiduLBS_AndroidSDK_Lib

SQLite 数据库软件的特点

SQLite 是 Android 系统手机自带(内置)的轻量级数据库软件,类似于 Access 数据
库软件,它提供了对数据库增加、删除、修改和查询的操作。此外,它还具有如下特点:
 占用资源少,特别适合于嵌入式设备;
 支持较多的开发语言;
 无需安装和配置;
 使用关系型的 SQL 命令进行 SQLite 数据库操作。  

Android 系统对 SQLite 数据库的支持

在标准的 Android 软件包里,提供了与 SQLite 数据库相关的两个软件包。一个包是
android.database,它定义了游标接口 Cursor(与 JDBC 中的 ResultSet 类似);另一个包
是 android.database.sqlite,它包含了 2 个抽象类 SQLiteOpenHelper 和 SQLiteDatabase

使用 SQLiteOpenHelper 创建、打开或更新数据库

使用 SQLiteOpenHelper 创建数据库

抽象类 SQLiteOpenHelper 位于包 android.database.sqlite 内,定义了子类必须重写的2 个方法 onCreate()和 onUpgrade(),不仅提供了创建、打开数据库操作的构造方法SQLiteOpenHelper(),还提供了获取 SQLiteDatabase 对象的方法(getReadableDatabase()和 getWritableDatabase())


注意:使用抽象类 SQLiteOpenHelper 的构造方法创建数据库时,以上下文对象作为
其中的 1 个参数。
由于 Java 不支持多继承,为了代码复用,通常在访问 SQLite 数据库的项目里,建立抽象类 SQLiteOpenHelper 的子类作为一个独立类,或者作为 Activity 组件程序的内部类,(需要在Activity调用才能生成数据库)其示例代码如下:

复制Javapublic class MyDbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
//super(context, name, factory, version); //调用父类构造方法
//第 2 个参数为库名,第 4 个参数为库版本号
super(context, "test.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//操作数据库的 SQL 命令,在创建新数据库时自动执行,创建数据库代码
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//操作数据库的 SQL 命令,在数据库版本提升时自动执行
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

使用 SQLiteOpenHelper 的方法 getWritableDatabase()可获得 SQLiteDatabase 类型的
数据库对象。类 SQLiteDatabase 封装了对数据库操作的方法,如图


使用 SQLiteSpy 验证创建的数据库

Android 应用创建的数据库位于文件夹 data/data/包名/databases 里,使用 Device File Explorer 找到应用创建的 SQLite 数据库,在数据库名的菜单里,选择 Save As 选项,即可将该 SQLite 数据库导入计算机,其操作如图找到 AVD 里的 SQLite 数据库

 View > Tool Windows > Device File Explorer



SQLiteSpy 是一款在 Windows 中运行、以图形方式管理 SQLite 数据库的软件,解压后即可使用(无须安装),其运行界面如图


SQLite 数据库的更新

SQLiteDatabase 类提供了对数据库操作查询的 execSQL(SQL),其中 SQL 参数是对数据库执行操作查询的 SQL 命令(而不是使用 Select 命令的普通查询),通常是 Insert、Delete、Update 或 Create Table、Alter Table 等命令。

【例】 SQLite 数据库及表的创建与更新。
【程序运行】程序首次部署到手机运行后,创建数据库 test.db 及表 person,其中person 表包含两个字段。当修改源程序,将数据库版本从 1 提升到 2 时,再次部署、运行程序,会执行 onUpgrade()方法,修改 person 表结构,增加一个字段。导出数据库,并使用 SQLiteSpy 可查验。程序 MainActivity 的结构,如图所示

复制Javapackage com.example.chapter08;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.widget.Toast;

/*
首次安装时,调用 SQLiteOpenHelper 的 onCreate()方法创建库 test.db 及表 person
以后运行时,若数据库没有版本提升,则用可读写方式直接打开数据库;
若有版本提升,则先执行 onUpgrade()方法后,再用可读写方式打开数据库
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyDbOpenHelper helper = new MyDbOpenHelper(this);
helper.getWritableDatabase(); //数据库文件句柄
}
class MyDbOpenHelper extends SQLiteOpenHelper { //内部工具类
public MyDbOpenHelper(Context context) {
//必须调用抽象父类的构造方法,第 4 个参数为数据库版本
super(context, "test.db", null,1); //建立或打开库
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "创建数据库表...", Toast.LENGTH_SHORT). show();
db.execSQL("CREATE TABLE person(id Integer Primary Key AutoIncrement, name VARCHAR(20))");
db.execSQL("insert into person values(null,'luo')");
db.execSQL("insert into person values(null,'lei')");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Toast.makeText(MainActivity.this, "数据库表更新中...", Toast.LENGTH_SHORT).show();
db.execSQL("ALTER TABLE person ADD tel CHAR(20)");
db.execSQL("update person set tel='18770000001' where name='luo'");
db.execSQL("update person set tel='15000000001' where name='lei'");
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

使用 SQLiteDatabase 实现数据库表的增删改查

记录的增删改查

1.操作数据库的两种方式

操作数据库有两种方式,一种是使用方法 execSQL()实现记录的增加、删除和修改,使用方法 rawQuery()查询数据库表,它们都以一条完整的 SQL 命令作为方法参数。
注意:方法 execSQL()可以实现数据库表结构的创建和修改。
操作数据库的另一种方式是使用方法 insert()、update()、delete()和 query()实现记录的增加、删除、修改和查询,这些方法的参数不是完整的 SQL 命令,而是 SQL 命令中的相关短语。其中,方法 insert()和 update()使用了 ContentValues 类型的参数。
注意:
(1)execSQL(String,Object[])方法较 execSQL(String)而言,在 SQL 命令中支持通配符“?”。
(2)方法 insert()、update()、delete()和 query()中的第 1 个参数都是表名。
(3)执行 insert()等方法,本质上也是执行 SQL 命令,只是系统已经组装相关参数为完整的 SQL 语句。

2.使用接口 Cursor 表示查询结果

使用 SQL 命令查询数据库得到的是内存中的一张虚拟表(记录集),通过记录指针可以遍历所有记录,游标接口 android.database.Cursor 就是为这个目的设计的。

含有两个参数的原生查询方法 rawQuery(),它的第 1 个参数是完整的 SQL 命令,第2 个参数是条件参数,配合 SQL 命令使用的占位符“?”。例如:

复制JavaCursor c=db.rawQuery("select * from person where id=?",new String[]{idv+""});
  • 1

注意:由于 id 字段是整型,因此上面的 idv 表达式应为整型。作为 SQL 命令的一部分,它需要转换成字符串。比较标准的做法是使用“Integer(idv).toString()”。含 7 个参数的 query()方法,各参数的含义在 Android Studio 中有提示,第 1 个参数为表名,第 2 个参数为字段集,第 3 个参数为选择条件,第 4 个参数为条件参数,最后一个参数为排序依据。例如,查询表 person 中年龄低于 50 岁的人员代码如下:

复制JavaString selectFilter="age<50";
Cursor c=db.query("person", null, selectFilter, null, null, null, "_id ASC");
  • 1
  • 2

注意:较原生查询方法 rawQuery()而言,query()这种非原生查询方式更加灵活。
SQLiteDatabase 类的两种查询方法都是得到 Cursor 接口类型的对象,该接口提供的常用方法如图

Cursor 接口提供的常用方法


3.使用 ContentValues 类型的参数

SQLiteDatabase 的方法 insert()和 update()都包含了 ContentValues 类型的参数,类
ContentValues 提供了“键—值”对形式的数据,其主要方法如图


例如,插入记录常用方法为 insert(table,null,contentValues)。
注意:当 contentValues 参数为空或者里面没有内容的时候,insert()会失败,因为底层数据库不允许增加一个空行。为了防止这种情况,可以将第 2 个参数设置为一个列名。如果能保证 contentValues 值非空,则可以将第 2 个参数简单地设置为“null”。

使用适配器 SimpleAdapter 显示查询结果

为了在 ListView 等控件中显示查询得到的结果集,完成一条记录的多项输出,可以使用 SimpleAdapter 数据适配器来完成。数据适配器类 SimpleAdapter 提供的构造方法用于定义适配器。除此之外,它还有许多方法,如图 


定义数据适配器 SimpleAdapter 时,共需要 5 个参数,分别是上下文对象、泛型列表数据、列表布局文件名(不带扩展名)、列表数据中的字段名数组和列表布局项控件名称数组。定义与使用 SimpleAdapter 的参考代码如下

复制Javaprivate Cursor cursor;
ListView listView;
private Map<String,Object> listItem; //列表项,对应一条记录
private List<Map<String,Object>> listData; //所有列表数据
//查询数据库并赋值给 listData
while(cursor.moveToNext()){
listItem=new HashMap<String,Object>(); //创建实例
//分别获取各字段值给相应变量:id、name 和 age
listItem.put("_id",id); //键值对
listItem.put("name",name);
listItem.put("age",age);
listData.add(listItem);
}
//创建数据适配器对象并填充数据
SimpleAdapter listAdapter = new SimpleAdapter(
this,
listData,
R.layout.list_item,
//列表数据中的字段集,对应于 Map 集合里的键名
new String[]{"_id","name","age"},
//列表布局中用于显示字段数据的控件集
new int[]{R.id.tv_id,R.id.tv_name,R.id.tv_age});
listView.setAdapter(listAdapter); //绑定数据显示控件
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

注意:
(1)由于 SimpleAdapter 的一个列表项里包含了多项数据,因此,在使用 ArrayList
定义其数据项之前,需要使用 HashMap 定义其列表项;
(2)创建数据适配器 SimpleAdapter 对象时,其构造方法中共包含 5 个参数;
(3)通过 ListView 等控件提供的 setAdapter()方法实现数据的绑定。

以 DAO 方式访问数据库编写程序

使用 DAO 方式,访问 SQLite 数据库。
项目运行时,向数据库表增加 2 条记录并使用 ListView 控件显示效果,单击按钮,可以实现增加、修改和删除功能,如图


主要设计步骤如下。
(1)抽象类 SQLiteOpenHelper 的子类 MyDbHelper,其代码如下:

复制Javapublic class MyDbHelper extends SQLiteOpenHelper{
public static final String TB_NAME = "friends"; //表名
//构造方法:第 1 个参数为上下文,第 2 个参数为数据库名,第 3 个参数为游标工厂,第 4
个参数为版本
public MyDbHelper(Context context, String dbname, CursorFactory factory, int version) {
super(context, dbname, factory, version); //创建或打开数据库
}
@Override
public void onCreate(SQLiteDatabase db) {
//当表不存在时,创建表;第一字段为自增长类型
db.execSQL("CREATE TABLE IF NOT EXISTS " +
TB_NAME + "( _id integer primary key autoincrement," +
"name varchar," + "age integer"+ ")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 执行 SQL 命令
db.execSQL("DROP TABLE IF EXISTS " + TB_NAME);
onCreate(db);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

(2)封装 CRUD 方法到类文件 MyDAO.java,其代码如下:

复制Java/*
本类 MyDAO 调用了打开数据库的助手类 MyDbHelper
本类 MyDAO 提供的 CRUD 针对数据库 test.db 的表 friends
查询数据库表所有记录的方法:allQuery()
插入记录的方法:insertInfo(String name,int age)
删除记录的方法:deleteInfo(String selId)
修改记录的方法:updateInfo(String name,int age,String selId)
*/
public class MyDAO {
private SQLiteDatabase myDb; //类的成员
private MyDbHelper dbHelper; //类的成员
public MyDAO(Context context) { //构造方法,参数为上下文对象
//第 1 个参数为上下文,第 2 个参数为数据库名
dbHelper = new MyDbHelper(context,"test.db",null,1);
myDb = dbHelper.getReadableDatabase();
}
public Cursor allQuery(){ //查询所有记录
return myDb.rawQuery("select * from friends",null);
}
public int getRecordsNumber(){ //返回数据表记录数
Cursor cursor = myDb.rawQuery("select * from friends",null);
return cursor.getCount();
}
public void insertInfo(String name,int age){ //插入记录
myDb = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("age", age);
long rowid=myDb.insert(MyDbHelper.TB_NAME, null, values);
if(rowid==-1)
Log.i("myDbDemo", "数据插入失败!");
else
Log.i("myDbDemo", "数据插入成功!"+rowid);
}
public void deleteInfo(String selId){ //删除记录
String where = "_id=" + selId;
int i = myDb.delete(MyDbHelper.TB_NAME, where, null);
if (i > 0)
Log.i("myDbDemo", "数据删除成功!");
else
Log.i("myDbDemo", "数据未删除!");
}
public void updateInfo(String name,int age,String selId){ //修改记录
//方法中的第 3 个参数用于修改选定的记录
ContentValues values = new ContentValues();
values.put("name", name);
values.put("age", age);
String where="_id="+selId;
int i=myDb.update(MyDbHelper.TB_NAME, values, where, null);
//上面几行代码的功能可以用下面的一行代码实现
//myDb.execSQL("update friends set name = ? ,age = ? where _id = ?",
new Object[]{name,age,selId});
if(i>0)
Log.i("myDbDemo","数据更新成功!");
else
Log.i("myDbDemo","数据未更新!");
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

(3)编写 MainActivity 程序,其代码如下:

复制Java/*
本程序中对数据库的插入操作和查询,使用了 MyDAO 类的相关方法
首次运行时,增加两条记录并使用 ListView 控件显示出来
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private MyDAO myDAO; //数据库访问对象
private ListView listView;
private List<Map<String,Object>> listData;
private Map<String,Object> listItem;
private SimpleAdapter listAdapter;
private EditText et_name; //数据表包含 3 个字段,第 1 字段为自增长类型
private EditText et_age;
private String selId=null; //选择项 Id
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt_add= (Button) findViewById(R.id.bt_add);bt_add.setOnClickListener(this);
Button bt_modify=(Button)findViewById(R.id.bt_modify);bt_modify.setOnClickListener (this);
Button bt_del=(Button)findViewById(R.id.bt_del);bt_del.setOnClickListener(this);
et_name=(EditText)findViewById(R.id.et_name);
et_age=(EditText)findViewById(R.id.et_age);
myDAO = new MyDAO(this); //创建数据库访问对象
if(myDAO.getRecordsNumber()==0) { //防止重复运行时插入记录
myDAO.insertInfo("tian", 19); //插入记录
myDAO.insertInfo("wang", 18); //插入记录
}
displayRecords(); //显示记录
}
public void displayRecords(){ //显示记录方法定义
listView = (ListView)findViewById(R.id.listView);
listData = new ArrayList<Map<String,Object>>();
Cursor cursor = myDAO.allQuery();
while (cursor.moveToNext()){
int id=cursor.getInt(0); //获取字段值
String name=cursor.getString(1);
//int age=cursor.getInt(2);
int age=cursor.getInt(cursor.getColumnIndex("age")); //推荐此种方式
listItem=new HashMap<String,Object>(); //必须在循环体里新建
listItem.put("_id", id); //第 1 个参数为键名,第 2 个参数为键值
listItem.put("name", name);
listItem.put("age", age);
listData.add(listItem); //添加一条记录
}
listAdapter = new SimpleAdapter(this,
listData,
R.layout.list_item,
new String[]{"_id","name","age"},
new int[]{R.id.tv_id,R.id.tvname,R.id.tvage});
listView.setAdapter(listAdapter); //应用适配器
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { //列表项监听
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//从适配器读取记录
Map<String,Object> rec= (Map<String, Object>) listAdapter.getItem (position);
et_name.setText(rec.get("name").toString()); //刷新文本框
et_age.setText(rec.get("age").toString());
Log.i("ly",rec.get("_id").toString());
selId=rec.get("_id").toString(); //供修改和删除时使用
}
});
}
@Override
public void onClick(View v) { //实现的接口方法
if(selId!=null) { //选择了列表项后,可以增加、删除、修改
String p1 = et_name.getText().toString().trim();
int p2 = Integer.parseInt(et_age.getText().toString());
switch (v.getId()){
case R.id.bt_add:
myDAO.insertInfo(p1,p2);
break;
case R.id.bt_modify:
myDAO.updateInfo(p1,p2,selId);
Toast.makeText(getApplicationContext(),"更新成功!",
Toast.LENGTH_SHORT).show();
break;
case R.id.bt_del:
myDAO.deleteInfo(selId);
Toast.makeText(getApplicationContext(),"删除成功!",
Toast.LENGTH_SHORT).show();
et_name.setText(null);et_age.setText(null); selId=null; //提示
}
}else{ //未选择列表项
if(v.getId()==R.id.bt_add) { //单击“添加”按钮
String p1 = et_name.getText().toString();
String p2 = et_age.getText().toString();
if(p1.equals("")||p2.equals("")){ //要求输入信息
Toast.makeText(getApplicationContext(),"姓名和年龄都不能空!",
Toast.LENGTH_SHORT).show();
}else{
myDAO.insertInfo(p1, Integer.parseInt(p2)); //第 2 个参数转型
}
} else{ //单击修改或删除按钮
Toast.makeText(getApplicationContext(),"请先选择记录!",
Toast.LENGTH_SHORT).show();
}
}
displayRecords(); //刷新 ListView 对象
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100

===========================

由于在 DAO 类方法中的参数很多是数据表的字段,因此,可以将各个数据表对应地建立一个实体类,这些类通常称为 Model 层。每个实体类除了包含那些字段成员外,只包含 set×××()和 get×××()方法。在 DAO 类的方法中使用实体类对象参数,减少了 DAO 类方法中参数的个数,使程序更加清晰。
使用“DAO+实体类+BaseAdapter”方式,访问 SQLite 数据库。与上一个例子相比,添加了实体类,Activity 组件使用适配器 BaseAdapter。而类MyDbHelper 与 MyDAO 相同。

(1)实体类 Person.java 的代码如下:

复制Javapublic class Person {
private int _id; //数据库里是自增长字段
private String name;
private int age;
Person(int _id,String name,int age){
this._id=_id;
this.name=name;
this.age=age;
}
public void set_id(int _id) {
this._id = _id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int get_id() {
return _id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

2)MainActivity.java 代码如下:

复制Javapublic class MainActivity extends AppCompatActivity implements View.OnClickListener{
MyDAO myDAO; //数据库访问对象
ListView listView; //列表控件
List<Person> listData; //列表数据
BaseAdapter adapter; //列表控件的数据适配合器
//数据表包含 3 个字段,第 1 字段为自增长类型
int selId; //选择项 Id,与自增长类型的第一字段相对应
EditText et_name; //对应第 2 字段的控件对象
EditText et_age; //对应第 3 字段的控件对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//3 个按钮
Button bt_add= findViewById(R.id.bt_add);bt_add.setOnClickListener(this);
Button bt_modify=findViewById(R.id.bt_modify);bt_modify.setOnClickListener(this);
Button bt_del=findViewById(R.id.bt_del);bt_del.setOnClickListener(this);
//两个编辑文本框
et_name=findViewById(R.id.et_name);
et_age=findViewById(R.id.et_age);
//初次安装时建立两条记录
myDAO = new MyDAO(this); //创建数据库访问对象
if(myDAO.getRecordsNumber()==0) { //防止重复运行时插入记录
myDAO.insertInfo("tian", 19); //插入记录
myDAO.insertInfo("wang", 18); //插入记录
}
displayRecords(); //显示记录
}
public void displayRecords(){ //定义显示记录方法
listView = findViewById(R.id.listView);
listData = new ArrayList<Person>();
Cursor cursor = myDAO.allQuery();
while (cursor.moveToNext()){ //遍历记录集
int id=cursor.getInt(0); //获取字段值
String name=cursor.getString(1);
int age=cursor.getInt(cursor.getColumnIndex("age")); //推荐此种方式
Person person=new Person(id,name,age); //创建 Person 对象
listData.add(person); //添加一条记录
}
adapter=new BaseAdapter() { //创建适配器,需要重写 4 个抽象方法
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int position) {
return listData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 根据布局文件创建列表项 View(不同于 SimpleAdapter)
View item = View.inflate(getApplicationContext(), R.layout.list_item, null);
// 获取这个动态生成列表项中的各个字段对应的文本标签
TextView idTV = item.findViewById(R.id.tv_id);
TextView nameTV = item.findViewById(R.id.tvname);
TextView ageTV = item.findViewById(R.id.tvage);
// 根据位置获取 Person 对象(列表项数据)
Person p = listData.get(position);
/*设置标签文本(不同于 SimpleAdapter)。其中,_id 和 age 两个字段是整型,
不做字符串处理时,将导致闪退。用到实体类的 get/set 访问方法*/
idTV.setText(p.get_id()+"");
nameTV.setText(p.getName());
ageTV.setText(p.getAge()+"");
return item;
}
};
listView.setAdapter(adapter); //应用适配器
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { //列表项监听
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Person rec= (Person) adapter.getItem(position); //从适配器读取记录
et_name.setText(rec.getName()); //刷新文本框
et_age.setText(rec.getAge()+"");
selId=rec.get_id(); //供修改和删除时使用
}
});
}
@Override
public void onClick(View v) { //实现的接口方法
if(selId>0) { //选择了列表项后,可以增加、删除、修改
String p1 = et_name.getText().toString().trim();
int p2 = Integer.parseInt(et_age.getText().toString());
switch (v.getId()){
case R.id.bt_add:
myDAO.insertInfo(p1,p2);
break;
case R.id.bt_modify:
myDAO.updateInfo(p1,p2,selId);
Toast.makeText(getApplicationContext(),"更新成功!",
Toast.LENGTH_SHORT).show();
break;
case R.id.bt_del:
myDAO.deleteInfo(selId);
Toast.makeText(getApplicationContext(),"删除成功!",
Toast.LENGTH_SHORT).show();
et_name.setText(null);et_age.setText(null); selId=0; //提示
}
}else{ //未选择列表项
if(v.getId()==R.id.bt_add) { //单击“添加”按钮
String p1 = et_name.getText().toString();
String p2 = et_age.getText().toString();
if(p1.equals("")||p2.equals("")){ //要求输入信息
Toast.makeText(getApplicationContext(),"姓名和年龄都不能空!",
Toast.LENGTH_SHORT).show();
}else{
myDAO.insertInfo(p1, Integer.parseInt(p2)); //第 2 个参数转型
}
} else{ //单击“修改”或“删除”按钮
Toast.makeText(getApplicationContext(),"请先选择记录!",
Toast.LENGTH_SHORT).show();
}
}
displayRecords(); //刷新 ListView 对象
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119

使用数据库事务

使用数据库事务的典型案例就是银行转账汇款。当一个账户减少金额时,另一个账户增加金额,而不能出现一个账户减少金额后系统抛出异常,导致另一个账户没有增加金额,反之亦然。处理这类同时提交或同时不提交的业务,就是数据库事务。
SQLiteDatabase 提供了处理数据库事务的相关方法。例如,开启数据库事务的beginTransaction()方法、处理完毕数据库事务的 setTransactionSuccessful()方法、结束数据库事务的 endTransaction()方法等。

【例 】 使用数据库事务,实现银行汇款。初次运行程序,会产生除数为 0 的异常,账户余额不会变化,账户 111 的余额为 2000,账户 222 的余额为 8000,导出数据库可查验。屏蔽程序中会产生异常的代码,再次部署和运行程序,则交易成功,账户余额同时变化,账户 111 的余额为 1500,账户 222 的余额为 8500,导出数据库可查验。

复制Javapublic class MainActivity extends AppCompatActivity {
MyDbOpenHelper helper;
SQLiteDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建或连接数据库
helper = new MyDbOpenHelper(this);
db = helper.getWritableDatabase();
setMit(); //执行自定义的事务处理方法
db.close();
}
public void setMit(){ //事务处理方法
db.beginTransaction(); //数据库事务
try{
int num = 500; //汇款金额
String from = "111"; //汇出账户
String to = "222"; //接收账户
db.execSQL("update accounts set balance = balance - ? where id = ?",
new Object[]{num,from});
//产生除数为 0 的异常,屏蔽此行才能完成事务
int temp=1/0;
db.execSQL("update accounts set balance = balance + ? where id = ?",new
Object[]{num,to});
db.setTransactionSuccessful(); //事务成功标识
Toast.makeText(this, "交易成功", Toast.LENGTH_LONG).show();
} catch (Exception e){
Toast.makeText(MainActivity.this, "异常中断,交易未能成功",
Toast.LENGTH_SHORT).show();
} finally{
db.endTransaction();
}
}
class MyDbOpenHelper extends SQLiteOpenHelper { //自定义工具内部类
public MyDbOpenHelper(Context context) {
super(context, "test.db", null,1); //建立或打开库
}
@Override
public void onCreate(SQLiteDatabase db) {
//创建表结构
db.execSQL("CREATE TABLE accounts(id char(6) ,name VARCHAR(6), balance
double)");
//插入 2 条记录
db.execSQL("insert into accounts values('111', 'tian',2000)");
db.execSQL("insert into accounts values('222', 'liu',8000)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS accounts");
onCreate(db);
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53



没有更多推荐了 [去首页]
image
文章
357
原创
284
转载
73
翻译
0
访问量
199063
喜欢
47
粉丝
6
码龄
5年
资源
0

文章目录

加载中...
0
0