最近由于工作原因,经常需要保存用户数据,其中涉及创建表格、增删改查操作。虽然 SQLiteDatabase 提供 insert 、delete、update、query 方法,但每次都要小心翼翼传入参数,对于频繁操作数据数据比较容易出错,影响工作效率。现在我重新学习项目中数据库设计的方法,其中把每一张表字段写在一个bean,通过继承基础 BaseDao ,调用公共的数据库指令。 这样做的好处很明显:①逻辑清晰,方便以后数据的增添;②操作规范,不用每次打开数据库或者关闭数据库,避免忘记关闭数据库等误操作。

 最近由于工作原因,经常需要保存用户数据,其中涉及创建表格、增删改查操作。虽然 SQLiteDatabase 提供 insert 、delete、update、query 方法,但每次都要小心翼翼传入参数,对于频繁操作数据数据比较容易出错,影响工作效率。现在我重新学习项目中数据库设计的方法,其中把每一张表字段写在一个bean,通过继承基础 BaseDao ,调用公共的数据库指令。 这样做的好处很明显:①逻辑清晰,方便以后数据的增添;②操作规范,不用每次打开数据库或者关闭数据库,避免忘记关闭数据库等误操作。

     现在自己写了一个学生信息的 Demo ,SQL 操作示意图如下,有兴趣的朋友可以看看。

android建立数据库 android数据库设计_android建立数据库

 

代码详解

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>

布局很简单,页面如下所示

android建立数据库 android数据库设计_android_02

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 操作示意图,应该会觉得好理解些吧!