Android SQL 超實用設計


 最近由於工作原因,經常需要保存用戶數據,其中涉及創建表格、增刪改查操作。雖然 SQLiteDatabase 提供 insert 、delete、update、query 方法,但每次都要小心翼翼傳入參數,對於頻繁操作數據數據比較容易出錯,影響工作效率。現在我重新學習項目中數據庫設計的方法,其中把每一張表字段寫在一個bean,通過繼承基礎 BaseDao ,調用公共的數據庫指令。 這樣做的好處很明顯:①邏輯清晰,方便以后數據的增添;②操作規范,不用每次打開數據庫或者關閉數據庫,避免忘記關閉數據庫等誤操作。
     現在自己寫了一個學生信息的 Demo ,SQL 操作示意圖如下,有興趣的朋友可以看看。
 
代碼詳解
1、布局文件相當簡單,設置創建數據庫、更新數據庫和增刪改查操作,代碼如下所示:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="fill_parent"
 4     android:layout_height="fill_parent"
 5     android:orientation="vertical">
 6 
 7     <Button
 8         android:id="@+id/createDatabase"
 9         android:layout_width="fill_parent"
10         android:layout_height="wrap_content"
11         android:background="@color/colorBackGround"
12         android:text="創建數據庫" />
13 
14     <Button
15         android:id="@+id/updateDatabase"
16         android:layout_width="fill_parent"
17         android:layout_height="wrap_content"
18         android:layout_marginTop="5dp"
19         android:background="@color/colorBackGround"
20         android:text="更新數據庫" />
21 
22     <Button
23         android:id="@+id/insert"
24         android:layout_width="fill_parent"
25         android:layout_height="wrap_content"
26         android:layout_marginTop="5dp"
27         android:background="@color/colorBackGround"
28         android:text="插入數據" />
29 
30     <Button
31         android:id="@+id/update"
32         android:layout_width="fill_parent"
33         android:layout_height="wrap_content"
34         android:layout_marginTop="5dp"
35         android:background="@color/colorBackGround"
36         android:text="更新數據" />
37 
38     <Button
39         android:id="@+id/query"
40         android:layout_width="fill_parent"
41         android:layout_height="wrap_content"
42         android:layout_marginTop="5dp"
43         android:background="@color/colorBackGround"
44         android:text="查詢數據" />
45 
46     <Button
47         android:id="@+id/delete"
48         android:layout_width="fill_parent"
49         android:layout_height="wrap_content"
50         android:layout_marginTop="5dp"
51         android:background="@color/colorBackGround"
52         android:text="刪除數據" />
53 </LinearLayout>

布局很簡單,頁面如下所示

2、自定義一個繼承 SQLiteOpenHelper 的類 SQLiteHelper,重寫 onCreate(SQLiteDatabase sqLiteDatabase) 和 onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) 方法。其中當調用 SQLiteHelper 的 getReadableDatabase() 或者 getWritableDatabase() 時,如果沒有創建數據庫,則自動創建數據庫;接着調用 onCreate(SQLiteDatabase sqLiteDatabase) 方法,一般在這里創建數據庫表,當有版本更新時,走 onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) 方法,更新最新的數據庫表。
 1 /**
 2  * Created by LCS on 2016/11/1.
 3  */
 4 public class SQLiteHelper extends SQLiteOpenHelper {
 5 
 6     private static final String TAG = "LCS_SQLiteHelper";
 7     private static final String db_name = "sql.db";//數據庫名稱
 8     private static final SQLiteDatabase.CursorFactory factory = null;//暫時用不到
 9     private static final int version = 1;//版本號,方便以后項目更新用戶數據庫
10     private static SQLiteHelper sqLiteHelper = null;//實例化 SQLiteHelper 對象
11 
12     //創建班級通訊錄
13     private static final String create_class_address = SQLInstruction.createClassAddress();
14     /**
15      * 構造函數
16      * @param context
17      */
18     public SQLiteHelper(Context context){
19         super(context, db_name, factory, version);
20     }
21 
22     /**
23      * 獲取實例
24      * @param context
25      * @return
26      */
27     public static SQLiteHelper getInstance(Context context){
28 
29         if(sqLiteHelper == null){
30             sqLiteHelper = new SQLiteHelper(context);
31         }
32         return sqLiteHelper;
33     }
34 
35     /**
36      * 第一次創建數據庫,調用此方法
37      * @param sqLiteDatabase
38      */
39     @Override
40     public void onCreate(SQLiteDatabase sqLiteDatabase) {
41 
42         //創建班級通訊錄表
43         sqLiteDatabase.execSQL(create_class_address);
44         Log.d(TAG,"create db");
45     }
46 
47     /**
48      * 更新數據庫
49      * @param sqLiteDatabase
50      * @param oldVersion
51      * @param newVersion
52      */
53     @Override
54     public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
55 
56         if(version > 1){
57             sqLiteDatabase.execSQL(create_class_address);
58             Log.d(TAG,"upgrade db");
59         }
60     }
61 }

