SQLite的基本知识
SQLite常用的数据类型
字段 | 作用 |
---|---|
char(n) | 固定n 长度的字串 |
varchar(n) | 长度不固定的字符串,n 表示最大的长度 |
nchar(n) | 同char,不同的是可以用来存储中文 |
nvarchar(n) | 同varchar,不同的是可以用来存储中文 |
text | 存储文本 |
blob | 存储二进制文件 |
int | 整形 |
integer | 整形 |
bigint | 整形 |
float | 单精度类型 |
double | 双精度浮点 |
这里int
、integer
、bigint
的具体区别,还没弄明白。如果有哪个大佬了解,请在评论区指导一下??
创建和删除数据表
创建表的为语法:
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/
目录下建立数据库)
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
的使用
- 先在
asset
文件中创建my_database.xml
my_database.xml
如下:
xml version="1.0" encoding="UTF-8" ?>
<database name="test.db" version="1">
<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
作为标识符。
- 在
AndroidManifest.xml
中加入android:name="com.example.databaselibrary.MyApplication"
<application
...
android:name="com.example.databaselibrary.MyApplication"
>
复制代码
- 使用
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 l=SimpleDatabase.select(Employee.class,null,null,null,null,null,null);
for (int i = 0; i "===============",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 map=null;//用来存储数据库信息
private List 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://标签为
parseDatabase(xmlPullParser);
break;
case 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 getMap() {
return map;
}
public List 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 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 List select(Class clazz,String columnNames[],String where,
String args[],String groupBy, String having, String orderBy) {
List 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 {
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//最后一定要调用这个方法,完成数据的储存
}
/**
* 获取上一次的数据库的版本
* @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"");
}
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 deleteTable=checkWhichTableDisappear(databaseHelper.getTables());
List nowTable=Arrays.asList(simpleNames);
nowTable.remove(deleteTable);
for (int i=0;inew ContentValues();
if (cursor.moveToFirst()){
do{
String columnNames[]=cursor.getColumnNames();
for (int j=0;jwhile (cursor.moveToNext());
db.insert(nowTable.get(i),null,values);
}
}
for (String n:simpleNames) {//释放所有的资源
savedData.get(n).close();
}
}
/**
* 检查有哪些表被删除
* @param newTable
* @return
*/
private List checkWhichTableDisappear(List newTable) {
String deleteTable[]=new String[simpleNames.length];
for (int i=0,j=0;iif (!newTable.contains(simpleNames[i])){
deleteTable[j]=simpleNames[i];
j++;
}
}
return Arrays.asList(deleteTable);
}
}
复制代码
SimpleDatabase
的主要作用是在my_database.xml
中的配置更改时,能自动更新数据库;插入和更新时,通过saveAndUpdate(Object o)
使用对象来实现插入和更新操作(当数据库中不存在同一条数据时,就插入;当数据库中存在同一条数据时,就更新);查询时,通过
List select(Class clazz,String columnNames[],String where,String args[],String groupBy, String having, String orderBy)
获取包含查询结果对象的集合;删除时,通过delete(Object o)
使用对象来实现删除操作。
实现原理:
SimpleDatabase
通过实现MyDatabase
的onDatabaseUpdateListener
接口,监听MyDatabase
的onCreate
和onUpgrade
方法。在onCreate
被调用时,调用onDatabaseUpdateListener.onCreate
来存储之前的表名(如果修改了配置文件的话),并返回创建表的sql语句集合(可能创建多个表),之后在MyDatabase.onCreate
中创建表。当onUpgrade
被调用时,调用onDatabaseUpdateListener.update
来存储当前数据库中的数据,并返回删除表的sql语句集合,删除成功后创建新的表,之后调用onDatabaseUpdateListener.onCreateLater
方法将之前存储的数据重新存储到数据库中。
SimpleDatabase
中的select
、delete
、saveAndUpdate
方法是通过反射实现的,具体可以看注释。
其他类的实现很简单,具体可以看源码:
- 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 tables=null;//存储完整类名
private Map 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;inew 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;inew StringBuilder();
String simpleName=getSimpleName(tables.get(i));
stringBuilder.append("create table "+simpleName+"( ");
for (int j=0;jif (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 getTables() {
return tables;
}
public String[] getSimpleTableName() {
String simpleTableName[]=new String[tables.size()];
for (int i=0;ireturn 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://juejin.im/post/5cf152b2f265da1bd522b634