Android非常轻量的SQLite数据库访问对象

jopen 12年前

  在Android开发中我们经常会使用到SQLite数据库以及数据库的一些基本操作.  在这里介绍一种非常轻量级的数据库访问方法, 希望对于那些不想引入第三方ORM库, 而是完全采用SQL操作数据库的人能够提供一些方便.
    基本思路和ORM差不多, 采用annotation来对实体类进行标注, 但是简化了很多. 实体类的书写方式, 以及数据库的存储和读取方式和ORM基本一样. 废话不多说, 直接上代码...

Example.java 

package com.pls.share.db;    import java.util.Date;    import android.database.sqlite.SQLiteDatabase;  import android.util.Log;    import com.pls.share.db.entity.TUser;    /**   * @author jiuwuerliu@sina.com   *    * 调用示例   */  public class Example {   static final String tag="Example";      private SQLiteDatabase db;   public SQLiteDatabase createDatabase(){      SQLiteDatabase db=SQLiteDatabase.create(null);      String createdb=      "CREATE TABLE IF NOT EXISTS t_user("      +"id         VARCHAR(64) PRIMARY KEY,"      +"name       VARCHAR(512),"      +"status     INTEGER NOT NULL DEFAULT 0,"      +"createTime DATETIME"      +");";    db.execSQL(createdb);        return db;   }      public Example(){    db=createDatabase();   }      public void insert(){    SqliteDAO dao=new SqliteDAO(db);        TUser user=new TUser();    user.setId("user001");    user.setName("tsc9526");    user.setCreateTime(new Date());    user.setStatus(1);        //插入对象到数据库    dao.insert(user);   }      public void load(){    SqliteDAO dao=new SqliteDAO(db);        TUser user=new TUser();    user.setId("user001");         //载入数据库到对象    dao.loadByPrimaryKey(user);         Log.i(tag, "ID: "+user.getId()+", name: "+user.getName()+", status: "+user.getStatus());   }      }

TUser.java

package com.pls.share.db.entity;    import java.util.Date;    import com.pls.share.db.annotation.Id;  import com.pls.share.db.annotation.Table;  import com.pls.share.db.annotation.Transient;       /**   * @author jiuwuerliu@sina.com   *    * 数据库实体对象   */  @Table(name="t_user")  public class TUser{   /**    * 主键字段    */    @Id   private String id;      private Integer status;        private String name;      private Date createTime;      /**    * 非数据库字段    */   @Transient   private String detail;      public TUser(){}      public String getId() {    return id;   }     public void setId(String id) {    this.id = id;   }     public Integer getStatus() {    return status;   }     public void setStatus(Integer status) {    this.status = status;   }     public Date getCreateTime() {    return createTime;   }     public void setCreateTime(Date createTime) {    this.createTime = createTime;   }     public String getDetail() {    return detail;   }     public void setDetail(String detail) {    this.detail = detail;   }     public String getName() {    return name;   }     public void setName(String name) {    this.name = name;   }       }

 SqliteDAO.java

package com.pls.share.db;    import java.lang.annotation.Annotation;  import java.lang.reflect.Field;  import java.lang.reflect.Method;  import java.text.ParseException;  import java.text.SimpleDateFormat;  import java.util.ArrayList;  import java.util.Date;  import java.util.List;    import android.content.ContentValues;  import android.database.Cursor;  import android.database.sqlite.SQLiteDatabase;  import android.util.Log;    import com.pls.share.db.annotation.Id;  import com.pls.share.db.annotation.Table;  import com.pls.share.db.annotation.Transient;    /**   * @author jiuwuerliu@sina.com   *     */  public class SqliteDAO{    static final String tag="DAO";      /**    * 访问的数据库    */   private SQLiteDatabase db;      /**    * 数据插入冲突处理方式:    * 0-忽略    * 1-抛出异常    * 2-替换数据    */   private int conflictType=2;      public SqliteDAO(SQLiteDatabase db){    this.db=db;      }      public SQLiteDatabase getSQLiteDatabase(){    return db;   }      /**    * 插入对象到数据库, 存储对象的所有字段到数据库的对应字段,包括NULL字段.    * @param entity  待插入的对象    * @return 如果插入数据库成功则返回该对象,否则返回NULL    */   public <T> T insert(T entity){    return insert(entity,false);   }      /**    * 插入对象到数据库, 仅存储对象的非空字段到数据库,对象的NULL字段将被忽略.    * @param entity 待插入的对象    * @return 如果插入数据库成功则返回该对象,否则返回NULL    */   public <T> T insertSelective(T entity){    return insert(entity,true);   }         private <T> T insert(T entity,boolean selective){      ContentValues values=getContentValues(entity,selective);        T exist_obj=this.loadByPrimaryKey(entity);    if(exist_obj!=null){     return exist_obj;    }         long r=0;    if(conflictType==2){     r=db.replace(getTableName(entity), null,values);       }else{     r=db.insert(getTableName(entity), null, values);        }        if(r>=0){     return entity;    }         return null;       }      /**    * 根据主键删除数据    * @param entity 待删除的对象, 主键只必须设置.    * @return    */   public <T> int delete(T entity){    Object[] args=getPrimarySelectionAndArgs(entity);    return db.delete(getTableName(entity), (String)args[0], (String[])args[1]);     }         /**    * 根据主键从数据库载入一条记录到对象    * @param entity 数据实体(必须初始化主键字段)    * @return 成功则返回的该数据库实体,失败则返回NULL    */   public <T> T loadByPrimaryKey(T entity){    Object[] args=getPrimarySelectionAndArgs(entity);    Cursor cursor=db.query(getTableName(entity), null,(String)args[0],(String[])args[1], null,null,null);    try{     if(cursor.moveToNext()){      T db_entity=getEntity(cursor,entity);      return db_entity;     }else{      return null;     }    }finally{     cursor.close();    }   }         @SuppressWarnings("unchecked")   public <T> List<T> loadAll(T entity,String orderBy){     List<T> entities=new ArrayList<T>();        Cursor cursor=db.query(getTableName(entity), null,null,null, null,null,orderBy);    try{     if(cursor!=null && cursor.moveToFirst()){      T obj=(T)entity.getClass().newInstance();      getEntity(cursor,obj);            entities.add(obj);           }while(cursor.moveToNext());          return entities;    }catch(Exception e){     Log.e(tag,""+e,e);          return entities;    }finally{     cursor.close();    }   }      /**    * 更新数据库实体,  更新对象的所有字段到数据库的对应字段,包括NULL字段.    * @param entity 待更新的对象(必须包含主键)    * @return 成功更新的记录数    */   public int updateByPrimaryKey(Object entity){    return updateByPrimaryKey(entity,false);   }      /**    * 更新数据库实体,  仅更新对象的非空字段到数据库的对应字段,对象的NULL字段将被忽略.    * @param entity 待更新的对象(必须包含主键)    * @return 成功更新的记录数    */   public int updateByPrimaryKeySelective(Object entity){    return updateByPrimaryKey(entity,true);   }      private int updateByPrimaryKey(Object entity,boolean selective){    ContentValues values=getContentValues(entity,selective);    Object[] args=getPrimarySelectionAndArgs(entity);        int r=db.update(getTableName(entity), values, (String)args[0],(String[])args[1]);        return r;    }      /**    * 从对象中解析出主键字段, 以及主键字段对应的值     * @param entity    * @return    */   private Object[] getPrimarySelectionAndArgs(Object entity){    Object[] ret=new Object[2];    String selection=null;    List<String> args=new ArrayList<String>();    try{     Class<?> entity_class=entity.getClass();        Field[] fs=entity_class.getDeclaredFields();     for(Field f:fs){      if(isPrimaryKey(f)){           Method get=getGetMethod(entity_class,f);       if(get!=null){        Object o=get.invoke(entity);              String value=null;        if(o!=null){         value=o.toString();         if(selection==null){          selection=f.getName()+"=?";                 }else{          selection+=" AND "+f.getName()+"=?";         }                  args.add(value);                 }else{         throw new RuntimeException("Primary key: "+f.getName()+" must not be null");        }       }      }     }        if(selection==null){      throw new RuntimeException("Primary key not found!");     }          ret[0]=selection;     ret[1]=args.toArray(new String[args.size()]);     return ret;    }catch(Exception e){     throw new RuntimeException(e.getMessage(),e);    }   }       /**    * 将对象转换为ContentValues    * @param entity    * @param selective    * @return    */   private ContentValues getContentValues(Object entity,boolean selective){    ContentValues values=new ContentValues();    try{     Class<?> entity_class=entity.getClass();        Field[] fs=entity_class.getDeclaredFields();     for(Field f:fs){      if(isTransient(f)==false){           Method get=getGetMethod(entity_class,f);       if(get!=null){        Object o=get.invoke(entity);        if(!selective || (selective && o!=null)){         String name=f.getName();               Class<?> type=f.getType();         if(type==String.class){          values.put(name,(String)o);         }else if(type==int.class || type==Integer.class){          values.put(name,(Integer)o);         }else if(type==float.class || type==Float.class){          values.put(name,(Float)o);         }else if(type==long.class || type==Long.class){          values.put(name,(Long)o);         }else if(type==Date.class){          values.put(name,datetimeToString((Date)o));         }else{           values.put(name,o.toString());                 }        }       }      }     }     return values;    }catch(Exception e){     throw new RuntimeException(e.getMessage(),e);    }   }      /**    * 将数据库记录转换为对象    *     * @param cursor    * @param entity    * @return    */   private <T> T getEntity(Cursor cursor, T entity){     try{     Class<?> entity_class=entity.getClass();          Field[] fs=entity_class.getDeclaredFields();     for(Field f:fs){      int index=cursor.getColumnIndex(f.getName());      if(index>=0){            Method set=getSetMethod(entity_class,f);       if(set!=null){        String value=cursor.getString(index);                   if(cursor.isNull(index)){         value=null;        }        Class<?> type=f.getType();        if(type==String.class){         set.invoke(entity,value);        }else if(type==int.class || type==Integer.class){         set.invoke(entity,value==null?(Integer)null:Integer.parseInt(value));        }else if(type==float.class || type==Float.class){         set.invoke(entity,value==null?(Float)null:Float.parseFloat(value));        }else if(type==long.class || type==Long.class){         set.invoke(entity,value==null?(Long)null:Long.parseLong(value));        }else if(type==Date.class){         set.invoke(entity,value==null?(Date)null:stringToDateTime(value));        }else{          set.invoke(entity,value);              }               }      }     }         return entity;    }catch(Exception e){     throw new RuntimeException(e.getMessage(),e);    }   }      private String datetimeToString(Date d){    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    if(d!=null){     return sdf.format(d);    }    return null;   }      private Date stringToDateTime(String s){    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    if(s!=null){     try {      return sdf.parse(s);     } catch (ParseException e) {          Log.e(tag,"解析时间错误: "+s,e);     }    }    return null;   }      private Method getGetMethod(Class<?> entity_class,Field f){    String fn=f.getName();    String mn="get"+fn.substring(0,1).toUpperCase()+fn.substring(1);    try{        return entity_class.getDeclaredMethod(mn);    }catch(NoSuchMethodException e){     Log.w(tag,"Method: "+mn+" not found.");          return null;    }   }      private Method getSetMethod(Class<?> entity_class,Field f){    String fn=f.getName();    String mn="set"+fn.substring(0,1).toUpperCase()+fn.substring(1);    try{        return entity_class.getDeclaredMethod(mn,f.getType());    }catch(NoSuchMethodException e){     Log.w(tag,"Method: "+mn+" not found.");          return null;    }   }       /**    * 检查是否为主键字段    */   private boolean isPrimaryKey(Field f){       Annotation an=f.getAnnotation(Id.class);    if(an!=null){     return true;        }    return false;   }      private boolean isTransient(Field f){       Annotation an=f.getAnnotation(Transient.class);    if(an!=null){     return true;        }    return false;   }           private String getTableName(Object entity){    Table table=entity.getClass().getAnnotation(Table.class);    String name= table.name();    return name;   }      public int getConflictType() {    return conflictType;   }     public void setConflictType(int conflictType) {    this.conflictType = conflictType;   }        }

Id.java

package com.pls.share.db.annotation;    import java.lang.annotation.ElementType;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;    /**   * @author jiuwuerliu@sina.com   *    * 标注为主键字段   */  @Target(ElementType.FIELD)  @Retention(RetentionPolicy.RUNTIME)   public @interface Id {    }

Table.java

package com.pls.share.db.annotation;    import java.lang.annotation.ElementType;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;    /**   * @author jiuwuerliu@sina.com   *    *  标注数据库表名   */  @Target(ElementType.TYPE)  @Retention(RetentionPolicy.RUNTIME)   public @interface  Table {   /**    * @return 数据库表名    */   String name();  }

Transient.java

package com.pls.share.db.annotation;    import java.lang.annotation.ElementType;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;    /**   * @author jiuwuerliu@sina.com   *    * 标注为非数据库字段   */  @Target(ElementType.FIELD)  @Retention(RetentionPolicy.RUNTIME)   public @interface Transient {    }