• Android(java)学习笔记135:SQLite数据库(表)的创建 以及 SQLite数据库的升级


    一、数据库的创建

    1.文件的创建

         //引用,如果文件不存在是不会创建的

      File  file = new File("haha.txt");

        //输出流写数据,文件才会被创建

      FileOutputStream  fos = new FileOutputStream(file);

      fos.write("".getBytes());

      fos.close();

    2.数据库的创建

    //执行下面这一点代码,数据库是不会被创建出来的。相当于File file = new File("one.txt");(文件one.txt也没有创建出来)

            MyDBOpenHelper helper = new MyDBOpenHelper(this);

    //如果要想创建数据库就必须执行下面的代码

           helper.getWritableDatabase();

    创建文件我们需要一个File类,创建数据库我们也需要一个特殊的类SQLiteOpenHelper(抽象类)

    (1)我创建一个新的Android工程如下:

    (2)我们找到SQLiteOpenHelper,发现这是一个抽象类,所以我们必须自定义一个SQLiteOpenHelper的子类实现类:MyDBOpenHelper

    代码如下:

     1 package com.himi.sqlite;
     2 
     3 import android.content.Context;
     4 import android.database.sqlite.SQLiteDatabase;
     5 import android.database.sqlite.SQLiteDatabase.CursorFactory;
     6 import android.database.sqlite.SQLiteOpenHelper;
     7 
     8 public class MyDBOpenHelper extends SQLiteOpenHelper {
     9 
    10     public MyDBOpenHelper(Context context, String name, CursorFactory factory,
    11             int version) {
    12         super(context, name, factory, version);
    13         // TODO 自动生成的构造函数存根
    14     }
    15 
    16     @Override
    17     public void onCreate(SQLiteDatabase db) {
    18         // TODO 自动生成的方法存根
    19         
    20     }
    21 
    22     @Override
    23     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    24         // TODO 自动生成的方法存根
    25         
    26     }
    27 
    28 }

    这里我们发现这个构造方法参数很多,很晕,这个我们慢慢仔细看看这个构造函数,如下:

    public MyDBOpenHelper(Context context, String name, CursorFactory factory,int version)

      context:上下文,用来打开或者创建数据库

      name:数据库文件的名称

      factory:用来创建游标对象,null就是使用默认的游标工厂

    这个游标是什么概念?不懂啊?没事我们这里就说明一下这个概念,要知道这个概念必然是解决问题思路抽取出来的,为解决问题而服务,只是我们不知道这个内在解决问题的思路,才会这样迷糊,没事,很快就好了。

    下面这个逻辑图就会让你明白:

    version:从数字1开始的一个版本号,用来数据库更新使用

    (3)上面已经知道构造函数的4个参数,一次性传入4个参数(context, name, factory, version)太过繁琐,这里修改只传入context。

    package com.himi.sqlite;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    
    /**
     * 相当于File类
     * @author Administrator
     *
     */
    public class MyDBOpenHelper extends SQLiteOpenHelper {
    
        public MyDBOpenHelper(Context context) {
            super(context, "Juck.db", null, 1);
            // TODO 自动生成的构造函数存根
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            // TODO 自动生成的方法存根
            
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO 自动生成的方法存根
            
        }
    
    }

    这时候我们已经创建出来了数据库工具类MyDBOpenHelper,接下来我们就可以在MainActivity中创建数据库,代码如下:

    package com.himi.sqlite;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    
    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            //执行下面这一点代码,数据库是不会被创建出来的。相当于File file = new File("one.txt");(文件one.txt也没有创建出来)
            MyDBOpenHelper helper = new MyDBOpenHelper(this);
            //如果要想创建数据库就必须执行下面的代码
            helper.getWritableDatabase();
        }
    
        
    }

    程序运行到手机上,我们在/data/data/com.himi.sqlite/databases目录下查找已经创建的数据库Juck.db,如下:

    二、数据库的表创建

        1.之前的MyDBOpenHelper继承SQLiteOpenHelper实现的抽象方法onCreate(), 数据库第一次创建的时候调用,如果数据库已经创建,就不会执行这个onCreate()方法,在onCreate()方法中我们往往执行创建表的操作:create table

        public void onCreate(SQLiteDatabase db)

      2.当数据库的版本需要更新的时候调用的方法:

        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)  

      这里我们知道我们在刚刚利用构造函数创建数据库的时候

    public MyDBOpenHelper(Context context) {
            super(context, "itheima.db", null, 1);
        }

    这里的默认数据库的版本号为version = 1,当我们修改版本号为version = 2,也就是说构造方法修改为如下:

    public MyDBOpenHelper(Context context) {
            super(context, "itheima.db", null, 2);
        }

    这就是说明数据库的版本由1升级到2,这样的话就会调用onUpgrade方法,顺便说一句数据库版本号只能升级,不能降级

    比如:起初我们创建的数据库版本为version = 1,如下代码:

    package com.himi.sqlite;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    
    /**
     * 相当于File类
     * @author Administrator
     *
     */
    public class MyDBOpenHelper extends SQLiteOpenHelper {
    
        public MyDBOpenHelper(Context context) {
            super(context, "Juck.db", null, 1);
            // TODO 自动生成的构造函数存根
        }
        
        /**
         * 数据库第一次创建的时候调用,如果数据库已经创建,就不会执行这段代码
         * @param db  代表的就是我们创建出来的数据库
         */
        @Override
        public void onCreate(SQLiteDatabase db) {
            //创建表
            db.execSQL("create table info (_id integer primary key autoincrement, name varchar(20), phone varchar(20))");
            
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO 自动生成的方法存根
            
        }
    
    }

    当我们想添加数据库info一个字段为money varchar(10),代码如下:

    package com.himi.sqlite;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    
    /**
     * 相当于File类
     * @author Administrator
     *
     */
    public class MyDBOpenHelper extends SQLiteOpenHelper {
    
        public MyDBOpenHelper(Context context) {
            super(context, "Juck.db", null, 2);    //  为了满足升级的需求,这里已经修改了版本号,由1修改为2
            // TODO 自动生成的构造函数存根
        }
        
        /**
         * 数据库第一次创建的时候调用,如果数据库已经创建,就不会执行这段代码
         * @param db  代表的就是我们创建出来的数据库
         */
        @Override
        public void onCreate(SQLiteDatabase db) {
            //创建表
            db.execSQL("create table info (_id integer primary key autoincrement, name varchar(20), phone varchar(20))");
            
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("alter table info add money varchar(10)");  //上面修改了版本号,这里就会调用onUpgrade()方法,从而实现添加money字段
            
        }
    
    }

    三、这样的话,完整的数据库创建和使用的代码我们也将完成了,如下:

    MainActivity.java:

     1 package com.itheima.dbcreate;
     2 
     3 import android.os.Bundle;
     4 import android.app.Activity;
     5 import android.view.Menu;
     6 
     7 public class MainActivity extends Activity {
     8 
     9     @Override
    10     protected void onCreate(Bundle savedInstanceState) {
    11         super.onCreate(savedInstanceState);
    12         setContentView(R.layout.activity_main);
    13         //执行下面的一行代码,数据库是不会别创建的了。
    14         MyDBOpenHelper helper = new MyDBOpenHelper(this);
    15         //如果想创建数据库必须执行,下一行代码
    16         helper.getWritableDatabase();
    17     }
    18 
    19     
    20 }

    而且MyDBOpenHelper.java:

     1 package com.itheima.dbcreate;
     2 
     3 import android.content.Context;
     4 import android.database.sqlite.SQLiteDatabase;
     5 import android.database.sqlite.SQLiteDatabase.CursorFactory;
     6 import android.database.sqlite.SQLiteOpenHelper;
     7 
     8 /**
     9  * 相当于File类
    10  * @author Administrator
    11  *
    12  */
    13 public class MyDBOpenHelper extends SQLiteOpenHelper {
    14 
    15     /**
    16      * @param context 上下文
    17      * @param name 数据库文件的名称
    18      * @param factory 用来创建游标对象, null就用默认的游标工厂
    19      * @param version 数据库的版本号 从1开始
    20      */
    21     public MyDBOpenHelper(Context context) {
    22         super(context, "itheima.db", null, 1);
    23     }
    24 
    25     /**
    26      * 数据库第一次被创建的时候调用,如果数据库已经创建,就不会执行这一句代码
    27      * @param db 代表的就是我们创建出来的数据库
    28      */
    29     @Override
    30     public void onCreate(SQLiteDatabase db) {
    31         System.out.println("哈哈哈,数据库被创建了。适合初始化数据库的表结构");
    32         //创建表
    33         db.execSQL("create table info (_id integer primary key autoincrement, name varchar(20), phone varchar(20)) ");
    34     }
    35     /**
    36      * 当数据库的版本需要更新的时候调用的方法
    37      */
    38     @Override
    39     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    40         System.out.println("onupgrade 数据库被升级啦 。哈哈哈,适合修改数据库的表结构");
    41         //db.execSQL("alter table info add money varchar(10)");
    42 
    43     }
    44 }

    四、特别说明:

    首先我们通过一张图引出一个问题,如下:

    有时候我们会经常处理数据库,这样的话就会出现很多版本的数据库。不同版本的数据库之间如果要升级,必须要做onUpgrade()方法中执行,比如

    上面图中:数据库版本1------>数据库版本2,这里只需要在构造方法中修改版本号为2,同时在 onUpgrade()方法中添加字段money即可;同样的道理,数据库版本2------>数据库版本3,这里只需要在构造方法中修改版本号为3,同时在 onUpgrade()方法中添加字段age即可

    相信你已经感觉到了,就是我们数据库升级的时候要考虑自己现在的版本(oldVersion  以及我们要升级的版本(newVersion

    所以这里我们要说一下这里:public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

    将来我们去上班的时候,你会发现有的项目做了很久,DBSQLiteHelper中的 onUpgrade()方法代码很复杂,可能都有好几百行,甚至要上千行,如下:

    @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            System.out.println("onupgrade 数据库被升级啦 。哈哈哈,适合修改数据库的表结构");
             for (int j = oldVersion; j <= newVersion; j++){
                switch(j) {
                case 1:
                    ........
                    break;
                case 2:
                    ........
                    break;
                case 3:
                    ........
                    break;
                case 4:
                    ........
                    break;
                case 5:
                    ........
                    break;
        
                    .
                    .
                    .            
                
                }
            }
        }

    为什么要在方法里写for循环,主要是考虑到夸数据库版本升级,比如有的用户一直不升级版本,数据库版本号一直是1,而客户端最新版本其实对应的数据库版本已经是4了,那么我中途可能对数据库做了很多修改,通过这个for循环,可以迭代升级,不会发生错误。

    你会发现onUpgrade()方法中,有很多类似switch……case……  或者 if……else;这些都是因为我们升级项目的时候,更新数据库,这样就会出现很多版本的数据库,用户在升级数据库的时候,这里会根据用户现在的数据库版本oldVersion,执行相应的操作升级到现在数据库版本newVersion。

    这样的话,用户升级软件的时候就不会清除你之前的数据,比如升级游戏的时候,之前的游戏登录账号和密码就还会记住,就不会要求用户重新输入,这样的用户体验是很好的

    但是往往有些垄断行业,升级软件就不会有这一大堆switch这样的判断,就会出现升级软件账号和密码要重新输入,就是因为它清空我们之前的数据库内容,但是这样的用户体验是很不好的,这只有垄断行业才会采用的,比如QQ升级。

  • 相关阅读:
    C#反射中Assembly.Load及Assembly.Load.CreateInstance
    ASP.NET知识点(一):面向接口,工厂模式的程序结构
    表格布局规范
    山塞一个PetShop 4.0(01)——最简单的数据库连接
    ASP.NET知识点(二):数据访问层的基础[SQLHelper]
    山塞一个PetShop ——源代码下载、安装、配置及体验
    OD基本快捷键及功能
    OD使用教程 调试篇01|解密系列
    OD基本快捷键及功能
    OD基本快捷键及功能
  • 原文地址:https://www.cnblogs.com/hebao0514/p/4753258.html
Copyright © 2020-2023  润新知