1、概述
开发Android的同学都知道sdk已经为我们提供了一个SQLiteOpenHelper类来创建和管理SQLite数据库,通过写一个子类去继承它,就可以方便的创建、管理数据库。但是当我们需要去做增删改查的操作的时候,就得通过getWritableDatabase获取一个SQLiteDataBase然后老老实实去写操作值的put以及查询返回的Cursor处理,其实我们可以搞一个对象来帮我们干这些事情,打造属于你自己的数据库操作类。
2、操作类的初显形
假设现在我们什么都没有,我们要去搞一个对象来给我们干这件事情,它需要有什么才可以干呢?
先想想要做的事情:管理数据库的操作
那要做数据库的操作需要什么就很简单了吧?
1、要操作数据库,所以需要一个SQLiteDataBase对象,可以通过SQLiteOpenHelper的子类来获取。
2、此外数据库要创建,还需要数据库信息吧?那就直接变量引入。
3、有了数据库信息,创建了数据库,你要操作,怎么也得告诉我操作哪个表。所以还得包含创建表和更新表的信息,由于表一般会有多张,所以这里用一个数组变量。
有了信息还得交互,不然我怎么知道你要怎么创建表,所以我们在构造方法中直接获取这些信息。
接下看上面文字的代码表示
1public abstract class DataBaseHelper { 2 3 /** 4 * 用来创建和获取数据库的SQLiteOpenHelper 5 */ 6 protected DBHelper mDbHelper; 7 /** 8 * 数据库对象 9 */ 10 protected SQLiteDatabase mDb; 11 12 /** 13 * 数据库信息 14 */ 15 private int mDbVersion;//版本 16 private String mDbName;//数据库名 17 /** 18 * 创建表语句 19 */ 20 private String[] mDbCreateSql; 21 /** 22 * 更新表语句 23 */ 24 private String[] mDbUpdateSql; 25 26 protected abstract int getMDbVersion(Context context); 27 28 protected abstract String getDbName(Context context); 29 30 protected abstract String[] getDbCreateSql(Context context); 31 32 protected abstract String[] getDbUpdateSql(Context context); 33 34 public DataBaseHelper(Context context) { 35 this.mDbVersion = this.getMDbVersion(context); 36 this.mDbName = this.getDbName(context); 37 this.mDbCreateSql = this.getDbCreateSql(context); 38 this.mDbUpdateSql = this.getDbUpdateSql(context); 39 this.mDbHelper = new DBHelper(context,this.mDbName,null,this.mDbVersion); 40 } 41 42 protected void open(){ 43 new Thread(new Runnable() { 44 @Override 45 public void run() { 46 mDb = mDbHelper.getWritableDatabase(); 47 } 48 }).start(); 49 50 } 51 52 protected SQLiteDatabase getDB(){ 53 return this.mDb; 54 } 55 56 57 public void close(){ 58 this.mDb.close(); 59 this.mDbHelper.close(); 60 } 61 62 private class DBHelper extends SQLiteOpenHelper{ 63 64 public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { 65 super(context, name, factory, version); 66 } 67 68 @Override 69 public void onCreate(SQLiteDatabase db) { 70 String[] arr = DataBaseHelper.this.mDbCreateSql; 71 //执行创建表语句 72 for (int i=0;i<arr.length;i++){ 73 String sql = arr[i]; 74 db.execSQL(sql); 75 } 76 } 77 78 @Override 79 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 80 String[] arr = DataBaseHelper.this.mDbUpdateSql; 81 //执行更新语句 82 for (int i=0;i<arr.length;i++){ 83 String sql = arr[i]; 84 db.execSQL(sql); 85 } 86 } 87 } 88}
代码比较简单,包含了进行数据库操作要用到的各种信息,并且在初始化的进行了赋值。同时还提供了SQLiteDatabase的open、close。同时在这里用到了抽象方法是因为考虑创建多个数据库的情况,让子类来提供具体的数据库信息,我只管做创建和操作就行了。
这里我们的数据库操作类已经初显雏形了,但是现在除了创建表还没什么用。操作类不提供简便的操作还叫什么操作类,下面就来说说操作。
我们要做操作类,无非是要简化操作,就像当老板一样。我告诉你一些用到的东西,你去给我完成这个事情。哈哈。
假如我现在就是要操作数据库的老板,那我其实只想告诉你必要的事情,其它的我都不想做。
那么必要的信息只有表名,要操作的字段和值,如果是删除、更新、和查询的话多加个筛选条件。接下来看代码
1 /** 2 * 统一对ContentValues处理 3 * @param contentValues 4 * @param key 5 * @param value 6 */ 7 private void ContentValuesPut(ContentValues contentValues,String key,Object value){ 8 if (value==null){ 9 contentValues.put(key,""); 10 }else{ 11 String className = value.getClass().getName(); 12 if (className.equals("java.lang.String")){ 13 contentValues.put(key,value.toString()); 14 } else if (className.equals("java.lang.Integer")){ 15 contentValues.put(key,Integer.valueOf(value.toString())); 16 } else if (className.equals("java.lang.Float")){ 17 contentValues.put(key,Float.valueOf(value.toString())); 18 } else if (className.equals("java.lang.Double")){ 19 contentValues.put(key,Double.valueOf(value.toString())); 20 } else if (className.equals("java.lang.Boolean")){ 21 contentValues.put(key,Boolean.valueOf(value.toString())); 22 } else if (className.equals("java.lang.Long")){ 23 contentValues.put(key,Long.valueOf(value.toString())); 24 } else if (className.equals("java.lang.Short")){ 25 contentValues.put(key,Short.valueOf(value.toString())); 26 } 27 } 28 } 29 30 /** 31 * 根据数组的列和值进行insert 32 * @param tableName 33 * @param columns 34 * @param values 35 * @return 36 */ 37 public boolean insert(String tableName,String[] columns,Object[] values){ 38 ContentValues contentValues = new ContentValues(); 39 for (int rows = 0; rows < columns.length;++rows){ 40 ContentValuesPut(contentValues,columns[rows],values[rows]); 41 } 42 long rowId = this.mDb.insert(tableName,null,contentValues); 43 return rowId!=-1; 44 } 45 46 /** 47 * 根据map来进行insert 48 * @param tableName 49 * @param columnValues 50 * @return 51 */ 52 public boolean insert(String tableName,Map<String,Object> columnValues){ 53 ContentValues contentValues = new ContentValues(); 54 Iterator iterator = columnValues.keySet().iterator(); 55 while (iterator.hasNext()){ 56 String key = (String) iterator.next(); 57 this.ContentValuesPut(contentValues,key,columnValues.get(key)); 58 } 59 60 long rowId = this.mDb.insert(tableName,null,contentValues); 61 return rowId!=-1; 62 } 63 64 65 /** 66 * 统一对数组where条件进行拼接 67 * @param whereColumns 68 * @return 69 */ 70 private String initWhereSqlFromArray(String[] whereColumns){ 71 StringBuffer whereStr = new StringBuffer(); 72 for (int i=0;i<whereColumns.length;++i){ 73 whereStr.append(whereColumns[i]).append(" = ? "); 74 if (i<whereColumns.length-1){ 75 whereStr.append(" and "); 76 } 77 } 78 return whereStr.toString(); 79 } 80 81 /** 82 * 统一对map的where条件和值进行处理 83 * @param whereParams 84 * @return 85 */ 86 private Map<String,Object> initWhereSqlFromMap(Map<String,String> whereParams){ 87 Set set = whereParams.keySet(); 88 String[] temp = new String[whereParams.size()]; 89 int i = 0; 90 Iterator iterator = set.iterator(); 91 StringBuffer whereStr = new StringBuffer(); 92 while (iterator.hasNext()){ 93 String key = (String) iterator.next(); 94 whereStr.append(key).append(" = ? "); 95 temp[i] = whereParams.get(key); 96 if (i<set.size()-1){ 97 whereStr.append(" and "); 98 } 99 i++; 100 } 101 HashMap result = new HashMap(); 102 result.put("whereSql",whereStr); 103 result.put("whereSqlParam",temp); 104 return result; 105 } 106 107 108 /** 109 * 根据数组条件来update 110 * @param tableName 111 * @param columns 112 * @param values 113 * @param whereColumns 114 * @param whereArgs 115 * @return 116 */ 117 public boolean update(String tableName,String[] columns,Object[] values,String[] whereColumns,String[] whereArgs){ 118 ContentValues contentValues = new ContentValues(); 119 for (int i=0;i<columns.length;++i){ 120 this.ContentValuesPut(contentValues,columns[i],values[i]); 121 } 122 String whereClause = this.initWhereSqlFromArray(whereColumns); 123 int rowNumber = this.mDb.update(tableName,contentValues,whereClause,whereArgs); 124 return rowNumber > 0 ; 125 } 126 127 /** 128 * 根据map值来进行update 129 * @param tableName 130 * @param columnValues 131 * @param whereParam 132 * @return 133 */ 134 public boolean update(String tableName,Map<String,Object> columnValues,Map<String,String> whereParam){ 135 ContentValues contentValues = new ContentValues(); 136 Iterator iterator = columnValues.keySet().iterator(); 137 138 String columns; 139 while (iterator.hasNext()){ 140 columns = (String) iterator.next(); 141 ContentValuesPut(contentValues,columns,columnValues.get(columns)); 142 } 143 144 Map map = this.initWhereSqlFromMap(whereParam); 145 int rowNumber = this.mDb.update(tableName,contentValues,(String)map.get("whereSql"),(String[]) map.get("whereSqlParam")); 146 return rowNumber > 0; 147 } 148 149 /** 150 * 根据数组条件进行delete 151 * @param tableName 152 * @param whereColumns 153 * @param whereParam 154 * @return 155 */ 156 public boolean delete(String tableName,String[] whereColumns,String[] whereParam){ 157 String whereStr = this.initWhereSqlFromArray(whereColumns); 158 int rowNumber = this.mDb.delete(tableName,whereStr,whereParam); 159 return rowNumber > 0; 160 } 161 162 163 /** 164 * 根据map来进行delete 165 * @param tableName 166 * @param whereParams 167 * @return 168 */ 169 public boolean delete(String tableName,Map<String,String> whereParams){ 170 Map map = this.initWhereSqlFromMap(whereParams); 171 int rowNumber = this.mDb.delete(tableName,map.get("whereSql").toString(),(String[]) map.get("whereSqlParam")); 172 return rowNumber > 0; 173 } 174 175 176 /** 177 * 查询返回List 178 * @param sql 179 * @param params 180 * @return 181 */ 182 public List<Map> queryListMap(String sql,String[] params){ 183 ArrayList list = new ArrayList(); 184 Cursor cursor = this.mDb.rawQuery(sql,params); 185 int columnCount = cursor.getColumnCount(); 186 while (cursor.moveToNext()){ 187 HashMap item = new HashMap(); 188 for (int i=0;i<columnCount;++i){ 189 int type = cursor.getType(i); 190 switch (type){ 191 case 0: 192 item.put(cursor.getColumnName(i),null); 193 break; 194 case 1: 195 item.put(cursor.getColumnName(i), cursor.getInt(i)); 196 break; 197 case 2: 198 item.put(cursor.getColumnName(i),cursor.getFloat(i)); 199 break; 200 case 3: 201 item.put(cursor.getColumnName(i),cursor.getString(i)); 202 break; 203 } 204 } 205 list.add(item); 206 } 207 cursor.close(); 208 return list; 209 } 210 211 /** 212 * 查询单条数据返回map 213 * @param sql 214 * @param params 215 * @return 216 */ 217 public Map queryItemMap(String sql,String[] params){ 218 Cursor cursor = this.mDb.rawQuery(sql,params); 219 HashMap map = new HashMap(); 220 if (cursor.moveToNext()){ 221 for (int i = 0;i < cursor.getColumnCount();++i){ 222 int type = cursor.getType(i); 223 switch (type){ 224 case 0: 225 map.put(cursor.getColumnName(i),null); 226 break; 227 case 1: 228 map.put(cursor.getColumnName(i),cursor.getInt(i)); 229 break; 230 case 2: 231 map.put(cursor.getColumnName(i),cursor.getFloat(i)); 232 break; 233 case 3: 234 map.put(cursor.getColumnName(i),cursor.getString(i)); 235 break; 236 } 237 } 238 } 239 cursor.close(); 240 return map; 241 } 242 243 public void execSQL(String sql){ 244 this.mDb.execSQL(sql); 245 } 246 247 public void execSQL(String sql,Object[] params){ 248 this.mDb.execSQL(sql,params); 249 }
上面的操作代码就完毕了,这里主要对增删改的参数是数组和Map的情况进行了处理,对查询的结果进行了处理,代码比较简单也都有注释,这里就不做特别说明了。到这里一个数据库操作类就成型了。
3、操作类的继续完善
通过上面的过程已经可以使用了,那么先来看看使用,我们只需要继承操作抽象类告诉它具体的数据库信息以及建表语句。
1public class TestDBHelper extends DataBaseHelper { 2 3 private static TestDBHelper mTestDBHelper; 4 5 private TestDBHelper(Context context){ 6 super(context); 7 } 8 9 public static TestDBHelper getInstance(Context context){ 10 if (mTestDBHelper==null){ 11 synchronized (DataBaseHelper.class){ 12 if (mTestDBHelper==null){ 13 mTestDBHelper = new TestDBHelper(context); 14 if (mTestDBHelper.getDB()==null||!mTestDBHelper.getDB().isOpen()){ 15 mTestDBHelper.open(); 16 } 17 } 18 } 19 } 20 return mTestDBHelper; 21 } 22 23 @Override 24 protected int getMDbVersion(Context context) { 25 return 1; 26 } 27 28 @Override 29 protected String getDbName(Context context) { 30 return "test.db"; 31 } 32 33 @Override 34 protected String[] getDbCreateSql(Context context) { 35 String[] a = new String[1]; 36 a[0] = "CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,gender TEXT,age INTEGER)"; 37 return a; 38 } 39 40 @Override 41 protected String[] getDbUpdateSql(Context context) { 42 return new String[0]; 43 } 44}
重写父类的抽象方法告诉它数据库信息以及建表语句,然后提供一个单例供外部获取,如果没有open就open数据库,接下来看看使用
4、使用
直接获取,然后传入你想操作的表信息,So Easy!
1public class MainActivity extends AppCompatActivity implements View.OnClickListener { 2 3 private Button selectBtn; 4 private Button insertBtn; 5 private Button updateBtn; 6 private Button deleteBtn; 7 private TextView contentTv; 8 9 private TestDBHelper testDBHelper; 10 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_main); 15 16 testDBHelper = TestDBHelper.getInstance(getApplicationContext()); 17 18 selectBtn = (Button) findViewById(R.id.select_btn); 19 insertBtn = (Button) findViewById(R.id.insert_btn); 20 updateBtn = (Button) findViewById(R.id.update_btn); 21 deleteBtn = (Button) findViewById(R.id.delete_bt); 22 contentTv = (TextView) findViewById(R.id.content_tv); 23 24 25 selectBtn.setOnClickListener(this); 26 insertBtn.setOnClickListener(this); 27 updateBtn.setOnClickListener(this); 28 deleteBtn.setOnClickListener(this); 29 } 30 31 @Override 32 public void onClick(View v) { 33 switch (v.getId()){ 34 case R.id.select_btn: 35 List<Map> list = testDBHelper.queryListMap("select * from user",null); 36 contentTv.setText(String.valueOf(list)); 37 break; 38 case R.id.insert_btn: 39 testDBHelper.insert("user",new String[]{"name","gender","age"},new Object[]{"qiangyu","male",23}); 40 break; 41 case R.id.update_btn: 42 testDBHelper.update("user",new String[]{"name","gender","age"},new Object[]{"yangqiangyu","male",24}, 43 new String[]{"name"},new String[]{"qiangyu"}); 44 break; 45 case R.id.delete_bt: 46 testDBHelper.delete("user", 47 new String[]{"name"},new String[]{"qiangyu"}); 48 break; 49 } 50 } 51}
很简单了,附一张演示图
gif制作了做了压缩,图的效果不好请见谅

是不是简单多了
5、最后的完善
在第3步里,我们的数据库信息,和建表语句都是写在具体的代码里的,这样我们每次修改都要动代码。Android推荐我们这些具体的信息都写在配置文件xml里面,那么我们就来做一下修改。
建立一个db.xml
1<?xml version="1.0" encoding="utf-8"?> 2<resources> 3 4 <array name="DATABASE_INFO"> 5 <item>test.db</item> 6 <item>1</item> 7 </array> 8 9 <array name="CREATE_TABLE_SQL"> 10 <item>CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,gender TEXT,age INTEGER)</item> 11 </array> 12 13 <array name="UPDATE_TABLE_SQL"> 14 <item></item> 15 </array> 16 17</resources>
现在的获取数据信息的代码是这样
1 @Override 2 protected int getMDbVersion(Context context) { 3 return Integer.valueOf(context.getResources().getStringArray(R.array.DATABASE_INFO)[1]); 4 } 5 6 @Override 7 protected String getDbName(Context context) { 8 return context.getResources().getStringArray(R.array.DATABASE_INFO)[0]; 9 } 10 11 @Override 12 protected String[] getDbCreateSql(Context context) { 13 return context.getResources().getStringArray(R.array.CREATE_TABLE_SQL); 14 } 15 16 @Override 17 protected String[] getDbUpdateSql(Context context) { 18 return context.getResources().getStringArray(R.array.UPDATE_TABLE_SQL); 19 }
从配置文件当中获取数据库信息,这样以后每次修改只需要修改xml文件就可以了。
6、结语
到此,一个数据库操作类就完成啦,当然你可以根据自己的需要在其实添加更多的便捷操作方法。
这里提供的操作类,在使用的时候我们还在需要在Activity中写一些查询的sql代码,我们可以再搞一个统一做各种具体操作表的对象。
觉得不错别忘记点赞哟!
最后送给大家一个鸡汤,共勉
他每做一件小事的时候 他都像救命稻草一样抓着 有一天我一看 嚯 好家伙 他抱着的是已经是让我仰望的参天大树