• Android菜鸟成长记11 -- sqlite数据库的设计和升降级


     Google为Andriod的较大的数据处理提供了SQLite,他在数据存储、管理、维护等各方面都相当出色,功能也非常的强大。SQLite具备下列特点:
      1.轻量级
      使用 SQLite 只需要带一个动态库,就可以享受它的全部功能,而且那个动态库的尺寸想当小。
      2.独立性
      SQLite 数据库的核心引擎不需要依赖第三方软件,也不需要所谓的“安装”。
      3.隔离性
      SQLite 数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件夹内,方便管理和维护。
      4.跨平台
      SQLite 目前支持大部分操作系统,不至电脑操作系统更在众多的手机系统也是能够运行,比如:Android。
      5.多语言接口
      SQLite 数据库支持多语言编程接口。
      6.安全性

      SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据。

    创建数据库的方法,在android开发中,要想为项目创建数据库,必须继承SQLiteOpenHelper类

      首先,我们创建一个类来继承SQLiteOpenHelper类

      

     1 package com.example.sqlltetest;
     2 
     3 import android.content.Context;
     4 import android.database.DatabaseErrorHandler;
     5 import android.database.sqlite.SQLiteDatabase;
     6 import android.database.sqlite.SQLiteDatabase.CursorFactory;
     7 import android.database.sqlite.SQLiteOpenHelper;
     8 import android.util.Log;
     9 
    10 public class MyDataBaseOpenOrCreate extends SQLiteOpenHelper{
    11 
    12     private static final String DB_NAME = "mydata.db"; // 数据库名称
    13     private static final int version = 1; // 数据库版本
    14 
    15     
    16 
    17     public MyDataBaseOpenOrCreate(Context context) {
    18         super(context, DB_NAME, null, version);
    19     }
    20 
    21     @Override
    22     public void onCreate(SQLiteDatabase db) {
    23         Log.i("tag", "欢迎你的加入");
    24         String sql_table = "create table t_student(stuid integer primary key autoincrement,stuName varchar(50))";
    25         db.execSQL(sql_table);
    26         String sql_1 = "insert into t_student(stuName) values ('小波')";
    27         String sql_2 = "insert into t_student(stuName) values ('小小波')";
    28         String sql_3 = "insert into t_student(stuName) values ('小小小波')";
    29         db.execSQL(sql_1);
    30         db.execSQL(sql_2);
    31         db.execSQL(sql_3);
    32     }
    33 
    34     @Override
    35     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newversion) {
    36         
    37     }
    38 
    39 }

    如过你的项目没有数据库的化,他会走onCreate()的方法,如果有的话,他是不会走onCreate()方法的,至于onUpgrade()方法,是当你数据库发生更新时触发的,上面我们通过日志打印来测试

    那么我们创建一个实体类来关联数据库

     

     1 package com.example.entity;
     2 
     3 public class student {
     4 
     5     private String stuid;
     6     private String stuName;
     7     private int age;//为了升级做准备的
     8     public String getStuid() {
     9         return stuid;
    10     }
    11     public void setStuid(String stuid) {
    12         this.stuid = stuid;
    13     }
    14     public String getStuName() {
    15         return stuName;
    16     }
    17     public void setStuName(String stuName) {
    18         this.stuName = stuName;
    19     }
    20     public int getAge() {
    21         return age;
    22     }
    23     public void setAge(int age) {
    24         this.age = age;
    25     }
    26     
    27 }

    后面我们直接通过程序来显示数据

      

     1 package com.example.sqlltetest;
     2 
     3 import java.util.*;
     4 
     5 import com.example.entity.student;
     6 
     7 import android.app.Activity;
     8 import android.database.Cursor;
     9 import android.database.sqlite.SQLiteDatabase;
    10 import android.os.Bundle;
    11 import android.util.Log;
    12 import android.view.LayoutInflater;
    13 import android.view.View;
    14 import android.view.ViewGroup;
    15 import android.widget.BaseAdapter;
    16 import android.widget.ListView;
    17 import android.widget.TextView;
    18 
    19 public class MainActivity extends Activity {
    20 
    21     private ListView lv;
    22     private List<student> list = new ArrayList<student>();
    23 
    24     @Override
    25     protected void onCreate(Bundle savedInstanceState) {
    26         super.onCreate(savedInstanceState);
    27         setContentView(R.layout.activity_main);
    28 
    29         MyDataBaseOpenOrCreate myDataBase = new MyDataBaseOpenOrCreate(
    30                 MainActivity.this);
    31         SQLiteDatabase db = myDataBase.getWritableDatabase();
    32         Log.i("tag", "创建数据库完成");
    33         Cursor cursor = db.query("t_student", null, null, null, null, null,
    34                 null);
    35         while (cursor.moveToNext()) {
    36             student s = new student();
    37             s.setStuName(cursor.getString(cursor.getColumnIndex("stuName")));
    38             
    39             list.add(s);
    40         }
    41         db.close();
    42         lv = (ListView) findViewById(R.id.listView1);
    43         lv.setAdapter(new BaseAdapter() {
    44 
    45             // 返回多少条记录
    46             @Override
    47             public int getCount() {
    48                 // TODO Auto-generated method stub
    49                 return list.size();
    50             }
    51 
    52             // 每一个item项,返回一次界面
    53             @Override
    54             public View getView(int position, View convertView, ViewGroup parent) {
    55                 View view = null;
    56 
    57         
    58                 LayoutInflater inflater = MainActivity.this.getLayoutInflater();
    59                 // 因为getView()返回的对象,adapter会自动赋给ListView
    60                 view = inflater.inflate(R.layout.list_item, null);
    61 
    62                 student m = list.get(position);
    63 
    64                 TextView tv_stuName = (TextView) view
    65                         .findViewById(R.id.tv_stuName);
    66                 tv_stuName.setText(m.getStuName());
    67 
    68 
    69                 return view;
    70             }
    71 
    72             @Override
    73             public Object getItem(int position) {
    74                 // TODO Auto-generated method stub
    75                 return null;
    76             }
    77 
    78             @Override
    79             public long getItemId(int position) {
    80                 // TODO Auto-generated method stub
    81                 return 0;
    82             }
    83 
    84         });
    85     }
    86 
    87 }

    显示的结果:

      

    当我们第一次运行的时候,在日志中可以看到之前oncreate()方法中日志

    但是当我们在重新运行一次的时候,日志是这样的

    由此可见,只有我们数据库没有这个数据库的时候他才会走oncreate()方法。

    因为我们创建的是app项目,会经常发生数据变化,所以我们就需要对数据库进行更新。

    更新的思路:

    当前版本 v1.0
      1.  没有安装过    会直接 走 onCreate()  
    --------------------------------------
     当前版本 v2.0   [onUpgrade 情况:n-1,onCreate 情况:1]    升级就会直接走  onUpgrade() 方法
      1.  v1.0 --> v2.0  onUpgrade   
      2.  没有安装过       onCreate()  
    -----------------------------------------
     当前版本 v3.0   [onUpgrade 情况:n-1,onCreate 情况:1]
      1.  v1.0 -->v3.0    onUpgrade   
          alter table t_message add column isdel bit default 0;
          插入数据
      2.  v2.0 -->v3.0    onUpgrade  
           alter table t_message add column isdel bit default 0;
      3.  没有安装过       onCreate()  
     
    ----------------------------------------------------------------------
     降级的设计关键点
    1、考虑云端要保存用户【自定义数据、行为习惯】。专业术语profile-->>提高用户黏度
    2、考虑[当前]的最低版本要求-->>降低维护成本
    3、尽可能本地的数据转移(所有新版本,都不删除字段)-->尽可能把未知变已知
        try catch 
     
    升级数据库的话,就在那个onUpgrade()方法中进行,我们把之前定义version(版本号)改为2,再在 onUpgrade()方法中修改数据库
      
     1 package com.example.sqlltetest;
     2 
     3 import android.content.Context;
     4 import android.database.DatabaseErrorHandler;
     5 import android.database.sqlite.SQLiteDatabase;
     6 import android.database.sqlite.SQLiteDatabase.CursorFactory;
     7 import android.database.sqlite.SQLiteOpenHelper;
     8 import android.util.Log;
     9 
    10 public class MyDataBaseOpenOrCreate extends SQLiteOpenHelper{
    11 
    12     private static final String DB_NAME = "mydata.db"; // 数据库名称
    13     private static final int version = 2; // 数据库版本
    14 
    15     
    16 
    17     public MyDataBaseOpenOrCreate(Context context) {
    18         super(context, DB_NAME, null, version);
    19     }
    20 
    21     @Override
    22     public void onCreate(SQLiteDatabase db) {
    23         Log.i("tag", "欢迎你的加入");
    24         String sql_table = "create table t_student(stuid integer primary key autoincrement,stuName varchar(50))";
    25         db.execSQL(sql_table);
    26         String sql_1 = "insert into t_student(stuName) values ('小波')";
    27         String sql_2 = "insert into t_student(stuName) values ('小小波')";
    28         String sql_3 = "insert into t_student(stuName) values ('小小小波')";
    29         db.execSQL(sql_1);
    30         db.execSQL(sql_2);
    31         db.execSQL(sql_3);
    32     }
    33 
    34     @Override
    35     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newversion) {
    36         if (oldVersion == 1){
    37             String sql_upgrade_1 = "alter table t_student add column age int default 18";
    38             db.execSQL(sql_upgrade_1);
    39             Log.i("db", "从1到2,升级成功!");
    40         }
    41         
    42     }
    43     
    44 
    45 }

     当然数据的改变,我们的显示也要跟着改变,我们对之前的MainActivity进行修改

       

     1 package com.example.sqlltetest;
     2 
     3 import java.util.*;
     4 
     5 import com.example.entity.student;
     6 
     7 import android.app.Activity;
     8 import android.database.Cursor;
     9 import android.database.sqlite.SQLiteDatabase;
    10 import android.os.Bundle;
    11 import android.util.Log;
    12 import android.view.LayoutInflater;
    13 import android.view.View;
    14 import android.view.ViewGroup;
    15 import android.widget.BaseAdapter;
    16 import android.widget.ListView;
    17 import android.widget.TextView;
    18 
    19 public class MainActivity extends Activity {
    20 
    21     private ListView lv;
    22     private List<student> list = new ArrayList<student>();
    23 
    24     @Override
    25     protected void onCreate(Bundle savedInstanceState) {
    26         super.onCreate(savedInstanceState);
    27         setContentView(R.layout.activity_main);
    28 
    29         MyDataBaseOpenOrCreate myDataBase = new MyDataBaseOpenOrCreate(
    30                 MainActivity.this);
    31         SQLiteDatabase db = myDataBase.getWritableDatabase();
    32         Log.i("tag", "创建数据库完成");
    33         Cursor cursor = db.query("t_student", null, null, null, null, null,
    34                 null);
    35         while (cursor.moveToNext()) {
    36             student s = new student();
    37             s.setStuName(cursor.getString(cursor.getColumnIndex("stuName")));
    38             s.setAge(cursor.getInt(cursor.getColumnIndex("age")));
    39             list.add(s);
    40         }
    41         db.close();
    42         lv = (ListView) findViewById(R.id.listView1);
    43         lv.setAdapter(new BaseAdapter() {
    44 
    45             // 返回多少条记录
    46             @Override
    47             public int getCount() {
    48                 // TODO Auto-generated method stub
    49                 return list.size();
    50             }
    51 
    52             // 每一个item项,返回一次界面
    53             @Override
    54             public View getView(int position, View convertView, ViewGroup parent) {
    55                 View view = null;
    56 
    57                 // 布局不变,数据变
    58 
    59                 // 如果缓存为空,我们生成新的布局作为1个item
    60                 LayoutInflater inflater = MainActivity.this.getLayoutInflater();
    61                 // 因为getView()返回的对象,adapter会自动赋给ListView
    62                 view = inflater.inflate(R.layout.list_item, null);
    63 
    64                 student m = list.get(position);
    65 
    66                 TextView tv_stuName = (TextView) view
    67                         .findViewById(R.id.tv_stuName);
    68                 tv_stuName.setText(m.getStuName());
    69 
    70                 TextView tv_Age = (TextView) view.findViewById(R.id.tv_age);
    71                 tv_Age.setText(m.getAge() + "");
    72 
    73                 return view;
    74             }
    75 
    76             @Override
    77             public Object getItem(int position) {
    78                 // TODO Auto-generated method stub
    79                 return null;
    80             }
    81 
    82             @Override
    83             public long getItemId(int position) {
    84                 // TODO Auto-generated method stub
    85                 return 0;
    86             }
    87 
    88         });
    89     }
    90 
    91 }

    下面我们看一下日志和结果:

    好了,我们的数据库升级成功了,接着我们来尝试一下降级吧,

    我们先把version(版本好)换成1

      

    package com.example.sqlltetest;
    
    import android.content.Context;
    import android.database.DatabaseErrorHandler;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteDatabase.CursorFactory;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.util.Log;
    
    public class MyDataBaseOpenOrCreate extends SQLiteOpenHelper{
    
        private static final String DB_NAME = "mydata.db"; // 数据库名称
        private static final int version = 1; // 数据库版本
    
        
    
        public MyDataBaseOpenOrCreate(Context context) {
            super(context, DB_NAME, null, version);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.i("tag", "欢迎你的加入");
            String sql_table = "create table t_student(stuid integer primary key autoincrement,stuName varchar(50))";
            db.execSQL(sql_table);
            String sql_1 = "insert into t_student(stuName) values ('小波')";
            String sql_2 = "insert into t_student(stuName) values ('小小波')";
            String sql_3 = "insert into t_student(stuName) values ('小小小波')";
            db.execSQL(sql_1);
            db.execSQL(sql_2);
            db.execSQL(sql_3);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newversion) {
            if (oldVersion == 1){
                String sql_upgrade_1 = "alter table t_student add column age int default 18";
                db.execSQL(sql_upgrade_1);
                Log.i("db", "从1到2,升级成功!");
            }
            
        }
        
        @Override
        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            try {
                //第一、先把t_message 未来的表,改名
                String rename_sql = "alter table t_student rename to t_student_bak";
                db.execSQL(rename_sql);
                Log.i("down", "1.改名成功");
                //第二、建立降级的表名的表结构
                String sql_message = "create table t_student(stuid integer primary key autoincrement,stuName varchar(50))";
                db.execSQL(sql_message);
                Log.i("down", "2.建立2.0表结构成功");
                //第三、把备份的数据,copy到 新建的2.0的表(即将之前表名的数据插入到降级的版本中)
                String sql_copy = "insert into t_student select stuName from t_student_bak";
                db.execSQL(sql_copy);
                Log.i("down", "3.copy到用户数据到 2.0的表");
                //第四、把备份表drop掉
                String drop_sql = "drop table if exists t_student_bak";
                db.execSQL(drop_sql);
                Log.i("down", "4.把备份表drop掉");
                
            } catch (Exception e) {
                //如果上面的方法不行,采取最暴力的行为,把表删了,重新建立一张之前版本的表
                Log.i("hi", "降级失败,重新建立");
                String sql_drop_old_table = "drop table if exists t_student";
                String sql_message = "create table t_student(stuid integer primary key autoincrement,stuName varchar(50))";
                String sql_init_1 = "insert into t_student(stuName) values ('小波')";
                String sql_init_2 = "insert into t_student(stuName) values ('小明')";
                String sql_init_3 = "insert into t_student(stuName) values ('小红')";
                db.execSQL(sql_drop_old_table);
                db.execSQL(sql_message);
                db.execSQL(sql_init_1);
                db.execSQL(sql_init_2);
                db.execSQL(sql_init_3);
            }
        }
    
    }
     1 package com.example.sqlltetest;
     2 
     3 import java.util.*;
     4 
     5 import com.example.entity.student;
     6 
     7 import android.app.Activity;
     8 import android.database.Cursor;
     9 import android.database.sqlite.SQLiteDatabase;
    10 import android.os.Bundle;
    11 import android.util.Log;
    12 import android.view.LayoutInflater;
    13 import android.view.View;
    14 import android.view.ViewGroup;
    15 import android.widget.BaseAdapter;
    16 import android.widget.ListView;
    17 import android.widget.TextView;
    18 
    19 public class MainActivity extends Activity {
    20 
    21     private ListView lv;
    22     private List<student> list = new ArrayList<student>();
    23 
    24     @Override
    25     protected void onCreate(Bundle savedInstanceState) {
    26         super.onCreate(savedInstanceState);
    27         setContentView(R.layout.activity_main);
    28 
    29         MyDataBaseOpenOrCreate myDataBase = new MyDataBaseOpenOrCreate(
    30                 MainActivity.this);
    31         SQLiteDatabase db = myDataBase.getWritableDatabase();
    32         Log.i("tag", "创建数据库完成");
    33         Cursor cursor = db.query("t_student", null, null, null, null, null,
    34                 null);
    35         while (cursor.moveToNext()) {
    36             student s = new student();
    37             s.setStuName(cursor.getString(cursor.getColumnIndex("stuName")));
    38             //s.setAge(cursor.getInt(cursor.getColumnIndex("age")));
    39             list.add(s);
    40         }
    41         db.close();
    42         lv = (ListView) findViewById(R.id.listView1);
    43         lv.setAdapter(new BaseAdapter() {
    44 
    45             // 返回多少条记录
    46             @Override
    47             public int getCount() {
    48                 // TODO Auto-generated method stub
    49                 return list.size();
    50             }
    51 
    52             // 每一个item项,返回一次界面
    53             @Override
    54             public View getView(int position, View convertView, ViewGroup parent) {
    55                 View view = null;
    56 
    57                 // 布局不变,数据变
    58 
    59                 // 如果缓存为空,我们生成新的布局作为1个item
    60                 LayoutInflater inflater = MainActivity.this.getLayoutInflater();
    61                 // 因为getView()返回的对象,adapter会自动赋给ListView
    62                 view = inflater.inflate(R.layout.list_item, null);
    63 
    64                 student m = list.get(position);
    65 
    66                 TextView tv_stuName = (TextView) view
    67                         .findViewById(R.id.tv_stuName);
    68                 tv_stuName.setText(m.getStuName());
    69 
    70                 /*TextView tv_Age = (TextView) view.findViewById(R.id.tv_age);
    71                 tv_Age.setText(m.getAge() + "");*/
    72 
    73                 return view;
    74             }
    75 
    76             @Override
    77             public Object getItem(int position) {
    78                 // TODO Auto-generated method stub
    79                 return null;
    80             }
    81 
    82             @Override
    83             public long getItemId(int position) {
    84                 // TODO Auto-generated method stub
    85                 return 0;
    86             }
    87 
    88         });
    89     }
    90 
    91 }

     结果:

     因为我的数据主键用的是自增长,没有对数据降级的表的数据插入数据进行考虑,所以直接把之前那个表个删了在建一个新的。

  • 相关阅读:
    java架构之路-(面试篇)Mysql面试大全
    web工程的路径问题详解
    SQL知识点总结
    Mybatis简介
    mysql大全
    配置心得
    spring4.1.3+springmvc+mybatis3.2.1整合
    jstl标签
    jstl标签库
    Java并发控制机制
  • 原文地址:https://www.cnblogs.com/lsyverygood/p/6118205.html
Copyright © 2020-2023  润新知