前言:
你还在苦恼的写SQL么?你还在为数据库升级而烦恼么?你还在因查询数据而写繁琐不可用的代码么? 在这,这些都将不复存在!在本篇中,将会让你一点一滴从无到有创建一个不再为数据库而烦恼的框架。
在开始之前我们先欣赏一下本章实现的最终效果 效果展示
如图所示:
- 对应的
model,可直接成为表结构,不再写对应的Create table xxx对应的SQL了 - 对应
model的Dao层,里面封装了数据表的基本操作(增删改查) - 对应的增删改查操作,再也不用SQL了,全用对象处理
接下来开始实战了
1、先创建对应相关操作的注解
1.1 bTable 标识表
|
1
2
3
4
5
6
|
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface DbTable { //表名
String value();
} |
1.2 DbPrimaryKey 标识主键
|
1
2
3
4
5
6
7
8
9
10
|
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DbPrimaryKey { //表列名
String value();
//是否为自动增长
boolean isAuto() default false;
} |
1.3DbFiled 标识成员属性
|
1
2
3
4
5
6
7
8
9
10
11
|
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DbFiled { //表列名
String value();
/*
这里可以像主键一样,添加其他属性,比如是否唯一约束,是否非空等
甚至可以将主键的约束放在这里来,只是表明可以这样做,具体怎样扩展,完全可以按你们想法来
*/
} |
2、创建对应表操作类Dao层
2.1 建 待实现的基层 IBaseDao
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public interface IBaseDao<T> { Long insert(T entity);
int update(T entity, T where);
/**
* 删除数据
*
* @param where
* @return
*/
int delete(T where);
/**
* 查询数据
*/
List<T> query(T where);
List<T> query(T where, String groupBy, String orderBy, String having, Integer startIndex,
Integer limit);
} |
代码分析:
这里创建了基类 IBaseDao ,拥有待实现的增删改查, T 代表对应的 数据表结构的 model。
2.2 建已实现的基层 BaseDao
|
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
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
|
public class BaseDao<T> implements IBaseDao<T> { private static final String TAG = "hqk";
/**
* 持有数据库操作类的引用
*/
private SQLiteDatabase database;
/**
* 持有操作数据库表所对应的java类型
* User
*/
private Class<T> entityClass;
/**
* 保证实例化一次
*/
private boolean isInit = false;
private String tableName;
// 检查表
private HashMap<String, Field> cacheMap;
protected BaseDao() {
}
protected synchronized boolean init(Class<T> entity, SQLiteDatabase sqLiteDatabase) {
if (!isInit) {
//初始化完了 自动建表
entityClass = entity;
database = sqLiteDatabase;
if (entity.getAnnotation(DbTable.class) == null) {
tableName = entity.getClass().getSimpleName();
} else {
tableName = entity.getAnnotation(DbTable.class).value();
}
if (!database.isOpen()) {
return false;
}
String sql = createTable();
database.execSQL(sql);
//建立好映射关系
initCacheMap();
isInit = true;
}
return true;
}
/**
* 将真实表中的列名 + 成员变量进行 映射
* 缓存对应的 表 Model里的属性名以及对应表列名
*/
private void initCacheMap() {
cacheMap = new HashMap<>();
//这里没有必要查询 对应表中的任何数据,只想要对应表列名,所以 这 limit 0
String sql = "select * from " + tableName + " limit 0";
Cursor cursor = database.rawQuery(sql, null);
String[] columnNames = cursor.getColumnNames();
Field[] columnFields = entityClass.getDeclaredFields();
//获取对应表中的列名数组,以及对应表Model里面的属性数组
for (String columnName : columnNames) {
Field resultField = null;
for (Field field : columnFields) {
//拿到对应属性的注解值
String fieldAnnotationName = field.getAnnotation(DbFiled.class).value();
//如果对应的属性注解值与数据库表列名相同,则拿到对应属性值
if (columnName.equals(fieldAnnotationName)) {
resultField = field;
break;
}
}
if (resultField != null) {
cacheMap.put(columnName, resultField);
}
}
}
/**
* 组装 创建表的SQL语句
*
* @return
*/
private String createTable() {
StringBuffer stringBuffer = new StringBuffer();
//开始组装 SQL语句
stringBuffer.append("create table if not exists ");
stringBuffer.append(tableName + " (");
Field[] fields = entityClass.getDeclaredFields();
for (Field field : fields) {
Class type = field.getType();
String primaryKey = null;
try {
primaryKey = field.getAnnotation(DbPrimaryKey.class).value();
} catch (Exception e) {
}
Log.i(TAG, "createTable primaryKey " + primaryKey);
Log.i(TAG, "createTable type " + type);
if (type == String.class) {
if (null == primaryKey) {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " TEXT,");
} else {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " TEXT PRIMARY KEY,");
}
} else if (type == Double.class) {
if (null == primaryKey) {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " DOUBLE,");
} else {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " DOUBLE PRIMARY KEY,");
}
} else if (type == Integer.class) {
if (null == primaryKey) {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " INTEGER,");
} else {
boolean isAuto = field.getAnnotation(DbPrimaryKey.class).isAuto();
if (isAuto) {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " INTEGER PRIMARY KEY AUTOINCREMENT,");
} else {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " INTEGER PRIMARY KEY,");
}
}
} else if (type == Long.class) {
if (null == primaryKey) {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " BIGINT,");
} else {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " BIGINT PRIMARY KEY,");
}
} else if (type == byte[].class) {
if (null == primaryKey) {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " BLOB,");
} else {
stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " BLOB PRIMARY KEY,");
}
} else {
/*
不支持的类型
*/
continue;
}
}
//循环完成后,最后一项会有 逗号 ,如果最后一个是逗号,则删除最后一个字符
if (stringBuffer.charAt(stringBuffer.length() - 1) == \',\') {
stringBuffer.deleteCharAt(stringBuffer.length() - 1);
}
//SQL 语句 收尾
stringBuffer.append(")");
Log.i(TAG, "createTable: " + stringBuffer.toString());
return stringBuffer.toString();
}
@Override
public Long insert(T entity) {
Map<String, String> map = getValues(entity);
ContentValues contentValues = getContentValues(map);
return database.insert(tableName, null, contentValues);
}
/**
* 获取对应 model 属性以及对应的注解值(表列名值)
*
* @param entity 对应 表结构的model
* @return 返回 key= 列名,value=属性的值 map集合
*/
private Map<String, String> getValues(T entity) {
HashMap<String, String> map = new HashMap<>();
//获取对应缓存 model 里面的属性键
Iterator<Field> fieldIterator = cacheMap.values().iterator();
while (fieldIterator.hasNext()) {
Field field = fieldIterator.next();
field.setAccessible(true);
try {
Object object = field.get(entity);
if (object == null) {
continue;
}
String value = object.toString();
String key = field.getAnnotation(DbFiled.class).value();
//遍历 取出对应 属性的值 以及对应的 注解值,并添加至Map里
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
map.put(key, value);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return map;
}
/**
* 数据库数据结构的封装
*
* @param map 带有 以表列名为键,的map
* @return 数据库需要的封装格式
*/
private ContentValues getContentValues(Map<String, String> map) {
ContentValues contentValues = new ContentValues();
Set keys = map.keySet();
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
String value = map.get(key);
if (value != null) {
contentValues.put(key, value);
}
}
return contentValues;
}
@Override
public int update(T entity, T where) {
Map values = getValues(entity);
ContentValues contentValues = getContentValues(values);
//条件
Map whereMap = getValues(where);
Condition condition = new Condition(whereMap);
return database.update(tableName, contentValues, condition.whereClause, condition.whereArgs);
}
class Condition {
String whereClause;
String[] whereArgs;
public Condition(Map<String, String> whereClause) {
boolean flag = false;
if (true && flag) {
}
ArrayList list = new ArrayList();
StringBuilder stringBuilder = new StringBuilder();
// 这里之所以先添加 1=1 这个条件 是因为
// SQL where 后面需要给条件判断,而下面 while 循环 直接添加了 and
// SQL 语句就变成了 where and 这显然不符合SQL语句
// 因此 加上 1=1 就变成了 where 1=1 and xx。起了一个呈上去下的作用
stringBuilder.append("1=1");
Set keys = whereClause.keySet();
Iterator iterator = keys.iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
String value = whereClause.get(key);
if (value != null) {
stringBuilder.append(" and " + key + " =?");
list.add(value);
}
}
this.whereClause = stringBuilder.toString();
this.whereArgs = (String[]) list.toArray(new String[list.size()]);
}
}
@Override
public int delete(T where) {
Map map = getValues(where);
Condition condition = new Condition(map);
return database.delete(tableName, condition.whereClause, condition.whereArgs);
}
@Override
public List<T> query(T where) {
return query(where, null, null, null, null, null
);
}
//所有 条件
@Override
public List<T> query(T where, String groupBy, String orderBy, String having,Integer startIndex,
Integer limit) {
String limitString=null;
if(startIndex!=null&&limit!=null)
{
limitString=startIndex+" , "+limit;
}
Map map=getValues(where);
Condition condition=new Condition(map);
Cursor cursor= database.query(tableName, null, condition.whereClause,
condition.whereArgs,
groupBy, having,
orderBy, limitString
);
// 封装 --返回
List<T> result = getResult(cursor, where);
cursor.close();
return result;
}
private List<T> getResult(Cursor cursor, T where) {
ArrayList list=new ArrayList();
Object item;
while (cursor.moveToNext()) {
try {
// cachmap ---对象中的成员变量 Filed annotion-- tb_name
//cacheMap name ---Filed 1
// tb_name ---Filed 2
item=where.getClass().newInstance();
Iterator iterator=cacheMap.entrySet().iterator();
while (iterator.hasNext())
{
Map.Entry entry= (Map.Entry) iterator.next();
//tb_name
/**
* 得到列名
*/
String colomunName= (String) entry.getKey();
// 通过列名查找到游标的索性
Integer colmunIndex= cursor.getColumnIndex(colomunName);
// Filed
//反射的成员 cursor
Field field= (Field) entry.getValue();
Class type=field.getType();
if(colmunIndex!=-1)
{
// if (type == String.class) {
field.set(item, cursor.getString(colmunIndex));
}else if(type==Double.class)
{
field.set(item,cursor.getDouble(colmunIndex));
}else if(type==Integer.class)
{
field.set(item,cursor.getInt(colmunIndex));
}else if(type==Long.class)
{
field.set(item,cursor.getLong(colmunIndex));
}else if(type==byte[].class)
{
field.set(item,cursor.getBlob(colmunIndex));
/*
不支持的类型
*/
}else {
continue;
}
}
}
list.add(item);
} catch ( Exception e) {
e.printStackTrace();
}
}
return list;
}
} |
代码分析:
在这个BaseDao 里面,几乎分担了数据表大部分的脏活累活,根据model结构自动生成对应SQL并创建对应表,以及基础的增删改查操作。
2.3 建对应model 的Dao层
1.UserDao
|
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
|
public class UserDao<User> extends BaseDao<User> { @Override
public Long insert(User entity) {
return super.insert(entity);
}
@Override
public List<User> query(User where) {
return super.query(where);
}
@Override
public int delete(User where) {
return super.delete(where);
}
@Override
public int update(User entity, User where) {
return super.update(entity, where);
}
@Override
public List<User> query(User where, String groupBy, String orderBy, String having, Integer startIndex, Integer limit) {
return super.query(where, groupBy, orderBy, having, startIndex, limit);
}
} |
2.PhotoDao
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class PhotoDao<Photo> extends BaseDao<Photo> { @Override
public Long insert(Photo entity) {
return super.insert(entity);
}
@Override
public int update(Photo entity, Photo where) {
return super.update(entity, where);
}
@Override
public List<Photo> query(Photo where) {
return super.query(where);
}
@Override
public int delete(Photo where) {
return super.delete(where);
}
} |
代码分析:
虽然 BaseDao 已经完成了几乎所有的操作,但是一旦遇到多表查询的时候,光是一个BaseDao远远不够。所以这里还是选择创建不同model的Dao层,并继承与BaseDao。也就是说,有多少表,最好就创建对应多少个Dao层(参考资料:https://suowo.cn)。
3、创建数据库工厂
|
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
|
public class BaseDaoFactory { private final String TAG = "hqk";
private SQLiteDatabase sqLiteDatabase;
private String sqliteDatabasePath;
private static BaseDaoFactory instance = new BaseDaoFactory();
//饿汉单例模式
public static BaseDaoFactory getInstance() {
return instance;
}
public BaseDaoFactory() {
//读者可随意更改路径以及对应数据库名,这里演示暂时放在根目录
sqliteDatabasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/hqk.db";
sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqliteDatabasePath, null);
Log.i(TAG, "sqliteDatabasePath : " + sqliteDatabasePath);
Log.i(TAG, "sqLiteDatabase : " + sqLiteDatabase.getPath());
}
/**
* @param clazz
* @param entityClass
* @param <R> 我们在这可以把它看成某一个对象,它继承与 BaseDao<T> ,而里面的T 就是下面的那个空对象
* @param <T> 我们在这可以吧它看成某一个空对象 T
* @return
*/
public synchronized <R extends BaseDao<T>, T> R createBaseDao(Class<R> clazz, Class<T> entityClass) {
BaseDao baseDao = null;
try {
baseDao = clazz.newInstance();
baseDao.init(entityClass, sqLiteDatabase);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return (R) baseDao;
}
} |
代码分析:
这里也没啥好分析的,就一个数据库创建,以及对应model的初始化。唯一值得注意的就是初始化的时候用了俩个泛型,具体什么意思,可按照代码注释理解。
4、创建对应model
1.User
|
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
|
@DbTable("tb_user")
public class User { @DbPrimaryKey(value = "tb_id", isAuto = true)
@DbFiled("tb_id")
public Integer id;
@DbFiled("tb_name")
public String name;//
@DbFiled("tb_age")
public Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public User() {
}
} |
2.Photo
|
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
|
@DbTable("tb_photo")
public class Photo { @DbFiled("time")
private String time;
@DbFiled("id")
private Long id;
@DbFiled("path")
private String path;
public Photo( ) {
}
public Photo(String time, Long id, String path) {
this.time = time;
this.id = id;
this.path = path;
}
public void setTime(String time) {
this.time = time;
}
public void setId(Long id) {
this.id = id;
}
public void setPath(String path) {
this.path = path;
}
} |
代码分析:
这俩类就是对应表结构model 类,用到了对应注解,相信通过注解能够清楚知道对应表结构是怎样的。
5、最终使用
ainActivity
|
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
|
public class MainActivity extends AppCompatActivity { UserDao<User> userDao;
PhotoDao<Photo> photoDao;
private ArrayList<User> listUser = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission(this);
}
public void save(View view) {
User user = new User("hqk", 18);
long size = userDao.insert(user);
Photo photo = new Photo("time", System.currentTimeMillis(), "path");
long photoSize = photoDao.insert(photo);
Toast.makeText(this, "save line : " + size, Toast.LENGTH_LONG).show();
}
public void update(View view) {
User where = new User();
where.setAge(18);
int size = userDao.update(new User("TOM", 99), where);
Toast.makeText(this, "update Size : " + size, Toast.LENGTH_LONG).show();
}
public void delete(View view) {
User where = new User();
where.setAge(18);
int size = userDao.delete(where);
Toast.makeText(this, "delete Size : " + size, Toast.LENGTH_LONG).show();
}
public void queryList(View view) {
listUser.clear();
listUser.addAll(userDao.query(new User()));
Toast.makeText(this, "查询条数为:" + listUser.size(), Toast.LENGTH_LONG).show();
}
public void requestPermission(
Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ActivityCompat.checkSelfPermission(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
return;
}
createTable();
}
private void createTable() {
userDao = BaseDaoFactory.getInstance().createBaseDao(UserDao.class, User.class);
photoDao = BaseDaoFactory.getInstance().createBaseDao(PhotoDao.class, Photo.class);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
createTable();
}
} |