android SQLite 使用實例


     Android作為眼下主流的移動操作系統,全然符合SQLite占用資源少的優勢,故在Android平台上,集成了一個嵌入式關系型數據庫—SQLite。假設想要開發 Android 應用程序,須要在 Android 上存儲數據,使用SQLite 數據庫是一種很好的選擇。在一般程序中使用數據庫的過程都能夠框架化,套路化,實比例如以下:


表說明:

1.班級 classes:

   class_id  主鍵 class_name 

2.學生 students:

   student_id 主鍵 student_name  score  class_id 外鍵


創建表:

CREATE TABLE classes(class_id varchar(10) primary key , class_name varchar(20))


CREATE TABLE students(student_id varchar(10) primary key ,

                                               student_name varchar(20) ,
                                               score varchar(4) ,
                                               class_id varchar(10),

                                              foreign key (class_id) references classes(class_id) on delete cascade on update cascade )





1. 繼承擴展 SQLiteOpenHelper 創建數據庫和相應表

package com.tang.databasedemo;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DBHelper extends SQLiteOpenHelper
{

	public DBHelper(Context context) {
		super(context, "info.db", null, 1);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void onCreate(SQLiteDatabase db) 
	{
		// TODO Auto-generated method stub
		String classesSQL = "CREATE TABLE classes(class_id varchar(10) primary key , " +
        		"class_name varchar(20))";
		
		String studentsSQL = "CREATE TABLE students(student_id varchar(10) primary key , " +
        		"student_name varchar(20) ,score varchar(4) ,class_id varchar(10), " +
        		"foreign key (class_id) references classes(class_id) " +
        		"on delete cascade on update cascade )";
		db.execSQL(classesSQL);
		Log.d("my", "create table classes:"+classesSQL);
		db.execSQL(studentsSQL);
		Log.d("my", "create table students:"+studentsSQL);
		
		
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
	{
		// TODO Auto-generated method stub
		
	}

}

2. 創建學生(Class)學生(Student)實體

package com.tang.databasedemo;
import android.util.Log;
public class Class 
{
	private String classId;
	private String className;
	
	public String getClassId() {
		return classId;
	}
	public void setClassId(String classId) {
		this.classId = classId;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public String toString() {
		return "Class--->"+"classId:"+classId+"  className:"+className;

	}
}

package com.tang.databasedemo;
public class Student 
{
	private String studentId;
	private String studentName;
	private String score;
	private String classId;
	
	public String getStudentId() {
		return studentId;
	}
	public void setStudentId(String studentId) {
		this.studentId = studentId;
	}
	public String getStudentName() {
		return studentName;
	}
	public void setStudentName(String studentName) {
		this.studentName = studentName;
	}
	public String getScore() {
		return score;
	}
	public void setScore(String score) {
		this.score = score;
	}
	public String getClassId() {
		return classId;
	}
	public void setClassId(String classId) {
		this.classId = classId;
	}
	public String  toString() 
	{
		return "Student--->"+"studentId:"+studentId+" studentName:"+studentName+" score:"+score+" classId:"+classId;
		
		
	}

}

3. 創建DBServer類,在該類中定義增刪改查等方法來操作數據庫

package com.tang.databasedemo;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class DBServer 
{
	private DBHelper dbhelper;
	public DBServer(Context context)
	{
		 this.dbhelper = new DBHelper(context);
	}
	/**
	 * 加入班級
	 * @param entity
	 */
	public void addClass(Class entity)
	{
		  
		  SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
		  Object[] arrayOfObject = new Object[2];
		  arrayOfObject[0] = entity.getClassId();
		  arrayOfObject[1] = entity.getClassName();
		  localSQLiteDatabase.execSQL("insert into classes(class_id,class_name) values(?,?)", arrayOfObject);
		  localSQLiteDatabase.close();
	}
	/**
	 * 加入學生
	 * @param entity
	 */
	public void addStudent(Student entity)
	{
		  
		  SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
		  Object[] arrayOfObject = new Object[4];
		  arrayOfObject[0] = entity.getStudentId();
		  arrayOfObject[1] = entity.getStudentName();
		  arrayOfObject[2] = entity.getScore();
		  arrayOfObject[3] = entity.getClassId();
		  localSQLiteDatabase.execSQL("insert into students(student_id,student_name,score,class_id) values(?,?,?,?)", arrayOfObject);
		  localSQLiteDatabase.close();
	}
	
	/**
	 * 刪除一個班級
	 * 同一時候會刪除students中該班級的學生
	 * @param class_id
	 */
	public void deleteClass(String class_id)
	{
	    SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
	    //設置了級聯刪除和級聯更新
	    //在運行有級聯關系的語句的時候必須先設置“PRAGMA foreign_keys=ON”
	    //否則級聯關系默認失效
	    localSQLiteDatabase.execSQL("PRAGMA foreign_keys=ON");
	    Object[] arrayOfObject = new Object[1];
	    arrayOfObject[0] =class_id;
	    localSQLiteDatabase.execSQL("delete from classes where class_id=?", arrayOfObject);
	    localSQLiteDatabase.close();
	}
	
	/**
	 * 刪除一個學生
	 * @param student_id
	 */
	public void deleteStudent(String student_id)
	{
	    SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
	    Object[] arrayOfObject = new Object[1];
	    arrayOfObject[0] =student_id;
	    localSQLiteDatabase.execSQL("delete from students where student_id=?", arrayOfObject);
	    localSQLiteDatabase.close();
	}
	
	/**
	 * 改動學生信息
	* @param entity
	*/
   public void updateStudentInfo(Student entity)
   {
	   SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();
	   Object[] arrayOfObject = new Object[4];
	   
	   arrayOfObject[0] = entity.getStudentName();
	   arrayOfObject[1] = entity.getScore();
	   arrayOfObject[2] = entity.getClassId();
	   arrayOfObject[3] = entity.getStudentId();
   
	   localSQLiteDatabase.execSQL("update students set student_name=?,score=?,class_id=?  where student_id=?", arrayOfObject);
	   localSQLiteDatabase.close();
   }
	
	/**
	 * 使用班級編號查找該班級全部學生
	 * @param classId
	 * @return
	 */
	public List<Student> findStudentsByClassId(String classId)
	{
		  List<Student> localArrayList=new ArrayList<Student>();
		  SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();    
		  Cursor localCursor = localSQLiteDatabase.rawQuery("select student_id, student_name ,score  from students  " +
		  		"where class_id=?  order by score desc", new String[]{classId});
		 
		  while (localCursor.moveToNext())
		  {
			  Student temp=new Student();
			  temp.setStudentId(localCursor.getString(localCursor.getColumnIndex("student_id")));
			  temp.setStudentName(localCursor.getString(localCursor.getColumnIndex("student_name")));
			  temp.setScore(localCursor.getString(localCursor.getColumnIndex("score")));
			  temp.setClassId(classId);
		      localArrayList.add(temp);
		  }
		  localSQLiteDatabase.close();
		  return localArrayList;
	 }
	
	/**
	 * 使用班級名查找該班級全部學生
	 * @param className
	 * @return
	 */
	public List<Student> findStudentsByClassName(String className)
	{
		  List<Student> localArrayList=new ArrayList<Student>();
		  SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();    
		  Cursor localCursor = localSQLiteDatabase.rawQuery("select student_id, student_name,score,classes.class_id from students,classes" +
		  		" where students.class_id=classes.class_id and classes.class_name =?  order by score asc" , new String[]{className});
		 
		  while (localCursor.moveToNext())
		  {
			  Student temp=new Student();
			  temp.setStudentId(localCursor.getString(localCursor.getColumnIndex("student_id")));
			  temp.setStudentName(localCursor.getString(localCursor.getColumnIndex("student_name")));
			  temp.setScore(localCursor.getString(localCursor.getColumnIndex("score")));
			  temp.setClassId(localCursor.getString(3));
		      localArrayList.add(temp);
		  }
		  localSQLiteDatabase.close();
		  return localArrayList;
	 }
	/**
	 * 查找全部學生
	 * @param className
	 * @return
	 */
	public List<Student> findAllStudents()
	{
		  List<Student> localArrayList=new ArrayList<Student>();
		  SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();    
		  Cursor localCursor = localSQLiteDatabase.rawQuery("select * from students " +
		  		"where 1=1  order by score desc ", null);
		  while (localCursor.moveToNext())
		  {
			  Student temp=new Student();
			  temp.setStudentId(localCursor.getString(localCursor.getColumnIndex("student_id")));
			  temp.setStudentName(localCursor.getString(localCursor.getColumnIndex("student_name")));
			  temp.setScore(localCursor.getString(localCursor.getColumnIndex("score")));
			  temp.setClassId(localCursor.getString(localCursor.getColumnIndex("class_id")));
		      localArrayList.add(temp);
		  }
		  localSQLiteDatabase.close();
		  return localArrayList;
	 }
	
	
	/**
	 * 	取得全部班級
	 * @return
	 */
	public List<Class> findAllClasses()
	{
		  List<Class> localArrayList=new ArrayList<Class>();
		  SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();    
		  Cursor localCursor = localSQLiteDatabase.rawQuery("select * from classes " +
		  		"where 1=1", null);
		  while (localCursor.moveToNext())
		  {
			  Class temp=new Class();
			  temp.setClassId(localCursor.getString(localCursor.getColumnIndex("class_id")));
			  temp.setClassName(localCursor.getString(localCursor.getColumnIndex("class_name")));
		      localArrayList.add(temp);
		  }
		  localSQLiteDatabase.close();
		  return localArrayList;
	 }
	
	/**
	 * 成績最好
	 * @return
	 */
	public Student findMaxScoreStudent()
	{
		Student temp =new Student();
		SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();    
		Cursor localCursor = localSQLiteDatabase.rawQuery("select student_id,student_name,class_id,max(score)  from students  " +
		  		"where 1=1",null );
		localCursor.moveToFirst();
		temp.setStudentId(localCursor.getString(0));
		temp.setStudentName(localCursor.getString(1));
		temp.setClassId(localCursor.getString(2));
		temp.setScore(localCursor.getString(3));
		return temp;
	}
	

	
	/**
	 * 查找是否有該學生
	 * @param studentId
	 * @return
	 */
	public boolean isStudentsExists(String studentId)
	{
		  SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();    
		  Cursor localCursor = localSQLiteDatabase.rawQuery("select count(*)  from students  " +
		  		"where student_id=?", new String[]{studentId});
		  localCursor.moveToFirst();
		  if(localCursor.getLong(0)>0)
			  return true;
		  else
			  return false;
	 }
	
	/**
	 * 確認該班級是否存在
	 * @param classId
	 * @return
	 */
	public boolean isClassExists(String s)
	{
		  SQLiteDatabase localSQLiteDatabase = this.dbhelper.getWritableDatabase();    
		  Cursor localCursor = localSQLiteDatabase.rawQuery("select count(*)  from classes  " +
		  		"where class_id=? or class_name=?", new String[]{s,s});
		  localCursor.moveToFirst();
		  if(localCursor.getLong(0)>0)
			  return true;
		  else
			  return false;
	 }

}

4.調用DBServer里的方法,操作數據

package com.tang.databasedemo;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.text.AlteredCharSequence;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {

	private List<Class> classData =new ArrayList<Class>();
	private List<Student> studentsData =new ArrayList<Student>();
	private static final String className ="A/B/C/D/E";
	private static final String studentName ="彭大/黃二/張三/李四/王五/鄭六/田七/周八/葉九/孔十/蕭十一";
	private DBServer db;
	private SharedPreferences share;
	private SharedPreferences.Editor editor;
	private String info ="";
	private EditText editText;
	private Button b,b1,b2,b3,b4,b5,b6;
	private EditText sId,sName,score,cId,cName;
	private Handler hander =new Handler()
	{
		@Override
		public void handleMessage(Message msg) 
		{
			// TODO Auto-generated method stub
			if(msg.what==0)
			{
				sId.setText("");
				sName.setText("");
				score.setText("");
				cName.setText("");
				cId.setText("");
			}
			else if(msg.what==1)
			{
				db.deleteClass((String)msg.obj);
				info += "刪除一個班級及班級里面的學生:班級Id:"+(String)msg.obj;
				editText.setText(info);
			}
			
		}
		
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
		share = getSharedPreferences("DatabaseDamo", 0);
		editor =share.edit();
		db=new DBServer(this);
		if(share.getInt("times", 0)==0)
		{
			initDatabase();
			editor.putInt("times", 1);
			editor.commit();
		}
	}
	
	
	private void initView()
	{
		editText = (EditText) findViewById(R.id.info);
		sId = (EditText) findViewById(R.id.studentId);
		sName = (EditText) findViewById(R.id.studentName);
		score = (EditText) findViewById(R.id.score);
		cId = (EditText) findViewById(R.id.classId);
		cName = (EditText) findViewById(R.id.className);
		b =(Button) findViewById(R.id.button);
		b1 =(Button) findViewById(R.id.button1);
		b2 =(Button) findViewById(R.id.button2);
		b3 =(Button) findViewById(R.id.button3);
		b4 =(Button) findViewById(R.id.button4);
		b5 =(Button) findViewById(R.id.button5);
		b6 =(Button) findViewById(R.id.button6);
		b.setOnClickListener(this);
		b1.setOnClickListener(this);
		b2.setOnClickListener(this);
		b3.setOnClickListener(this);
		b4.setOnClickListener(this);
		b5.setOnClickListener(this);
		b6.setOnClickListener(this);
		
		
	}
	private void initDatabase()
	{
		info="";
		editText.setText("");
		String []classTemp = className.split("/");
		Class c;
		for(int i=0;i<classTemp.length;i++)
		{
			c=new Class();
			c.setClassName(classTemp[i]);
			c.setClassId("00"+i);
			db.addClass(c);
			info+= '\n'+"add to database classes:"+c.toString();
		}		
		String []studentTemp = studentName.split("/");
		Student s;
		for(int j=0;j<studentTemp.length;j++)
		{
			s=new Student();
			s.setStudentName(studentTemp[j]);
			s.setStudentId("2014050"+j);
			s.setClassId("00"+new Random().nextInt(classTemp.length));
			s.setScore(String.valueOf(new Random().nextInt(100)+1));
			db.addStudent(s);
			info+= '\n'+ "add to database students:"+'\n'+s.toString();
		}
		editText.setText(info);
	}

	private void addAStudent()
	{
		info ="";
		editText.setText("");
		String tempSID = sId.getText().toString();
		String tempSName = sName.getText().toString();
		String tempScore = score.getText().toString();
		String tempCID = cId.getText().toString();
		if(checkInfo(tempSID)&&checkInfo(tempSName)&&checkInfo(tempScore)&&checkInfo(tempCID))
		{
			Student temp =new Student();
			temp.setStudentId(tempSID);
			temp.setStudentName(tempSName);
			temp.setScore(tempScore);
			temp.setClassId(tempCID);
			db.addStudent(temp);
			info+=  "add to database students:"+'\n'+temp.toString();
		}
		else
		{
			info += "加入一個學生失敗:缺少必要信息,請確認studentId,studentName,score,classId的信息是否完整!";
		}
		editText.setText(info);
	}
	
	
	private void deleteAClass()
	{
		info ="";
		editText.setText("");
		final String tempCID = cId.getText().toString();
		if(checkInfo(tempCID))
		{
			if(db.isClassExists(tempCID))
			{
				new AlertDialog.Builder(this)
				.setTitle("提示:")
				.setMessage("刪除一個班級將會刪除該班的全部學生信息,確定?")
				.setPositiveButton("確定",new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						// TODO Auto-generated method stub
						Message msg =new Message();
						msg.what = 1;
						msg.obj = tempCID;
						hander.sendMessage(msg);
					}
				})
				.setNegativeButton("取消", null)
				.show();
			}
			else
				info += "刪除一個班級失敗:查無此相應班級,請確認classId的信息是否正確!";
		}
		else
		{
			info += "刪除一個班級失敗:缺少必要信息,請確認classId的信息是否完整!";
		}
		editText.setText(info);
	}
	
	private void deleteAStudent()
	{
		info ="";
		editText.setText("");
		String tempSID = sId.getText().toString();
		if(checkInfo(tempSID))
		{
			if(db.isStudentsExists(tempSID))
			{
				db.deleteStudent(tempSID);
				info += "刪除一個學生:學生Id:"+tempSID;
			}
			else
				info += "刪除一個學生失敗:查無此相應學生,請確認studentId的信息是否正確!";
		}
		else
		{
			info += "刪除一個學生失敗:缺少必要信息,請確認studentId的信息是否完整!";
		}
		editText.setText(info);
	}
	
	
	private void updateStudent()
	{
		info ="";
		editText.setText("");
		String tempSID = sId.getText().toString();
		String tempSName = sName.getText().toString();
		String tempScore = score.getText().toString();
		String tempCID = cId.getText().toString();
		if(checkInfo(tempSID)&&checkInfo(tempSName)&&checkInfo(tempScore)&&checkInfo(tempCID))
		{
			if(db.isStudentsExists(tempSID))
			{
				Student temp =new Student();
				temp.setStudentId(tempSID);
				temp.setStudentName(tempSName);
				temp.setScore(tempScore);
				temp.setClassId(tempCID);
				db.updateStudentInfo(temp);
				info+=  "update database students:"+'\n'+temp.toString();
			}
			else
			{
				Student temp =new Student();
				temp.setStudentId(tempSID);
				temp.setStudentName(tempSName);
				temp.setScore(tempScore);
				temp.setClassId(tempCID);
				db.addStudent(temp);
				info+= "沒有找到相應ID的學生,將此學生加入到數據庫!"+'\n'+
						"add to database students:"+'\n'+temp.toString();
			}
		}
		else
		{
			info += "更新學生失敗:缺少必要信息,請確認studentId,studentName,score,classId的信息是否完整!";
		}
		editText.setText(info);
	}
	
	/**
	 * 打印某班的學生
	 */
	private void printStudentsOfClass()
	{
		info ="";
		editText.setText("");
		String tempCID = cId.getText().toString();
		String tempCName = cName.getText().toString();
		if(checkInfo(tempCID))
		{
			if(db.isClassExists(tempCID))
			{
				info += "使用ID查詢";
				studentsData.clear();
				studentsData= db.findStudentsByClassId(tempCID);
			}
			else
			{
				info += "該ID相應的班級不存在";
			}	
		}
		else if(checkInfo(tempCName))
		{
			if(db.isClassExists(tempCName))
			{
				info += "使用Name查詢";
				studentsData.clear();
				studentsData = db.findStudentsByClassName(tempCName);
			}
			else
			{
				info += "該Name相應的班級不存在";
			}
		}
		else
		{
			studentsData.clear();
			info += "查找學生失敗:缺少必要信息,請確認classId或className的信息是否完整!";
		}
		for(int i=0;i<studentsData.size();i++)
		{
			info+= '\n'+studentsData.get(i).toString();
		}
		editText.setText(info);;
	}

	private void printMaxScoreStudent()
	{
		info ="";
		editText.setText("");
		Student temp =db.findMaxScoreStudent();
		info+= '\n'+temp.toString();
		editText.setText(info);;
	}
	
	
	private void getAllStudent()
	{
		studentsData.clear();
		studentsData = db.findAllStudents();
		for(int i=0;i<studentsData.size();i++)
		{
			info+= '\n'+studentsData.get(i).toString();
		}
	}
	
	private void getAllClass()
	{
		classData.clear();
		classData = db.findAllClasses();
		for(int i=0;i<classData.size();i++)
		{
			info+= '\n'+classData.get(i).toString();
		}
	}
	
	private void printAllInfo()
	{
		info ="";
		editText.setText("");
		getAllStudent();
		getAllClass();
		editText.setText(info);
		
	}
	
	@Override
	public void onClick(View v) 
	{
		// TODO Auto-generated method stub
		int id = v.getId();
		switch(id)
		{
			case R.id.button:
				printAllInfo();
				break;
			case R.id.button1:
				addAStudent();
				break;
			case R.id.button2:
				deleteAStudent();
				break;
			case R.id.button3:
				deleteAClass();
				break;
			case R.id.button4:
				updateStudent();
				break;
			case R.id.button5:
				printStudentsOfClass();
				break;
			case R.id.button6:
				printMaxScoreStudent();
				break;
		}
		hander.sendEmptyMessageDelayed(0, 5000);
	}

	private boolean checkInfo(String s)
	{
		if(s.equals("")||s==null)
			return false;
		else
			return true;
	}
}

附圖一張:


注:

1 . 關於游標(Cursor)

    在查詢返回的是一個Cursor類型的對象,它是一個指針,且永遠都不會為空,所以,當查詢某語句,並推斷返回值是否為空時,切勿用cursor==null表示。而有個方法,cursor.getCount()==0就能推斷其結果值是否為空了。

close()
關閉游標,釋放資源
copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) yB
在緩沖區中檢索請求的列的文本,將將其存儲
getColumnCount()
返回全部列的總數
getColumnIndex(String columnName)
返回指定列的名稱,假設不存在返回-1
getColumnIndexOrThrow(String columnName)
從零開始返回指定列名稱,假設不存在將拋出IllegalArgumentException 異常。
getColumnName(int columnIndex)
從給定的索引返回列名
getColumnNames()
返回一個字符串數組的列名
getCount()
返回Cursor 中的行數
moveToFirst()
移動光標到第一行
moveToLast()
移動光標到最后一行
moveToNext()
移動光標到下一行
moveToPosition(int position)
移動光標到一個絕對的位置
moveToPrevious()
移動光標到上一行