3、先構建數據庫連接管理器類 ConnectionProvider,這是真正執行數據庫語句的位置。其中 execute(String sql) 可以執行數據庫增加、刪除和更新操作,query(String sql) 執行查找操作。被執行的的數據庫指令為 Stiing 類型,我們只需要檢查此語句正確性 ( 推薦使用 SQLite3 可視化工具 ),傳入給對應的方法即可,是不是很方便?

 1 /**
 2  * Created by lcs on 2016/11/2.
 3  * 連接管理器,數據庫語句真正執行位置
 4  */
 5 public class ConnectionProvider {
 6     private SQLiteDatabase db;
 7     private SQLiteHelper sqLiteHelper;
 8     private Context context;
 9     private static ConnectionProvider provider;
10 
11     public ConnectionProvider(Context context){
12         this.context = context;
13 /*        //初始化
14         initProvider();*/
15     }
16     //初始化
17     private void initProvider() {
18         if(sqLiteHelper == null){
19             sqLiteHelper = SQLiteHelper.getInstance(context);
20             db = null;
21         }
22         if(db == null){
23             db = sqLiteHelper.getWritableDatabase();
24         }
25     }
26 
27     /**
28      * 真正執行數據庫操作
29      * @param sql
30      */
31     public synchronized void execute(String sql){
32         //打開數據庫
33         openDB();
34         db.execSQL(sql);
35         //關閉數據庫
36         closeDB(db);
37     }
38 
39     /**
40      * 真正執行數據庫操作
41      * @param sql
42      */
43     public synchronized Cursor query(String sql){
44         //打開數據庫
45         openDB();
46         return db.rawQuery(sql,null);
47     }
48 
49     /**
50      * 打開數據庫
51      */
52     private void openDB() {
53         try {
54             initProvider();
55         }catch (Exception e){
56             e.printStackTrace();
57         }
58     }
59 
60     /**
61      * 關閉數據庫
62      * @param db
63      */
64     private void closeDB(SQLiteDatabase db) {
65         try {
66             sqLiteHelper = null;
67             db.releaseReference();
68         }catch (Exception e){
69             e.printStackTrace();
70         }
71     }
72 
73     /**
74      * 獲取 ConnectionProvider 實例
75      * @return
76      */
77     public static ConnectionProvider getInstance(Context context){
78         if(provider == null){
79             provider = new ConnectionProvider(context);
80         }
81         return provider;
82     }
83 }

4、構建基礎 Dao。BaseDao 很簡單,但很重要。當以后有操作數據庫需求,只需要定義 某某 Dao 繼承 BaseDao,即可調用公共的數據庫操作。

 1 /**
 2  * 基礎 Dao
 3  * Created by lcs on 2016/11/2.
 4  */
 5 public abstract class BaseDao <T>{
 6     private Context context;
 7     private ConnectionProvider provider;
 8 
 9     public BaseDao(Context context){
10         this.context = context;
11         this.provider = ConnectionProvider.getInstance(context);
12     }
13 
14     /**
15      * 執行 SQL 語句
16      */
17     public synchronized void execute(String sql){
18         provider.execute(sql);
19     }
20 
21     /**
22      * 執行 SQL 語句
23      */
24     public synchronized Cursor query(String sql){
25         return provider.query(sql);
26     }
27 
28     /**
29      * 是否有結果集
30      * @param c
31      * @return
32      */
33     protected synchronized boolean hasResult(Cursor c){
34         boolean has=false;
35         if(c.moveToFirst()&&c.getCount()>0){
36             has=true;
37         }
38         return has;
39     }
40 
41 }

5、創建學生信息 bean 。其中 StudentInfoBean 為需要存儲進數據庫的字段信息

 1 /**
 2  * Created by user on 2016/11/2.
 3  * 學生信息
 4  */
 5 public class StudentInfoBean {
 6     private String name = "";//姓名
 7     private String id = "";//學號
 8     private String age = "";//年齡
 9     private String tall = "";//身高
10 
11     public String getName() {
12         return name;
13     }
14 
15     public void setName(String name) {
16         this.name = name;
17     }
18 
19     public String getId() {
20         return id;
21     }
22 
23     public void setId(String id) {
24         this.id = id;
25     }
26 
27     public String getAge() {
28         return age;
29     }
30 
31     public void setAge(String age) {
32         this.age = age;
33     }
34 
35     public String getTall() {
36         return tall;
37     }
38 
39     public void setTall(String tall) {
40         this.tall = tall;
41     }
42 }

6、創建學生 Dao。其中 StudentDao 繼承 BaseDao,在通過學號 id 查找和刪除學生信息方法中,其實也可以傳入其他學生信息進行查找,例如學生 name 、age 等。還有通過 id 可能查到多條記錄,規范寫法應該寫成返回 StudentInfoBean 的 List 。

 1 /**
 2  * Created by lcs on 2016/11/2.
 3  * 學生信息的 Dao
 4  */
 5 public class StudentDao extends BaseDao {
 6 
 7     public StudentDao(Context context) {
 8         super(context);
 9     }
10 
11     /**
12      * 增加一條學生記錄
13      * @param studentInfoBean
14      * @return
15      */
16     public boolean addStudent(StudentInfoBean studentInfoBean){
17         boolean flag = false;
18         if(studentInfoBean != null){
19             flag = true;
20             execute(SQLInstruction.addStudent(studentInfoBean));
21             return flag;
22         }else {
23             return flag;
24         }
25     }
26 
27     /**
28      * 通過學號 id 刪除學生信息
29      * @param id
30      * @return
31      */
32     public boolean deleteStudentById(String id){
33         boolean flag = false;
34         if(id != "" && !id.isEmpty()){
35             flag = true;
36             execute(SQLInstruction.deleteStudentById(id));
37             return flag;
38         }else {
39             return flag;
40         }
41     }
42 
43     /**
44      * 更新指定列學生信息
45      * @param column
46      * @param old_value
47      * @param new_value
48      * @return
49      */
50     public boolean updateStudent(String column ,String old_value,String new_value){
51         boolean flag = false;
52         if(column != "" && !column.isEmpty()){
53             execute(SQLInstruction.updateStudent(column,old_value,new_value));
54             flag = true;
55             return flag;
56         }else {
57             return flag;
58         }
59     }
60 
61     /**
62      * 通過學號 id 查詢學生信息
63      * @param id
64      * @return
65      */
66     public StudentInfoBean queryStudent(String id){
67         StudentInfoBean studentInfoBean = new StudentInfoBean();
68         if(id != "" && !id.isEmpty()){
69             Cursor cursor = query(SQLInstruction.queryStudentById(id));
70             if(hasResult(cursor)){
71                 studentInfoBean.setName(cursor.getString(cursor.getColumnIndex("NAME")));
72                 studentInfoBean.setAge(cursor.getString(cursor.getColumnIndex("AGE")));
73                 studentInfoBean.setTall(cursor.getString(cursor.getColumnIndex("TALL")));
74                 cursor.moveToNext();
75             }
76             cursor.close();
77         }
78         return studentInfoBean;
79     }
80 }

