标签(空格分隔): 未分类
为了提升自身的技能,有些时候就不能总依赖第三方的开源,虽然那些大牛写出来的东西很好用,但是对自身技能包却没有多大提升。所以还是决定写一下自己的DB框架,虽然写的不好,但是会提高自己的数据库操作技能,同时还能锻炼架构能力,实现从0到1的渐变。
废话不多说,直接开始吧。
class Developer{
private String id;
private String name;
private int age;
}
建表SQL:
create table if not exists developer([id] TEXT primary key,[name] TEXT,[age] Integer)
从这个简单的例子,我们就能分析出,建表所需要的元素。
需要表名,表字段,字段类型,如果我们依据实体模型建表,便于同实体模型一一对应,采用实体类名作为表名,类属性作为表字段。
因此,第一步功能:获取表名,字段名,字段类型
为了方便,这里引入注解辅助建表
//表注解,获取表名
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table{
String name();
}
//字段注解,确定主键,字段名,字段类型
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column{
//确定主键
boolean id() default false;
//字段名
String name() default "";
//字段类型
ColumnType type() default UNKNOW;
public enum ColumnType{
TONE, TMANY, SERIALIZABLE, UNKNOW
}
}
所以引入注解后的Developer.java如下
@Table(name="developer")
class Developer{
@Column(id = true)
private String id;
@Column
private String name;
@Column
private int age;
}
下面要做的就是利用反射机制,获取需要的元素
(1). 获取表名
public static String getTableName(Class> clz) {
if (clz.isAnnotationPresent(Table.class)) {
String name = clz.getAnnotation(Table.class).name();
//判断非空
if (TextUtils.isValidate(name)) {
return name;
} else {
return clz.getSimpleName().toLowerCase();
}
}
throw new IllegalArgumentException("the class " + clz.getSimpleName() + " can't map to the table");
}
此时建表语句,我们就进行到了
create table if not exists getTableName(xx)(..?..)
下一步自然就是确定主键,字段名,字段类型
//确定主键
public static String getIDColumnName(Class> clz) {
if (!clz.isAnnotationPresent(Table.class)) {
return null;
}
Field[] fields = clz.getDeclaredFields();
Column column = null;
for (Field field : fields) {
if (field.isAnnotationPresent(Column.class)) {
column = field.getAnnotation(Column.class);
if (column.id()) {
String id = column.value();
if (!TextUtils.isValidate(id)) {
id = field.getName();
}
return id;
}
}
}
return null;
}
//确定字段名,字段类型
public static String getOneColumnStmt(Field field) {
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
//字段名
String name = column.name();
//加[]防止关键字冲突
if (!TextUtils.isValidate(name)) {
name = "[" + field.getName() + "]";
} else {
name = "[" + name + "]";
}
String type = null;
Class> clz = field.getType();
//确定字段类型
if (clz == String.class) {
type = " TEXT ";
} else if (clz == int.class || clz == Integer.class) {
type = " Integer ";
} else {
//TODO
}
name += type;
if (column.id()) {
name += " primary key ";
}
return name;
}
return "";
}
拼接建表语句
private static String getCreateTableStmt(Class> clz) {
StringBuilder mColumnStmts = new StringBuilder();
mColumnStmts.append("create table if not exists ").append(getTableName(clz)).append(" ( ");
if (clz.isAnnotationPresent(Table.class)) {
Field[] fields = clz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].isAnnotationPresent(Column.class)) {
mColumnStmts.append(getOneColumnStmt(fields[i]));
mColumnStmts.append(",");
}
}
if (mColumnStmts.length() > 0) {
mColumnStmts.delete(mColumnStmts.length() - 2, mColumnStmts.length());
}
}
mColumnStmts.append(")");
return mColumnStmts.toString();
}
测试结果如下:
11-16 15:12:56.791: I/System.out(2076): create table if not exists developer ( [age] Integer ,[id] TEXT primary key ,[name] TEXT )
删表语句:
delete table if exists developer;
建表:利用android提供的SQLiteOpenHelper进行建表删表
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "stay4it.db";
public static final int DB_VERSION = 1;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
public DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
DBUtils.createTable(db, Developer.class);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
DBUtils.dropTable(db, Developer.class);
}
}
注解请参考:公共技术点之 Java 注解 Annotation
反射请参考:公共技术点之 Java 反射 Reflection
至此,简单的建表就完成了。