专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

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

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的参数如下:

61_1.png

  • 使用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;
        }
    }
}

参考菜鸟教程

文章永久链接:https://tech.souyunku.com/28232

未经允许不得转载:搜云库技术团队 » SQLite的使用和实现一个简单的数据库框架

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们