7、看到現在,不知道你會不會覺得很奇怪,為什么還沒有涉及真正數據庫操作語句?那是因為我們把所有數據庫語句放在一個類中 SQLInstruction。為方便調用,將每一個數據庫操作方法設置為 static。看到這里,你是否發現如此設計數據庫操作好處呢?

 1 /**
 2  * Created by user on 2016/11/1.
 3  * 數據庫語句
 4  */
 5 public class SQLInstruction {
 6 
 7     /**
 8      * 創建班級通訊錄表
 9      *
10      * @return
11      */
12     public static String createClassAddress() {
13         StringBuffer sql = new StringBuffer();
14         sql.append("create table IF NOT EXISTS CLASS_ADDRESS("
15                 + "NAME String," + "ID int," +"AGE int,"
16                 + "TALL int," + "CLASS_NAME String" + " )");
17         return sql.toString();
18     }
19 
20     /**
21      * 在數據庫添加一條學生記錄
22      */
23     public static String addStudent(StudentInfoBean student){
24         StringBuffer sql = new StringBuffer("insert into CLASS_ADDRESS(")
25                 .append("NAME,")
26                 .append("ID,")
27                 .append("AGE,")
28                 .append("TALL")
29                 .append(") VALUES(");
30         sql.append("'").append(student.getName()).append("',");
31         sql.append("'").append(student.getId()).append("',");
32         sql.append("'").append(student.getAge()).append("',");
33         sql.append("'").append(student.getTall()).append("')");
34         return sql.toString();
35     }
36 
37     /**
38      * 通過學號 id 刪除學生信息
39      * @param id
40      * @return
41      */
42     public static String deleteStudentById(String id){
43         StringBuffer sql = new StringBuffer();
44         sql.append("delete from CLASS_ADDRESS where ID = '");
45         sql.append(id).append("'");
46         return sql.toString();
47     }
48 
49     /**
50      * 更新指定列學生信息
51      * @param column
52      * @param old_value
53      * @param new_value
54      * @return
55      */
56     public static String updateStudent(String column ,String old_value,String new_value){
57         StringBuffer sql = new StringBuffer();
58         sql.append("update CLASS_ADDRESS set ");
59         sql.append(column).append(" = ");
60         sql.append("'").append(new_value).append("'");
61         sql.append(" where ").append(column).append(" = ");
62         sql.append("'").append(old_value).append("'");
63         return sql.toString();
64     }
65 
66     /**
67      * 通過學號 id 查詢學生信息
68      * @param id
69      * @return
70      */
71     public static String queryStudentById(String id){
72         StringBuffer sql = new StringBuffer();
73         sql.append("select NAME,ID,AGE,TALL ");
74         sql.append("from CLASS_ADDRESS where ID = '");
75         sql.append(id).append("'");
76         return sql.toString();
77     }
78 
79 }

8、進入最后一步操作,在 Activity 進行數據庫操作。

 1 @Override
 2     public void onClick(View view) {
 3         StudentDao studentDao = null;
 4         switch (view.getId()){
 5             case R.id.createDatabase://創建數據庫
 6                 SQLiteHelper sqLiteHelper = new SQLiteHelper(SQLiteActivity.this);
 7                 SQLiteDatabase database_create = sqLiteHelper.getReadableDatabase();
 8                 database_create.close();
 9                 break;
10 
11             case R.id.updateDatabase://更新數據庫
12                 SQLiteHelper sqLiteHelper_update = new SQLiteHelper(SQLiteActivity.this);
13                 SQLiteDatabase database_update = sqLiteHelper_update.getWritableDatabase();
14                 database_update.close();
15                 break;
16 
17             case R.id.insert://插入兩條學生記錄
18                 if(studentDao == null){
19                     studentDao = new StudentDao(SQLiteActivity.this);
20                 }
21                 boolean insert_result1 = studentDao.addStudent(studentInfoBean1);
22                 boolean insert_result2 = studentDao.addStudent(studentInfoBean1);
23                 Log.d(TAG,String.valueOf(insert_result1));
24                 Log.d(TAG,String.valueOf(insert_result2));
25                 break;
26 
27             case R.id.delete://通過學號 id 刪除學生信息
28                 if(studentDao == null){
29                     studentDao = new StudentDao(SQLiteActivity.this);
30                 }
31                 boolean delete_result = studentDao.deleteStudentById("1000001");
32                 Log.d(TAG,String.valueOf(delete_result));
33                 break;
34 
35             case R.id.update://更新指定列學生信息
36                 if(studentDao == null){
37                     studentDao = new StudentDao(SQLiteActivity.this);
38                 }
39                 boolean update_result = studentDao.updateStudent("NAME", "小明", "飛天");
40                 Log.d(TAG,String.valueOf(update_result));
41                 break;
42 
43             case R.id.query://通過學號 id 查詢學生信息
44                 if(studentDao == null){
45                     studentDao = new StudentDao(SQLiteActivity.this);
46                 }
47                 StudentInfoBean studentInfoBean = studentDao.queryStudent("1000001");
48                 String age = studentInfoBean.getAge();
49                 String name = studentInfoBean.getName();
50                 String tall = studentInfoBean.getTall();
51                 Log.d(TAG,"age= " + age + "\nname = " + name + "\ntall= " + tall);
52                 break;
53         }
54     }

  現在重新看 SQL 操作示意圖,應該會覺得好理解些吧!

 


免責聲明!

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



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