2. 關於on delete cascade on update cascade 級聯更新和級聯刪除

   SQLite在3.6.19版本號中才開始支持外鍵約束,可是為了兼容曾經的程序,默認並沒有啟用該功能,假設要啟用該功能每次都要須要使用例如以下語句:PRAGMA foreign_keys = ON來打開。也就是說,在運行刪除一個班級的語句的時候須要運行db.execSQL("PRAGMA foreign_keys=ON")

可見:http://blog.csdn.net/tangnengwu/article/details/25980263


3.關於getWritableDatabase()和getReadableDatabase()

  這2個方法都能夠獲取SQLiteDatabase的實例,當使用getWritableDatabase() 方法打開數據庫時,一旦數據庫的磁盤空間滿了,數據庫在運行寫操作的時候就會出錯,

而getReadableDatabase()方法則是先以讀寫方式打開數據庫,假設數據庫的磁盤空間滿了,就會打開失敗,當打開失敗后會繼續嘗試以僅僅讀方式打開數據庫。假設該問題成功

解決,則僅僅讀數據庫對象就會關閉,然后返回一個可讀寫的數據庫對象。也就是說getReadableDatabase()將getWritableDatabase()在安全上進行了優化。

在4.4的源代碼中:/frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java

 /**
     * Create and/or open a database that will be used for reading and writing.
     * The first time this is called, the database will be opened and
     * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
     * called.
     *
     * <p>Once opened successfully, the database is cached, so you can
     * call this method every time you need to write to the database.
     * (Make sure to call {@link #close} when you no longer need the database.)
     * Errors such as bad permissions or a full disk may cause this method
     * to fail, but future attempts may succeed if the problem is fixed.</p>
     *
     * <p class="caution">Database upgrade may take a long time, you
     * should not call this method from the application main thread, including
     * from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
     *
     * @throws SQLiteException if the database cannot be opened for writing
     * @return a read/write database object valid until {@link #close} is called
     */
    public SQLiteDatabase getWritableDatabase() {
        synchronized (this) {
            return getDatabaseLocked(true);
        }
    }

    /**
     * Create and/or open a database.  This will be the same object returned by
     * {@link #getWritableDatabase} unless some problem, such as a full disk,
     * requires the database to be opened read-only.  In that case, a read-only
     * database object will be returned.  If the problem is fixed, a future call
     * to {@link #getWritableDatabase} may succeed, in which case the read-only
     * database object will be closed and the read/write object will be returned
     * in the future.
     *
     * <p class="caution">Like {@link #getWritableDatabase}, this method may
     * take a long time to return, so you should not call it from the
     * application main thread, including from
     * {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
     *
     * @throws SQLiteException if the database cannot be opened
     * @return a database object valid until {@link #getWritableDatabase}
     *     or {@link #close} is called.
     */
    public SQLiteDatabase getReadableDatabase() {
        synchronized (this) {
            return getDatabaseLocked(false);
        }
    }

    private SQLiteDatabase getDatabaseLocked(boolean writable) {
        if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // Darn!  The user closed the database by calling mDatabase.close().
                mDatabase = null;
            } else if (!writable || !mDatabase.isReadOnly()) {
                // The database is already open for business.
                return mDatabase;
            }
        }

        if (mIsInitializing) {
            throw new IllegalStateException("getDatabase called recursively");
        }

        SQLiteDatabase db = mDatabase;
        try {
            mIsInitializing = true;

            if (db != null) {
                if (writable && db.isReadOnly()) {
                    db.reopenReadWrite();
                }
            } else if (mName == null) {
                db = SQLiteDatabase.create(null);
            } else {
                try {
                    if (DEBUG_STRICT_READONLY && !writable) {
                        final String path = mContext.getDatabasePath(mName).getPath();
                        db = SQLiteDatabase.openDatabase(path, mFactory,
                                SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                    } else {
                        db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
                                Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
                                mFactory, mErrorHandler);
                    }
                } catch (SQLiteException ex) {
                    if (writable) {
                        throw ex;
                    }
                    Log.e(TAG, "Couldn't open " + mName
                            + " for writing (will try read-only):", ex);
                    final String path = mContext.getDatabasePath(mName).getPath();
                    db = SQLiteDatabase.openDatabase(path, mFactory,
                            SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                }
            }

            onConfigure(db);

            final int version = db.getVersion();
            if (version != mNewVersion) {
                if (db.isReadOnly()) {
                    throw new SQLiteException("Can't upgrade read-only database from version " +
                            db.getVersion() + " to " + mNewVersion + ": " + mName);
                }

                db.beginTransaction();
                try {
                    if (version == 0) {
                        onCreate(db);
                    } else {
                        if (version > mNewVersion) {
                            onDowngrade(db, version, mNewVersion);
                        } else {
                            onUpgrade(db, version, mNewVersion);
                        }
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            }

            onOpen(db);

            if (db.isReadOnly()) {
                Log.w(TAG, "Opened " + mName + " in read-only mode");
            }

            mDatabase = db;
            return db;
        } finally {
            mIsInitializing = false;
            if (db != null && db != mDatabase) {
                db.close();
            }
        }
    }

對於getReadableDatabase()的凝視,大致意思也就是:

    getWritableDatabase()和getReadableDatabase()會返回同樣的對象,除非出現了一些如空間已滿的問題,這時就會返回一個僅僅讀的對象。當問題攻克了之后,僅僅讀對象將會被關閉,這時就會返回一個可讀寫的對象。



SQL實例可運行代碼:

http://download.csdn.net/detail/tangnengwu/7369503





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM