清华大佬耗费三个月吐血整理的几百G的资源,免费分享!....>>>
在Android开发中我们经常会使用到SQLite数据库以及数据库的一些基本操作. 在这里介绍一种非常轻量级的数据库访问方法, 只需要400多行代码.希望对于那些不想引入第三方ORM库, 而是完全采用SQL操作数据库的人能够提供一些方便. 基本思路和ORM差不多, 采用annotation来对实体类进行标注, 但是简化了很多. 实体类的书写方式, 以及数据库的存储和读取方式和ORM基本一样。
Example.java
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
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
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;
}
}
Android SQLite数据库访问对象
在Android开发中我们经常会使用到SQLite数据库以及数据库的一些基本操作. 在这里介绍一种非常轻量级的数据库访问方法, 只需要400多行代码.希望对于那些不想引入第三方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=; if(conflictType==2){ r=db.replace(getTableName(entity), null,values); }else{ r=db.insert(getTableName(entity), null, values); } if(r>=){ return entity; } return null; } /**
* 根据主键删除数据
* @param entity 待删除的对象, 主键只必须设置.
* @return
*/ public <T> int delete(T entity){ Object[] args=getPrimarySelectionAndArgs(entity); return db.delete(getTableName(entity), (String)args[], (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[],(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[],(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[]=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>=){ 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(,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(,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
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
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
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 {
}