SQLite的使用和实现一个简单的数据库框架

SQLite的使用和实现一个简单的数据库框架

技术杂谈小彩虹2021-08-24 23:11:29180A+A-

SQLite的基本知识

SQLite常用的数据类型

字段 作用
char(n) 固定n长度的字串
varchar(n) 长度不固定的字符串,n表示最大的长度
nchar(n) 同char,不同的是可以用来存储中文
nvarchar(n) 同varchar,不同的是可以用来存储中文
text 存储文本
blob 存储二进制文件
int 整形
integer 整形
bigint 整形
float 单精度类型
double 双精度浮点

这里intintegerbigint的具体区别,还没弄明白。如果有哪个大佬了解,请在评论区指导一下

创建和删除数据表

创建表的为语法:

create table database_name.table_name(
   column1 datatype  primary key(one or more columns),
   column2 datatype,
   column3 datatype,
   .....
   columnN datatype,
);

删除数据表的语法为

drop table database_name.table_name;

插入数据

插入数据表的语法为:

insert into table_name [(column1, column2, column3,...columnN)]  
values (value1, value2, value3,...valueN);
或
//注意:这种方式要确保值的顺序与列在表中的顺序一致
insert into table_name values (value1,value2,value3,...valueN);

删除数据

删除数据的语法为:

delete from table_name [条件];

如果没有删除数据的条件,默认删除所有数据;如果指定了条件,则删除符合条件的 数据

更新数据

语法为:

update table_name
set column1 = value1, column2 = value2...., columnN = valueN [条件];

查询数据

语法为:

//查询指定字段(列)的值
SELECT column1, column2, columnN FROM table_name;
或
//查询所有字段的值
SELECT * FROM table_name;

SQLite的逻辑运算符

运算符 描述
AND AND 运算符允许在一个 SQL 语句的 WHERE 子句中的多个条件的存在
BETWEEN BETWEEN 运算符用于在给定最小值和最大值范围内的一系列值中搜索值
EXISTS EXISTS 运算符用于在满足一定条件的指定表中搜索行的存在
IN IN 运算符用于把某个值与一系列指定列表的值进行比较
NOT IN IN 运算符的对立面,用于把某个值与不在一系列指定列表的值进行比较
LIKE LIKE 运算符用于把某个值与使用通配符运算符的相似值进行比较
GLOB GLOB 运算符用于把某个值与使用通配符运算符的相似值进行比较。GLOB 与 LIKE 不同之处在于,它是大小写敏感的
NOT NOT 运算符是所用的逻辑运算符的对立面。比如 NOT EXISTS、NOT BETWEEN、NOT IN,等等。它是否定运算符
OR OR 运算符用于结合一个 SQL 语句的 WHERE 子句中的多个条件
IS NULL NULL 运算符用于把某个值与 NULL 值进行比较
IS IS 运算符与 = 相似
IS NOT IS NOT 运算符与 != 相似
|| 连接两个不同的字符串,得到一个新的字符串
UNIQUE UNIQUE 运算符搜索指定表中的每一行,确保唯一性(无重复)

where

where用来过滤数据的,例如select * from employee where salary >= 65000;是指查询工资高于65000的员工的数据,使用where salary >= 65000;来过滤数据

and/or

and相当于逻辑与运算,只有条件全为真时,结果才为真;or相当于逻辑或运算,只要其中一个条件为真,结果就为真。

LIKE

LIKE运算符是用来匹配通配符指定模式的文本值。如果搜索表达式与模式表达式匹配,LIKE 运算符将返回真(true),也就是 1。这里有两个通配符与 LIKE 运算符一起使用:

  • 百分号 (%)
  • 下划线 (_)

百分号(%)代表零个、一个或多个数字或字符。下划线(_)代表一个单一的数字或字符。这些符号可以被组合使用。

下面一些实例演示了 带有 '%' 和 '_' 运算符的 LIKE 子句不同的地方:

语句 描述
WHERE SALARY LIKE '200%' 查找以 200 开头的任意值
WHERE SALARY LIKE '%200%' 查找任意位置包含 200 的任意值
WHERE SALARY LIKE '_00%' 查找第二位和第三位为 00 的任意值
WHERE SALARY LIKE '2_%_%' 查找以 2 开头,且长度至少为 3 个字符的任意值
WHERE SALARY LIKE '%2' 查找以 2 结尾的任意值
WHERE SALARY LIKE '_2%3' 查找第二位为 2,且以 3 结尾的任意值
WHERE SALARY LIKE '2___3' 查找长度为 5 位数,且以 2 开头以 3 结尾的任意值

GLOB

GLOB 运算符是用来匹配通配符指定模式的文本值。如果搜索表达式与模式表达式匹配,GLOB 运算符将返回真(true),也就是 1。与 LIKE 运算符不同的是,GLOB 是大小写敏感的,对于下面的通配符,它遵循 UNIX 的语法。

  • 星号 (*)
  • 问号 (?)

星号(*)代表零个、一个或多个数字或字符。问号(?)代表一个单一的数字或字符。这些符号可以被组合使用。

语句 描述
WHERE SALARY GLOB '200*' 查找以 200 开头的任意值
WHERE SALARY GLOB '200' 查找任意位置包含 200 的任意值
WHERE SALARY GLOB '?00*' 查找第二位和第三位为 00 的任意值
WHERE SALARY GLOB '2??' 查找以 2 开头,且长度至少为 3 个字符的任意值
WHERE SALARY GLOB '*2' 查找以 2 结尾的任意值
WHERE SALARY GLOB '?2*3' 查找第二位为 2,且以 3 结尾的任意值
WHERE SALARY GLOB '2???3' 查找长度为 5 位数,且以 2 开头以 3 结尾的任意值

LIMIT

子句用于限制由 SELECT 语句返回的数据数量

ORDER BY

子句是用来基于一个或多个列按升序或降序顺序排列数据。

ORDER BY 子句的基本语法如下:

SELECT column-list 
FROM table_name 
[WHERE condition] 
[ORDER BY column1, column2, .. columnN] [ASC | DESC];//ASC升序排序,DESC降序排序

GROUP BY

子句用于与 SELECT 语句一起使用,来对相同的数据进行分组。 在 SELECT 语句中,GROUP BY 子句放在 WHERE 子句之后,放在 ORDER BY 子句之前

HAVING

子句允许指定条件来过滤将出现在最终结果中的分组结果。 WHERE 子句在所选列上设置条件,而 HAVING 子句则在由 GROUP BY 子句创建的分组上设置条件。

DISTINCT

关键字与 SELECT 语句一起使用,来消除所有重复的记录,并只获取唯一一次记录。 有可能出现一种情况,在一个表中有多个重复的记录。当提取这样的记录时,DISTINCT 关键字就显得特别有意义,它只获取唯一一次记录,而不是获取重复记录。

select distinct name from company;

创建数据库

操作数据库,要使用SQLiteOpenHelper,由于SQLiteOpenHelper是抽象类,使用要实现它,并重写它的 onCreate(), onUpgrade()方法

public class MyDatabase extends SQLiteOpenHelper {
    //创建表
    public static final String CreateTable_my="create Table user(" +
            "id primary key, name text, sex text , age integer, password text)";

    Context myContext;
    /** * * @param context * @param name 创建数据库的名字 * @param factory 用于返回自定义的Cursor,一般填null * @param version 表示当前数据库的版本号,可用于对数据库进行升级 */
    public Mydatabase(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        myContext=context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
          sqLiteDatabase.execSQL(CreateTable_my);//创建表
          Toast.makeText(myContext, "数据表创建成功", Toast.LENGTH_SHORT).show();
    }
  
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

创建MyDatabase的对象

//first.db是数据库名
private Mydatabase base=new Mydatabase(DatabaseActivity.this,"first.db",null,1);

生成数据库(会在/data/data/<package name>/databases/目录下建立数据库)

base.getWritableDatabase();
//或者
base.getReadableDatabase()

两个方法的不同处:
getWritableDatabase()返回一个可对数据库进行读写操作的对象,会抛出异常
getReadableDatabase()返回一个以只读方法打开的数据库,不会抛出异常

添加表

public class Mydatabase extends SQLiteOpenHelper {
//用户表
public static final String CreateTable_user="create Table user(" +
            "id primary key, name text, sex text , age integer, password text)";

//创建另一个表,班级表
public static final String CreateTable_me="create Table clazz(" +
            "id primary key, className text, teacher text)";

    Context myContext;

    /** * * @param context * @param name 创建数据库的名字 * @param factory 用于返回自定义的Cursor,一般填null * @param version 表示当前数据库的版本号,可用于对数据库进行升级 */
    public Mydatabase(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        myContext=context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
          sqLiteDatabase.execSQL(CreateTable_user);
          sqLiteDatabase.execSQL(CreateTable_me);
          Toast.makeText(myContext, "数据库创建成功", Toast.LENGTH_SHORT).show();
    }
    //当 version 中的值改变时,会调用这个方法,通过这个方法,删除原来的表,再调用onCreate()方法生成两个表
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
           sqLiteDatabase.execSQL("drop table if exists user");
           sqLiteDatabase.execSQL("drop table if exists clazz");
           onCreate(sqLiteDatabase);
           Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show();
    }
}

操作表

  • 添加数据
//通过getWritableDatabase()获取SQLiteOpenHelper来操作数据库
SQLiteDatabase database= base.getWritableDatabase();
                ContentValues values=new ContentValues();
                values.put("name","小明");
                values.put("sex","男");
                values.put("password","12hjfgikldgislk");
                values.put("age",18);
                //参数 1.表的名字 2.用于未指定添加数据的情况下给某些可为空的列自动赋值NULL 
                //3. ContentValues 对象
                database.insert("user",null,values);
  • 更新数据
SQLiteDatabase database= base.getWritableDatabase();
                ContentValues values=new ContentValues();
                values.put("name","小军");  
                //后面的两个参数是操作的限制条件
                database.update("user",values,"age=?",new String[]{"18"});
  • 删除数据
SQLiteDatabase database= base.getWritableDatabase();
//后面的两个参数是操作的限制条件,用来约束删除哪几行,如果不指定就删除所有行
database.delete("user",null,null);
  • 查询数据
                SQLiteDatabase database=base.getWritableDatabase();
                Cursor cursor= database.query("user",null,null,null,null,null,null);
                if (cursor.moveToFirst()){
                    do{
                        Log.d("name:",cursor.getString(cursor.getColumnIndex("name")));
                        Log.d("age:",cursor.getString(cursor.getColumnIndex("age")));
                        Log.d("sex:",cursor.getString(cursor.getColumnIndex("sex")));
                        Log.d("password:",cursor.getString(cursor.getColumnIndex("password")));
                    }while (cursor.moveToNext());
                }
                cursor.close();

query的参数如下:

  • 使用sql直接对数据库进行操作
SQLiteDatabase database=base.getWritableDatabase();
database.execSQL();
database.rawQuery();//只有查询数据的时候才调用这个方法

仿照LitePal实现一个简易的数据库框架SimpleDatabase

SimpleDatabase的使用

  1. 先在asset文件中创建my_database.xml

my_database.xml如下:

<?xml version="1.0" encoding="UTF-8" ?>
<database name="test.db" version="1">
    <!--class属性是数据表Bean的全路径 -->
    <table class="com.example.mylibrary.Employee"/>
</database>

Employee的源码如下

public class Employee {
   private int id;

   private String name;

   private char sex;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        //使用id作为员工的唯一标识
        return Integer.toString(id);
    }
}

注意:SimpleDatabase通过toString来区别两个对象是否为同一对象,如Employee就使用id作为标识符。

  1. AndroidManifest.xml中加入android:name="com.example.databaselibrary.MyApplication"
<application ... android:name="com.example.databaselibrary.MyApplication" >
  1. 使用SimpleDatabase
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        SimpleDatabase.newInstance().create();//初始化
        
         Employee employee =new Employee();
                employee.setId(1);
                employee.setName("a");
                employee.setSex('男');
                SimpleDatabase.saveAndUpdate(employee);

                Employee employee1 =new Employee();
                employee1.setId(2);
                employee1.setName("b");
                employee1.setSex('男');
                SimpleDatabase.saveAndUpdate(employee1);

                Employee employee2 =new Employee();
                employee2.setId(3);
                employee2.setName("c");
                employee2.setSex('女');
                SimpleDatabase.saveAndUpdate(employee2);

                List<Employee> l=SimpleDatabase.select(Employee.class,null,null,null,null,null,null);
                for (int i = 0; i <l.size() ; i++) {
                    Employee e=l.get(i);
                    Log.d("===============",e.getName());
                    Log.d("===============",e.getSex()+"");
                    Log.d("===============",e.getId()+"");
                }
    }
    }

实现原理

首先读取配置信息,获取数据库和表的信息

/** * 解析xml文件 */
public class XMLParser {

   private final static String RESOURCES="my_database.xml";//配置数据库信息的xml名字

   private final static String TABLE="table";//xml属性常量

    final static String VERSION="version";//xml属性常量

    final static String DATABASE="database";//xml属性常量

    private final static String NAME="name";//xml属性常量

    private Context context;

    private Map<String,String> map=null;//用来存储数据库信息

    private List<String> tables=null;//用来存储表信息

   public XMLParser(){
        init();
    }

   private void init(){
        context=MyApplication.getContext();
        map=new HashMap<>(2);
        tables=new ArrayList<>();

   }

  //解析数据
  public void parse() throws IOException, XmlPullParserException {

        XmlPullParserFactory factory=XmlPullParserFactory.newInstance();

        XmlPullParser xmlPullParser=factory.newPullParser();
       //从asset文件下读取my_database.xml的信息
        xmlPullParser.setInput(new InputStreamReader(context.getAssets().open(RESOURCES)));
        int type=xmlPullParser.getEventType();
        while(type!=XmlPullParser.END_DOCUMENT){
                if (xmlPullParser.getEventType()==XmlResourceParser.START_TAG){//如果为开始标签
                    String name=xmlPullParser.getName();
                    switch (name){
                        case DATABASE://标签为<database>
                            parseDatabase(xmlPullParser);
                            break;
                        case TABLE://标签为<table>
                            parseTable(xmlPullParser);
                            break;
                    }
                }
                xmlPullParser.next();//下一个标签
                type=xmlPullParser.getEventType();
        }

    }

    //解析数据库信息
    private void parseDatabase(XmlPullParser xmlPullParser) {
        String databaseName=null;
        String version=null;
        if (xmlPullParser.getAttributeCount()==2){
            String value_1=xmlPullParser.getAttributeName(0);
            if (NAME.equals(value_1)){
                databaseName=xmlPullParser.getAttributeValue(0);
                version=xmlPullParser.getAttributeValue(1);
            }else {
                databaseName=xmlPullParser.getAttributeValue(1);
                version=xmlPullParser.getAttributeValue(0);
        }
        }else{
            throw new MyException("database标签的参数错误");
        }
        map.put(DATABASE,databaseName);
        map.put(VERSION,version);
    }

    //解析表格信息
    private void parseTable(XmlPullParser xmlPullParser) {
        String className=null;
        if (xmlPullParser.getAttributeCount()==1){
            className=xmlPullParser.getAttributeValue(0);
        }else
            throw new MyException("table参数错误");
        tables.add(className);
    }

    public Map<String, String> getMap() {
        return map;
    }
    public List<String> getTables() {
        return tables;
    }
}

创建数据库的类

public class MyDatabase extends SQLiteOpenHelper {

    private onDatabaseUpdateListener listener=null;

    private static final String TAG = "MyDatabase";

    public MyDatabase(Context context, String name, SQLiteDatabase.CursorFactory factory, int version,onDatabaseUpdateListener listener) {
        super(context, name, factory, version);
        this.listener=listener;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String[] createTables = listener.onCreate();
            for (String s: createTables){
                db.execSQL(s);
                Log.d("======建表语句",s);
            }
        Log.d("======","onCreate执行");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        String[] deleteTable = listener.update(db);
        Log.d("======","onUpgrade执行");
           if (deleteTable !=null){
               for (String s: deleteTable){
                   db.execSQL(s);
                   Log.d("=====删表语句",s);
               }
           }
           onCreate(db);
           listener.onCreateLater(db);
    }
    
    interface onDatabaseUpdateListener{
        String[] update(SQLiteDatabase db);//数据库版本更新时调用
        String[] onCreate();//创建新的表时调用
        void onCreateLater(SQLiteDatabase db);//创建完表时调用
    }
}

完成数据库操作的实现类

/** * 实现数据的操作和数据库的创建 */
public class SimpleDatabase implements MyDatabase.onDatabaseUpdateListener{

    private final static String NAME="SimpleDatabase.xml";

    private final static String OLD="old";

    private final static String TABLE="table_";

    private final static String NUMBER="number";

    //MyDatabaseHelper是一个辅助类,用来生成创建数据库和表所需要的数据
    private static MyDatabaseHelper databaseHelper=null;

   private static SQLiteDatabase db=null;

   private Map<String,Cursor> savedData=null;

    String simpleNames[]=null;

   private static final String TAG = "SimpleDatabase";

   private static SimpleDatabase simpleDatabase=new SimpleDatabase();

   public SimpleDatabase(){
       init();
   }

   private void init(){
       databaseHelper=new MyDatabaseHelper();
   }

    /** * 查询指定的数据 */
    public static<T> List<T> select(Class<T> clazz,String columnNames[],String where, String args[],String groupBy, String having, String orderBy){
        List<T> list = new ArrayList<>();
        Cursor cursor= db.query(clazz.getSimpleName(),columnNames,where,args,groupBy,having,orderBy);
        while(cursor.moveToNext()){
            try {
                T t = clazz.newInstance();
                Field fields[]=clazz.getDeclaredFields();
                for (Field f:fields) {
                        f.setAccessible(true);
                        String fieldName = f.getName();
                        String fieldValue = cursor.getColumnName(cursor.getColumnIndex(fieldName));
                        //由于getColumnName()只会返回String类型,所以这里需要getInitialTypeValue()
                        //获取初始类型的值
                        f.set(t,getInitialTypeValue(f.getType().getSimpleName(),fieldValue));
                }
                list.add(t);
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        cursor.close();
        return list;
    }

    private static Object getInitialTypeValue(String type,String value){
        switch (type){
            case "int":
            case "integer":
                return Integer.valueOf(value);
            case "boolean":
                return Boolean.valueOf(value);
            case "float":
                return Float.valueOf(value);
            case "double":
                return Double.valueOf(value);
            case "String":
            case "Character":
            case "char":
               return value;
        }
        return null;
    }

    /** * 查询指定的数据 */
    private static Cursor select(Object obj,String columnNames[],String where,String args[]){
       String tableName=obj.getClass().getSimpleName();
       return db.query(tableName,columnNames,where,args,null,null,null);
    }

    /** * 如果不存在数据库就创建,如果已经存在,则直接结束 */
   public void create(){
       String name=databaseHelper.getName();
       String version=databaseHelper.getVersion();
       if (databaseHelper.check(getOldVersion(),Integer.valueOf(version)))//如果需要更新
           saveDataInSharedPreferences(Integer.valueOf(version));
       Log.d("=========","name"+name);
       MyDatabase database = new MyDatabase(MyApplication.getContext(), name, null, Integer.valueOf(version), SimpleDatabase.this);
       db= database.getWritableDatabase();
   }

    public static SimpleDatabase newInstance() {
        return simpleDatabase;
    }

    /** * 存储批量数据 * @param list * @throws IllegalAccessException */
   public static void save(List<Object> list) {
       for (Object o:list) {
           save(o);
       }
   }

    /** * 存储单个数据到表中 * @param o * @throws IllegalAccessException */
   public static void save(Object o) {
           Class clazz=o.getClass();
           Field fields[]=clazz.getDeclaredFields();
           ContentValues values=new ContentValues();
           values.put("simple_database_id",o.toString());
           for (Field f:fields) {
               try {
                      f.setAccessible(true);
                      if (f.get(o)!=null&&!"serialVersionUID".equals(f.getName())) {
                          values.put(f.getName(), f.get(o).toString());
                          Log.d("========value", f.get(o).toString());
                      }
               } catch (IllegalAccessException e) {
                   e.printStackTrace();
                   Log.wtf(TAG,"类中所以的数据应该设置值");
               }
           }
           db.insert(clazz.getSimpleName(),null,values);
   }

   public static void saveAndUpdate(Object o){
       Class clazz=o.getClass();
       String id=o.toString();
       Field fields[]=clazz.getDeclaredFields();
       ContentValues values=new ContentValues();
       values.put("simple_database_id",o.toString());
       for (Field f:fields) {
           try {
               f.setAccessible(true);
               if (f.get(o)!=null&&!"serialVersionUID".equals(f.getName())) {
                   values.put(f.getName(), f.get(o).toString());
                   Log.d("========value", f.get(o).toString());
               }
           } catch (IllegalAccessException e) {
               e.printStackTrace();
               Log.wtf(TAG,"类中所以的数据应该设置值");
           }
       }
       Cursor cursor=select(o,null,"simple_database_id=?",new String[]{id});
       if (cursor.getCount()==0){//插入
           db.insert(clazz.getSimpleName(),null,values);
       }else {//更新
           db.update(clazz.getSimpleName(),values,"simple_database_id=?",new String[]{id});
       }
   }


    /** * 删除表中所有的数据 * @param o */
   public static void delete(Object o){
       Class clazz=o.getClass();
       delete(clazz.getSimpleName(),"simple_database_id=?",o.toString());
   }


    /** * 删除表中指定的数据 * @param name * @param where * @param arg */
   private static void delete(String name,String where,String... arg){
       db.delete(name,where,arg);
   }

    /** * 如果版本更新,则存储最新的版本 * @param version 版本号 */
   private static void saveDataInSharedPreferences(int version){
       //获取SharedPreferences的Editor对象来执行储存操作
       SharedPreferences.Editor editor=MyApplication.getContext().getSharedPreferences(NAME,0).edit();
       editor.putInt(OLD,version);
       editor.apply();//最后一定要调用这个方法,完成数据的储存
   }

    /** *存储过去的表名 * @param names */
    private void saveDataInSharedPreferences(String[] names){
        //获取SharedPreferences的Editor对象来执行储存操作
        SharedPreferences.Editor editor=MyApplication.getContext().getSharedPreferences(NAME,0).edit();
        for (int i=0;i<names.length;i++){
            editor.putString(TABLE+i,names[i]);
        }
        editor.putInt(NUMBER,names.length);
        editor.apply();//最后一定要调用这个方法,完成数据的储存
    }


    /** * 获取上一次的数据库的版本 * @return */
   private static int getOldVersion(){
       SharedPreferences get=MyApplication.getContext().getSharedPreferences(NAME,0);
       return get.getInt(OLD,0);
   }


    private String[] getOldTableName(){
        SharedPreferences get=MyApplication.getContext().getSharedPreferences(NAME,0);
        int length=get.getInt(NUMBER,-1);
        if (length==-1)
            Log.wtf(TAG,"原有表格不存在");
        String names[]=new String[length];
        for (int i=0;i<length;i++){
            names[i]=get.getString(TABLE+i,"");
        }
        return names;
    }

    @Override
    public String[] update(SQLiteDatabase db) {//在删除表之前把表的数据保存起来
        simpleNames=getOldTableName();
        savedData=new HashMap<>(simpleNames.length);
        for (String name:simpleNames) {
            Cursor cursor=db.query(name,null,null,null,null,null,null);
            savedData.put(name,cursor);
        }
        Cursor cursor=savedData.get(simpleNames[0]);
        if (cursor.moveToFirst()){
            String sex=cursor.getString(cursor.getColumnIndex("sex"));
            Log.d("===============update","sex="+sex);
        }
        return databaseHelper.getDeleteTable();
    }

    @Override
    public String[] onCreate() {
        saveDataInSharedPreferences(databaseHelper.getSimpleTableName());
        return databaseHelper.getCreateTable();
    }

    @Override
    public void onCreateLater(SQLiteDatabase db) {
        recoverAllData(db);
    }

    /** * 恢复所有的数据 */
    private void recoverAllData(SQLiteDatabase db){
       List<String> deleteTable=checkWhichTableDisappear(databaseHelper.getTables());
       List<String> nowTable=Arrays.asList(simpleNames);
       nowTable.remove(deleteTable);
       for (int i=0;i<nowTable.size();i++){
          Cursor cursor=savedData.get(nowTable.get(i));
          ContentValues values=new ContentValues();
           if (cursor.moveToFirst()){
               do{
                   String columnNames[]=cursor.getColumnNames();
                   for (int j=0;j<columnNames.length;j++)
                         values.put(columnNames[j],cursor.getString(cursor.getColumnIndex(columnNames[j])));
               }while (cursor.moveToNext());
               db.insert(nowTable.get(i),null,values);
           }
       }
        for (String n:simpleNames) {//释放所有的资源
            savedData.get(n).close();
        }
    }

    /** * 检查有哪些表被删除 * @param newTable * @return */
    private List<String> checkWhichTableDisappear(List<String> newTable){
            String deleteTable[]=new String[simpleNames.length];
            for (int i=0,j=0;i<simpleNames.length;i++){
                if (!newTable.contains(simpleNames[i])){
                    deleteTable[j]=simpleNames[i];
                    j++;
                }
            }
          return Arrays.asList(deleteTable);
    }
}

SimpleDatabase的主要作用是在my_database.xml中的配置更改时,能自动更新数据库;插入和更新时,通过saveAndUpdate(Object o)使用对象来实现插入和更新操作(当数据库中不存在同一条数据时,就插入;当数据库中存在同一条数据时,就更新);查询时,通过

List<T> select(Class<T> clazz,String columnNames[],String where,String args[],String groupBy, String having, String orderBy)获取包含查询结果对象的集合;删除时,通过delete(Object o)使用对象来实现删除操作。

实现原理:

SimpleDatabase通过实现MyDatabaseonDatabaseUpdateListener接口,监听MyDatabaseonCreateonUpgrade方法。在onCreate被调用时,调用onDatabaseUpdateListener.onCreate来存储之前的表名(如果修改了配置文件的话),并返回创建表的sql语句集合(可能创建多个表),之后在MyDatabase.onCreate中创建表。当onUpgrade被调用时,调用onDatabaseUpdateListener.update来存储当前数据库中的数据,并返回删除表的sql语句集合,删除成功后创建新的表,之后调用onDatabaseUpdateListener.onCreateLater方法将之前存储的数据重新存储到数据库中。

SimpleDatabase中的selectdeletesaveAndUpdate方法是通过反射实现的,具体可以看注释。

其他类的实现很简单,具体可以看源码:

  • MyApplication类
/** * 获取系统的context */
public class MyApplication extends Application {
    private static Context context;
    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }
    public static Context getContext(){
        return context;
    }
}
  • MyDatabaseHelper类
/** * 生成创建数据库和表所需要的数据 */
public class MyDatabaseHelper {

    private String name=null;

    private String version=null;

    private List<String> tables=null;//存储完整类名

    private Map<String,Table[]> maps=null;

    private String createTable[]=null;//存储建表语句

    private String deleteTable[]=null;//存储删除表的语句

    private boolean ok=false;

    private static final String TAG = "MyDatabaseHelper";

    public MyDatabaseHelper(){
       init();
    }

    /** * 初始化数据 */
    private void init(){
        XMLParser xmlParser=null;
        xmlParser=new XMLParser();
        try {
            xmlParser.parse();
        } catch (IOException | XmlPullParserException  e) {
            e.printStackTrace();
        }
        name=xmlParser.getMap().get(XMLParser.DATABASE);
        version=xmlParser.getMap().get(XMLParser.VERSION);
        tables=xmlParser.getTables();
        maps=new HashMap<>(tables.size());
    }

    /** * 检查是否需要更新 * @param old 之前的版本 * @param now 现在的版本 */
    public boolean check(int old,int now){
        if (now>old) {
            try {
                parseTable();
                ok=true;
                return true;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /** * 解析类的数据,在version改变时调用 * @throws ClassNotFoundException */
    private void parseTable() throws ClassNotFoundException {
        for (String name:tables){
            Class table=Class.forName(name);
            Field[] field=table.getDeclaredFields();
            Table info[]=new Table[field.length];
            for (int i=0;i<field.length;i++){
                Table t=new Table();
                t.setProperty(field[i].getName());
                t.setType(field[i].getType().getSimpleName());
                info[i]=t;
            }
            maps.put(name,info);
        }
    }
    /** * 生成建表语句 */
    private void generateTable(){
        for (int i=0;i<tables.size();i++){
            Table table[]=maps.get(tables.get(i));
            StringBuilder stringBuilder=new StringBuilder();
            String simpleName=getSimpleName(tables.get(i));
            stringBuilder.append("create table "+simpleName+"( ");
            for (int j=0;j<table.length;j++){
                Table t=table[j];
                if (t!=null)
                if (!Table.OTHER.equals(t.getType()))
                    stringBuilder.append(" , "+t.getProperty()+" "+t.getType());
            }
            String string=stringBuilder.append(")").toString();
            string=string.replaceFirst(",","");
            createTable[i]=string;
        }
    }

    /** * 生成删除表的语句 */
    private void deleteTable() {
        for (int i = 0; i < tables.size(); i++) {
            deleteTable[i]="drop table if exists "+getSimpleName(tables.get(i));
        }
    }

    /** * 获取简单类名,不包括包 * @param name 带有包名的类名 * @return 不包含包名的类名 */
    private String getSimpleName(String name){
       int position= name.lastIndexOf('.');
       return name.substring(position+1);
    }



    public String getName() {
        return name;
    }

    public String getVersion() {
        return version;
    }

    public String[] getCreateTable() {
        if (!ok)
            Log.e(TAG,"必须先调用check()");
        createTable=new String[tables.size()];
        generateTable();
        return createTable;
    }

    public String[] getDeleteTable() {
        if (!ok)
            Log.e(TAG,"必须先调用check()");
        deleteTable=new String[tables.size()];
        deleteTable();
        return deleteTable;
    }

    public List<String> getTables() {
        return tables;
    }

    public String[] getSimpleTableName() {

        String simpleTableName[]=new String[tables.size()];

        for (int i=0;i<tables.size();i++) {

            String simpleName = getSimpleName(tables.get(i));

            simpleTableName[i] = simpleName;

        }

        return simpleTableName;

    }
}
  • MyException
public class MyException extends RuntimeException {
    public MyException(String message) {
        super(message);
    }
}
  • Table类
/** * 存储每个字段对应的属性和名字 */
public class Table {
    final static String INTEGER="integer";

    final static String TEXT="text";

    final static String REAL="real";

    final static String BLOB="blob";

    final static String INT="int";

    final static String CHAR="char";

    final static String FLOAT="float";

    final static String DOUBLE="double";

    final static String STRING="String";

    final static String BOOLEAN="boolean";

    final static String OTHER="other";

    private String property;//对应的属性

    private String type;//对应的属性的类型

    public String getProperty() {
        return property;
    }

    public void setProperty(String property) {
        this.property = property;
    }

    public String getType() {
        return type;
    }
    
    public void setType(String type) {
        checkProperty(type);
    }

    private void checkProperty(String property){
        switch (property){
            case INT:
            case BOOLEAN:
                type=INTEGER;
                break;
            case FLOAT:
            case DOUBLE:
                type=REAL;
                break;
            case STRING:
            case CHAR:
                type=TEXT;
                break;
            default:
                 type=OTHER;
                 break;
        }
    }
}

参考菜鸟教程

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们