字段 | 做用 |
---|---|
char(n) | 固定n 長度的字串 |
varchar(n) | 長度不固定的字符串,n 表示最大的長度 |
nchar(n) | 同char,不一樣的是能夠用來存儲中文 |
nvarchar(n) | 同varchar,不一樣的是能夠用來存儲中文 |
text | 存儲文本 |
blob | 存儲二進制文件 |
int | 整形 |
integer | 整形 |
bigint | 整形 |
float | 單精度類型 |
double | 雙精度浮點 |
這裏int
、integer
、bigint
的具體區別,還沒弄明白。若是有哪一個大佬瞭解,請在評論區指導一下😄😄php
建立表的爲語法:html
create table database_name.table_name(
column1 datatype primary key(one or more columns),
column2 datatype,
column3 datatype,
.....
columnN datatype,
);
複製代碼
刪除數據表的語法爲java
drop table database_name.table_name;
複製代碼
插入數據表的語法爲:android
insert into table_name [(column1, column2, column3,...columnN)]
values (value1, value2, value3,...valueN);
或
//注意:這種方式要確保值的順序與列在表中的順序一致
insert into table_name values (value1,value2,value3,...valueN);
複製代碼
刪除數據的語法爲:sql
delete from table_name [條件];
複製代碼
若是沒有刪除數據的條件,默認刪除全部數據;若是指定了條件,則刪除符合條件的 數據數據庫
語法爲:bash
update table_name
set column1 = value1, column2 = value2...., columnN = valueN [條件];
複製代碼
語法爲:app
//查詢指定字段(列)的值
SELECT column1, column2, columnN FROM table_name;
或
//查詢全部字段的值
SELECT * FROM table_name;
複製代碼
運算符 | 描述 |
---|---|
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
用來過濾數據的,例如select * from employee where salary >= 65000;
是指查詢工資高於65000的員工的數據,使用where salary >= 65000;
來過濾數據框架
and
至關於邏輯與運算,只有條件全爲真時,結果才爲真;or
至關於邏輯或運算,只要其中一個條件爲真,結果就爲真。ide
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
運算符將返回真(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 結尾的任意值 |
子句用於限制由 SELECT 語句返回的數據數量
子句是用來基於一個或多個列按升序或降序順序排列數據。
ORDER BY 子句的基本語法以下:
SELECT column-list
FROM table_name
[WHERE condition]
[ORDER BY column1, column2, .. columnN] [ASC | DESC];//ASC升序排序,DESC降序排序
複製代碼
子句用於與 SELECT 語句一塊兒使用,來對相同的數據進行分組。 在 SELECT 語句中,GROUP BY 子句放在 WHERE 子句以後,放在 ORDER BY 子句以前
子句容許指定條件來過濾將出如今最終結果中的分組結果。 WHERE 子句在所選列上設置條件,而 HAVING 子句則在由 GROUP BY 子句建立的分組上設置條件。
關鍵字與 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的參數以下:
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">
<!--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
做爲標識符。
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<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
經過實現MyDatabase
的onDatabaseUpdateListener
接口,監聽MyDatabase
的onCreate
和onUpgrade
方法。在onCreate
被調用時,調用onDatabaseUpdateListener.onCreate
來存儲以前的表名(若是修改了配置文件的話),並返回建立表的sql語句集合(可能建立多個表),以後在MyDatabase.onCreate
中建立表。當onUpgrade
被調用時,調用onDatabaseUpdateListener.update
來存儲當前數據庫中的數據,並返回刪除表的sql語句集合,刪除成功後建立新的表,以後調用onDatabaseUpdateListener.onCreateLater
方法將以前存儲的數據從新存儲到數據庫中。
SimpleDatabase
中的select
、delete
、saveAndUpdate
方法是經過反射實現的,具體能夠看註釋。
其餘類的實現很簡單,具體能夠看源碼:
/** * 獲取系統的context */
public class MyApplication extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext(){
return context;
}
}
複製代碼
/** * 生成建立數據庫和表所須要的數據 */
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;
}
}
複製代碼
public class MyException extends RuntimeException {
public MyException(String message) {
super(message);
}
}
複製代碼
/** * 存儲每一個字段對應的屬性和名字 */
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;
}
}
}
複製代碼
參考菜鳥教程