轻量级的数据库SQLite
对于构造比较复杂的数据,Android提供了内置的SqlLite数据库存储数据,它是一个轻量的数据库引擎,且占用数据很少,专门用于资源有限的设备上。同时它不像Oracle、MySQL那样需要安装和启动,已经嵌入到手机上,SQLite数据库本身只是一个文件。
如果实际项目中有大量数据需要读写,或者并发访问,要放在服务器端的DATABASE
一般数据采用的固定的静态数据类型,而SQLite采用的是动态数据类型,会根据存入值自动判断。SQLite具有以下五种数据类型:
- 1.NULL:空值。
- 2.INTEGER:带符号的整型,具体取决有存入数字的范围大小。
- 3.REAL:浮点数字,存储为8-byte IEEE浮点数。
- 4.TEXT:字符串文本。
- 5.BLOB:二进制对象。
SQLiteDatabase简介
Android提供了SQLiteDatabase代表数据库。一旦指定了数据库的SQLiteDatabase对象,就可以通过SQLiteDatabase对象来管理、操作数据库了。
在SQLiteDatabase提供3种静态方法打开数据库(一般实际开发中不会直接使用)
- static SQLiteDatabase openDatabase(String path,SQLiteDatabase.CursorFactory factory,int flags):打开path文件所代表的SQLite数据库。
- static SQLiteDatabase openOrCreateDatabase(File file,SQLiteDatabase.Cursor factory):打开或创建file文件所代表的SQLite数据库。
- static SQLiteDatabase openOrCreateDatabase(String path,SQLiteDatabase.CursorFactory factory):打开或创建path文件所代表的SQLite数据库。
SQLiteDatabase操作数据库:
获得SQLiteDatabase对象后,就可以调用SQLiteDatabase方法操作数据库,SQLiteDatabase对象提供的常用方法:
-
create(SQLiteDatabase.CursorFactory factory) 创建数据库
-
execSQL(String sql,Object[] bindArgs)执行带占位符的SQL语句
-
execSQL(String sql) 执行SQL语句
-
rawQuery(String sql,String[] selectionArgs) 执行带占位符的查询
-
insert(String table,String nullColumnHack, ContentValues values):添加一条记录,表名、列名、参数集合。
-
delete(String table,String whereClause,String[] whereArgs):删除表中特定数据。表名、满足的条件、为条件传入的参数
-
update(String table,ContentValues values,String whereClause,String[] whereArgs):修改特定数据。表名、想更新的数据、满足的条件、为条件传入的参数
-
query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having, String orderBy):查询数据。表名、列名、查询条件、查询参数、分组、聚合函数、排序
使用SQLiteDatabase进行数据库操作的步骤:
- 获取SQLiteDatabase对象,它代表了与数据库的连接
- 调用SQLiteDatabase的方法来执行SQL语句:execSQL(……)、rawQuery(……)
- 操作SQLiteDatabase的查询结果,比如用SimpleCursorAdapter封装Cursor
- 关闭SQLiteDatabase,回收资源
示例代码:
//创建数据库
//SQLiteDatabase db=SQLiteDatabase.openOrCreateDatabase("/data/data/com.nsu.db/databases/stu.db",null);
SQLiteDatabase db=dbOpenHelper.getReadableDatabase();
//创建表
String sql = "create table dict(_id integer primary key autoincrement,word text,detail text)";
db.execSQL(sql);
//插入数据
db.execSQL("insert into user_info values(null,?,?)"
,new String[]{"小明","女"});
//删除数据
db.execSQL(“delete from user_info where _id = ?”,new String[]{cursor.getInt(positions)+“”})
//查询数据
String sql = "select * from dict where word like ? or detail like ?";
Cursor cursor = db.rawQuery(sql,
new String[]{"%"+key+"%","%"+key+"%"});
SQLiteOpenHelper类
SQLiteOpenHelper类是SQLiteDatabase一个辅助类。这个类的作用是生成一个数据库,并对数据库的版本进行管理。在实际项目中很少使用SQLiteDatabase的方法来打开数据库,通常会继承SQLiteOpenHelper开发子类。通过子类的相关方法打开数据库。
SQLiteOpenHelper是Android提供的一个管理数据库的工具类,可以用于管理数据库的创建和版本更新。创建SQLiteOpenHelper的子类,重写以下方法
- onCreate(SQLiteDatabase db)当第一次创建数据库时回调该方法
- onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion)当数据库版本更新时回调该方法
public class DBOpenHelper extends SQLiteOpenHelper {
private final static String CREATE_TABLE_SQL="create table employees(_id integer primary key autoincrement,name,age,department)";
public DBOpenHelper(Context context, int version) {
super(context,"zyl.db",null, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
Log.i("DBOpenHelper","---onCreate called ----");
sqLiteDatabase.execSQL(CREATE_TABLE_SQL);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
Log.i("DBOpenHelper","----onUpgrade called----");
sqLiteDatabase.execSQL("drop table if exists employees");
onCreate(sqLiteDatabase);
}
}
一旦得到SQLiteOpenHelper对象后,程序无需使用SQLiteDatabase的静态方法创建SQLiteDatabase实例,可以使用getWriteableDatabase()和getReadableDatabase()方法来获取一个用于操作数据库的SQLiteDatabase实例。
- 打开数据库:
getReadableDatabase():以读的方式打开数据库对应的SQLiteDatabase对象
getWriteableDatabase():以写的方式打开数据库对应的SQLiteDatabase对象 - 关闭数据库:
close():关闭所有打开的SQLiteDatabase
Cursor接口
Cursor是一个游标接口,游标是系统为用户开设的一个数据源缓冲区,用于存放SQL语句的执行结果。使用query方法时会得到一个Cursor对象,Cursor可以定位到结果集的某一行,通过移动指针遍历查询结果。
Cursor常用方法:
- move(int offset)将指针向上或向下移动指定的行数
- boolean moveToFirst()移动到第一行
- boolean moveToLast()移动到最后一行,成功则返回true
- boolean moveToNext()移动到下一行
- boolean moveToPosition(int position)移动到指定的行
- boolean moveToPrevious()移动到上一行
利用SimpleCursorAdapter解析Cursor:
SimpleCursorAdapter(Context context,int layout,Cursor c,String[] from,int[] to,int flags)
//flags推荐取值CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
context,R.layout.line,cursor,
new String[]{"news_title","news_content"},
new int[]{R.id.my_title,R.id.my_content}
)
注意:数据库表的主键列的列明必须为_id,否则会出现错误java.lang.IllegalArgumentException:column"_id" does not exist
SQLite事务操作:
SQLite支持事务,事务是针对数据库的一组操作,可以由一条或者多条SQL语句组成,事务具有原子性,也就是说事务中的语句要么都执行,要么都不执行,SQLiteDatabase中包含两个方法用于控制事务:
- beginTransaction():开始事务
- endTransaction():结束事务
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。
//获取数据库对象
SQLiteDatabase sqLiteDatabase=dbOpenHelper.getReadableDatabase();
sqLiteDatabase.beginTransaction();
try{
//批量处理的操作
sqLiteDatabase.execSQL("",new Object[]{});
sqLiteDatabase.execSQL("",new Object[]{});
//...
//设置事务标志成功,当结束事务时就会提交事务
sqLiteDatabase.setTransactionSuccessful();
}catch (Exception e){
Log.i("事务处理失败",e.toString());
}finally {
//结束事务
sqLiteDatabase.endTransaction();
sqLiteDatabase.close();
}
案例:员工管理
新建一个工程:主活动名为SQLiteOperateActivity,设置用户主界面:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
tools:context=".SQLiteOperateActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edtName"
android:hint="输入员工姓名"
android:layout_alignParentTop="true" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edtAge"
android:layout_below="@+id/edtName"
android:hint="输入员工年龄"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edtDepartment"
android:layout_below="@+id/edtAge"
android:hint="输入员工部门"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="新增"
android:id="@+id/btnInsert"
android:layout_below="@+id/edtDepartment"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView"
android:layout_below="@+id/btnInsert"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
布局样式:
设置每一个列表项的样式:itemt_employee.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Id"
android:id="@+id/txtId"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Name"
android:id="@+id/txtName"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/txtId"
android:layout_toEndOf="@+id/txtId" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Age"
android:id="@+id/txtAge"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/txtName"
android:layout_toEndOf="@+id/txtName" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Department"
android:id="@+id/txtDepartment"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/txtAge"
android:layout_toEndOf="@+id/txtAge" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:id="@+id/imgDelete"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:src="@android:drawable/ic_delete" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:id="@+id/imgEdit"
android:src="@android:drawable/ic_menu_edit"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/imgDelete"
android:layout_toStartOf="@+id/imgDelete" />
</RelativeLayout>
列表项样式:
创建数据库:DBOpenHelper类继承自SQLiteOpenHelper,在DBOpenHelper中完成数据库的创建工作:
public class DBOpenHelper extends SQLiteOpenHelper {
private final static String CREATE_TABLE_SQL="create table employees(" +
"_id integer primary key autoincrement," +
"name text," +
"age int," +
"department text)";
public DBOpenHelper(Context context, int version) {
super(context,"zyl.db",null, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
Log.i("DBOpenHelper","---onCreate called ----");
sqLiteDatabase.execSQL(CREATE_TABLE_SQL);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
Log.i("DBOpenHelper","----onUpgrade called----");
sqLiteDatabase.execSQL("drop table if exists employees");
onCreate(sqLiteDatabase);
}
}
创建数据库业务操作类:EmployeesDAO,在类中实现增、删、改、查操作。
public class EmployeesDAO {
private DBOpenHelper dbOpenHelper;
private static final String TABLENAME="employees";
public EmployeesDAO(Context context){
//创建DBOpenHelper对象
dbOpenHelper=new DBOpenHelper(context,1);
}
//向数据库插入一条记录
public void insert(String name,int age,String department){
//获取数据库对象
SQLiteDatabase sqLiteDatabase=dbOpenHelper.getReadableDatabase();
ContentValues contentValues=new ContentValues();
contentValues.put("name",name);
contentValues.put("age",age);
contentValues.put("department",department);
//向表中插入记录
sqLiteDatabase.insert(TABLENAME,null,contentValues);
sqLiteDatabase.close();
}
//根据_id删除记录
public int delete(int _id){
SQLiteDatabase sqLiteDatabase=dbOpenHelper.getReadableDatabase();
int count=sqLiteDatabase.delete(TABLENAME,"_id=?",new String[]{_id+""});
sqLiteDatabase.close();
return count;
}
//修改数据
public int update(String name,int age,String department,int _id){
SQLiteDatabase sqLiteDatabase=dbOpenHelper.getReadableDatabase();
ContentValues contentValues=new ContentValues();
contentValues.put("name",name);
contentValues.put("age",age);
contentValues.put("department",department);
int count=sqLiteDatabase.update(TABLENAME,contentValues,"_id=?",new String[]{_id+""});
sqLiteDatabase.close();
return count;
}
//查询所有数据
public ArrayList queryAll(){
SQLiteDatabase sqLiteDatabase=dbOpenHelper.getReadableDatabase();
Cursor cursor=sqLiteDatabase.query(TABLENAME,new String[]{"_id","name","age","department"},null,null,null,null,null);
ArrayList list=new ArrayList();
while(cursor.moveToNext()){
HashMap map=new HashMap();
map.put("_id",cursor.getInt(cursor.getColumnIndex("_id")));
map.put("name",cursor.getString(cursor.getColumnIndex("name")));
map.put("age",cursor.getInt(cursor.getColumnIndex("age")));
map.put("department",cursor.getString(cursor.getColumnIndex("department")));
list.add(map);
}
cursor.close();
dbOpenHelper.close();
return list;
}
}
创建自定义Adapter:EmployeesAdapter
public class EmployeesAdapter extends BaseAdapter {
private Context context;
private ArrayList list;
public EmployeesAdapter(Context context,ArrayList list){
this.context=context;
this.list=list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(final int i, View view, ViewGroup viewGroup) {
View itemView=view;
ViewHolder holder;
if(itemView==null){
LayoutInflater inflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView=inflater.inflate(R.layout.item_sqlite_operator,null);
holder=new ViewHolder();
holder.txtId=(TextView)itemView.findViewById(R.id.txtId);
holder.txtName=(TextView)itemView.findViewById(R.id.txtName);
holder.txtAge=(TextView)itemView.findViewById(R.id.txtAge);
holder.txtDepartment=(TextView)itemView.findViewById(R.id.txtDepartment);
holder.imgDelete=(ImageView)itemView.findViewById(R.id.imgDelete);
holder.imgEdit=(ImageView)itemView.findViewById(R.id.imgEdit);
itemView.setTag(holder);
}else{
holder=(ViewHolder) itemView.getTag();
}
holder.txtId.setText(((HashMap)list.get(i)).get("_id")+"");
holder.txtName.setText(((HashMap)list.get(i)).get("name").toString());
holder.txtAge.setText(((HashMap)list.get(i)).get("age")+"");
holder.txtDepartment.setText(((HashMap)list.get(i)).get("department").toString());
holder.imgEdit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder=new AlertDialog.Builder(context);
builder.setTitle("请输入更新后的值");
final View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_edit,null);
final EditText edtName = (EditText) dialogView.findViewById(R.id.edtName);
final EditText edtAge = (EditText) dialogView.findViewById(R.id.edtAge);
final EditText edtDepartment = (EditText) dialogView.findViewById(R.id.edtDepartment);
builder.setView(dialogView);
final AlertDialog dialog=builder.create();
edtAge.setText(((HashMap)list.get(i)).get("age").toString());
edtName.setText(((HashMap)list.get(i)).get("name").toString());
edtDepartment.setText(((HashMap)list.get(i)).get("department").toString());
Button btnSubmit=(Button)dialogView.findViewById(R.id.btnSubmit);
btnSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int _id=Integer.parseInt(((HashMap)list.get(i)).get("_id").toString());
String name=edtName.getText().toString();
int age=Integer.parseInt(edtAge.getText().toString());
String department=edtDepartment.getText().toString();
HashMap map=(HashMap) list.get(i);
map.put("_id",_id);
map.put("name",name);
map.put("age",age);
map.put("department",department);
EmployeesDAO dao=new EmployeesDAO(context);
dao.update(name,age,department,_id);
notifyDataSetChanged();
dialog.dismiss();
}
});
dialog.show();
}
});
holder.imgDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
DialogInterface.OnClickListener listener=new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int pi) {
EmployeesDAO dao=new EmployeesDAO(context);
dao.delete(Integer.parseInt(((HashMap)list.get(i)).get("_id").toString()));
list.remove(i);
notifyDataSetChanged();
}
};
AlertDialog.Builder builder=new AlertDialog.Builder(context);
builder.setTitle("确定删除该记录?");
builder.setNegativeButton("取消",null);
builder.setPositiveButton("确定",listener);
builder.show();
}
});
return itemView;
}
private static class ViewHolder{
public TextView txtId;
public TextView txtName;
public TextView txtAge;
public TextView txtDepartment;
public ImageView imgDelete;
public ImageView imgEdit;
}
}
编写主界面:SQLiteOperateActivity
public class SQLiteOperateActivity extends AppCompatActivity {
private EmployeesDAO employeesDAO;
private EmployeesAdapter employeesAdapter;
private ArrayList list;
private EditText edtName,edtAge,edtDepartment;
private ListView employeesListView;
private Button btnInsert;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sqlite_operate);
edtName=(EditText) findViewById(R.id.edtName);
edtAge=(EditText)findViewById(R.id.edtAge);
edtDepartment=(EditText) findViewById(R.id.edtDepartment);
employeesListView=(ListView)findViewById(R.id.listView);
btnInsert=(Button)findViewById(R.id.btnInsert);
employeesDAO=new EmployeesDAO(SQLiteOperateActivity.this);
list=employeesDAO.queryAll();
employeesAdapter=new EmployeesAdapter(SQLiteOperateActivity.this,list);
employeesListView.setAdapter(employeesAdapter);
btnInsert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String name=edtName.getText().toString();
String str_age=edtAge.getText().toString();
int age=Integer.parseInt("".equals(str_age)?"0":str_age);
String department=edtDepartment.getText().toString();
employeesDAO.insert(name,age,department);
list=employeesDAO.queryAll();
employeesAdapter=new EmployeesAdapter(SQLiteOperateActivity.this,list);
employeesListView.setAdapter(employeesAdapter);
edtName.setText("");
edtAge.setText("");
edtDepartment.setText("");
}
});
}
}
运行结果: