SQLite的基本知识
SQLite常用的数据类型
| 字段 | 作用 |
|---|---|
| char(n) | 固定n长度的字串 |
| varchar(n) | 长度不固定的字符串,n表示最大的长度 |
| nchar(n) | 同char,不同的是可以用来存储中文 |
| nvarchar(n) | 同varchar,不同的是可以用来存储中文 |
| text | 存储文本 |
| blob | 存储二进制文件 |
| int | 整形 |
| integer | 整形 |
| bigint | 整形 |
| float | 单精度类型 |
| double | 双精度浮点 |
这里int、integer、bigint的具体区别,还没弄明白。如果有哪个大佬了解,请在评论区指导一下😄😄
创建和删除数据表
创建表的为语法:1
2
3
4
5
6
7create table database_name.table_name(
column1 datatype primary key(one or more columns),
column2 datatype,
column3 datatype,
.....
columnN datatype,
);
删除数据表的语法为1
drop table database_name.table_name;
插入数据
插入数据表的语法为:1
2
3
4
5insert into table_name [(column1, column2, column3,...columnN)]
values (value1, value2, value3,...valueN);
或
//注意:这种方式要确保值的顺序与列在表中的顺序一致
insert into table_name values (value1,value2,value3,...valueN);
删除数据
删除数据的语法为:1
delete from table_name [条件];
如果没有删除数据的条件,默认删除所有数据;如果指定了条件,则删除符合条件的
数据
更新数据
语法为:1
2update table_name
set column1 = value1, column2 = value2...., columnN = valueN [条件];
查询数据
语法为:1
2
3
4
5//查询指定字段(列)的值
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 子句的基本语法如下:1
2
3
4SELECT 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 关键字就显得特别有意义,它只获取唯一一次记录,而不是获取重复记录。1
select distinct name from company;
创建数据库
操作数据库,要使用SQLiteOpenHelper,由于SQLiteOpenHelper是抽象类,使用要实现它,并重写它的 onCreate(), onUpgrade()方法
1 | public class MyDatabase extends SQLiteOpenHelper { |
创建MyDatabase的对象
1 | //first.db是数据库名 |
生成数据库(会在/data/data/<package name>/databases/目录下建立数据库)1
2
3base.getWritableDatabase();
//或者
base.getReadableDatabase()
两个方法的不同处:
getWritableDatabase()返回一个可对数据库进行读写操作的对象,会抛出异常getReadableDatabase()返回一个以只读方法打开的数据库,不会抛出异常
添加表
1 | public class Mydatabase extends SQLiteOpenHelper { |
操作表
- 添加数据
1 | //通过getWritableDatabase()获取SQLiteOpenHelper来操作数据库 |
- 更新数据
1 | SQLiteDatabase database= base.getWritableDatabase(); |
- 删除数据
1 | SQLiteDatabase database= base.getWritableDatabase(); |
- 查询数据
1 | SQLiteDatabase database=base.getWritableDatabase(); |
query的参数如下:
- 使用sql直接对数据库进行操作
1 | SQLiteDatabase database=base.getWritableDatabase(); |
仿照LitePal实现一个简易的数据库框架SimpleDatabase
SimpleDatabase的使用
- 先在
asset文件中创建my_database.xml
my_database.xml如下:1
2
3
4
5
<database name="test.db" version="1">
<!--class属性是数据表Bean的全路径 -->
<table class="com.example.mylibrary.Employee"/>
</database>
Employee的源码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37public 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;
}
public String toString() {
//使用id作为员工的唯一标识
return Integer.toString(id);
}
}
注意:SimpleDatabase通过toString来区别两个对象是否为同一对象,如Employee就使用id作为标识符。
在
AndroidManifest.xml中加入android:name="com.example.databaselibrary.MyApplication"1
2
3
4<application
...
android:name="com.example.databaselibrary.MyApplication"
>使用
SimpleDatabase
1 | public class MainActivity extends AppCompatActivity { |
实现原理
首先读取配置信息,获取数据库和表的信息1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96/**
* 解析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;
}
}
创建数据库的类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41public 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;
}
public void onCreate(SQLiteDatabase db) {
String[] createTables = listener.onCreate();
for (String s: createTables){
db.execSQL(s);
Log.d("======建表语句",s);
}
Log.d("======","onCreate执行");
}
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);//创建完表时调用
}
}
完成数据库操作的实现类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304/**
* 实现数据的操作和数据库的创建
*/
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;
}
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();
}
public String[] onCreate() {
saveDataInSharedPreferences(databaseHelper.getSimpleTableName());
return databaseHelper.getCreateTable();
}
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通过实现MyDatabase的onDatabaseUpdateListener接口,监听MyDatabase的onCreate和onUpgrade方法。在onCreate被调用时,调用onDatabaseUpdateListener.onCreate来存储之前的表名(如果修改了配置文件的话),并返回创建表的sql语句集合(可能创建多个表),之后在MyDatabase.onCreate中创建表。当onUpgrade被调用时,调用onDatabaseUpdateListener.update来存储当前数据库中的数据,并返回删除表的sql语句集合,删除成功后创建新的表,之后调用onDatabaseUpdateListener.onCreateLater方法将之前存储的数据重新存储到数据库中。
SimpleDatabase中的select、delete、saveAndUpdate方法是通过反射实现的,具体可以看注释。
其他类的实现很简单,具体可以看源码:
MyApplication类
1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* 获取系统的context
*/
public class MyApplication extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext(){
return context;
}
}MyDatabaseHelper类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164/**
* 生成创建数据库和表所需要的数据
*/
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
1
2
3
4
5public class MyException extends RuntimeException {
public MyException(String message) {
super(message);
}
}Table类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66/**
* 存储每个字段对应的属性和名字
*/
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;
}
}
}
参考菜鸟教程