通用数据库CRUD操作
通用数据库CRUD操作
chenruibing 发表于3年前
通用数据库CRUD操作
  • 发表于 3年前
  • 阅读 474
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

对于属性  id  表单名的注解

package com.example.dbcommon.dao.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 指定了实体的字段与数据库中表中列的对应关系
 * @author Administrator
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	/**
	 * 数据库中的表名
	 * @return
	 */
	String value();
}
package com.example.dbcommon.dao.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 标志主键
 * @author Administrator
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ID {

	boolean autoincrement();
	
}
package com.example.dbcommon.dao.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 制定了将实体与数据库表中的对应关系
 * @author Administrator
 *
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
	/**
	 * 数据库中的表名
	 * @return
	 */
	String value();
}
实体类。可以直接在实体类注解,这样就知道了类的属性对应表的那个字段以及是否是id并且是否自增长等
package com.example.dbcommon.dao.domain;

import com.example.dbcommon.dao.DBHelper;
import com.example.dbcommon.dao.annotation.Column;
import com.example.dbcommon.dao.annotation.ID;
import com.example.dbcommon.dao.annotation.TableName;

@TableName(DBHelper.TABLE_NEWS_NAME)
public class News {

	//主键:明确,值的获取
	@ID(autoincrement=true)
	@Column(DBHelper.TABLE_ID)
	private int id;
	@Column(DBHelper.TABLE_NEWS_TITLE)
	private String title;
	@Column(DBHelper.TABLE_NEW_SUMMARY)
	private String summary;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getSummary() {
		return summary;
	}
	public void setSummary(String summary) {
		this.summary = summary;
	}
	
}
CRUD操作通用接口
package com.example.dbcommon.dao;

import java.io.Serializable;
import java.util.List;

/**
 * 实体操作的通用接口
 * @author Administrator
 *
 */
public interface DAO<M> {
	
	long insert(M m);
	int delete(Serializable id); //int long String
	int update(M m);
	List<M> findAll();
}

继承接口实现通用操作(基于所有类)

cursor.close()不关的话,最多提供300多个游标,超过了不报错,但是游标是空的,即便查出数据了也是空的

可以获取当前运行的类

通过class可以获取支持泛型的父类,也可以获取父类泛型的类型

通过class可以获取注解的value值,也可以设置value的值

通过class可以遍历所有字段

//问题1:表名的获取
    //解决方案1:获取到实体,字母小写就是表名。。不过定义实体的名称被受限制
    //解决方案2:利用注解,实体名称和数据库表名称脱离关系

package com.example.dbcommon.dao;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import com.example.dbcommon.dao.annotation.Column;
import com.example.dbcommon.dao.annotation.ID;
import com.example.dbcommon.dao.annotation.TableName;

import android.R.id;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.provider.ContactsContract.Data;
import android.util.Log;

public abstract class DaoSupportt<M> implements DAO<M>{


	private static final String TAG = "DaoSupportt";
	protected Context context;
	protected DBHelper helper;
	protected SQLiteDatabase db;
	public DaoSupportt(Context context) {
		super();
		this.context = context;
		this.helper = new DBHelper(context);
		this.db = helper.getWritableDatabase();
	}
	@Override
	public long insert(M m) {
		// TODO Auto-generated method stub
		ContentValues values = new ContentValues();
		
		fillColumn(m,values);//数据源第一个参数,导入的目标第二个参数
		return db.insert(getTableName(), null, values);
	}
	
	@Override
	public int delete(Serializable id) {
		// TODO Auto-generated method stub
		return db.delete(getTableName(), DBHelper.TABLE_ID + " =?", new String[]{id.toString()});
	}
	@Override
	public int update(M m) {
		// TODO Auto-generated method stub
		ContentValues values = new ContentValues();
		
		fillColumn(m,values);//数据源第一个参数,导入的目标第二个参数
		return db.update(getTableName(), values, DBHelper.TABLE_ID + " =?	", new String[]{getid(m)});
	}
	
	public List<M> findByCondition(String[] columns, String selection,
            String[] selectionArgs, String orderBy){
		return findByCondition(columns, selection, selectionArgs, null, null, orderBy);
	}
	
	/**
	 * 条件查询
	 * @param columns
	 * @param selection
	 * @param selectionArgs
	 * @param groupBy
	 * @param having
	 * @param orderBy
	 * @return
	 */
	public List<M> findByCondition(String[] columns, String selection,
            String[] selectionArgs, String groupBy, String having,
            String orderBy){
		List<M> result = null;
		Cursor cursor = db.query(getTableName(), columns, selection, selectionArgs, groupBy,
                having, orderBy);
		if(cursor != null){
			result = new ArrayList<M>();
			while(cursor.moveToNext()){
				M m = getInstrance();
				
				fillField(cursor,m);
				
				result.add(m);
			}
			//不关的话,最多提供300多个游标,超过了也不报错,但是提供的游标是空的,即便查出数据了也是空的
			cursor.close();
		}
		return result;
	}
	
	@Override
	public List<M> findAll() {
		// TODO Auto-generated method stub
		List<M> result = null;
		Cursor cursor = db.query(getTableName(), null, null, null, null, null, null);
		if(cursor != null){
			result = new ArrayList<M>();
			while(cursor.moveToNext()){
				M m = getInstrance();
				
				fillField(cursor,m);
				
				result.add(m);
			}
			//不关的话,最多提供300多个游标,超过了也不报错,但是提供的游标是空的,即便查出数据了也是空的
			cursor.close();
		}
		return result;
	}
	
	
	//问题1:表名的获取
	//解决方案1:获取到实体,字母小写就是表名。。不过定义实体的名称被受限制
	//解决方案2:利用注解,实体名称和数据库表名称脱离关系
	private String getTableName(){
		
		//获取实体
		M m = getInstrance();
		//获取实体的注解,依据value里设置值确定操作的数据库表
		//如果需要在运行时获取到注解的信息,设置存活的时间
		TableName tableName = m.getClass().getAnnotation(TableName.class);//annotationType:注解的类型
		if(tableName != null){
			return tableName.value();
		}
		return "";
	}
	//问题5:实体的对象创建
	private M getInstrance(){
		//实体是何时确定的?
		
		//1:是那个孩子调用的该方法-那个孩子在运行
		//jdk解释:返回此Object的运行时类
		Class clazz = getClass();
		//class com.ithm.dbhm28.dao.impl.NewsDaoImpl
//		Log.i(TAG, clazz.toString());
		
		//2:获取该孩子的父类(支持泛型的父类)
//		clazz.getSuperclass();//class com.ithm.dbhm28.dao.base.DAOSupport
		Type superclass = clazz.getGenericSuperclass();//com.ithm.dbhm28.dao.base.DAOSupport<com.ithm.dbhm28.dao.domain.News>
		//泛型实现接口,只要是泛型都会实现这个接口(参数化的类型),规定了泛型的通用操作
		if(superclass != null && superclass instanceof ParameterizedType){
			//[class com.ithm.dbhm28.dao.domain.News]
			Type[] arguments = ((ParameterizedType)superclass).getActualTypeArguments();
			try {
				return (M) ((Class)arguments[0]).newInstance();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		//3:获取到泛型中的参数
		return null;
	}
	//问题2:如何将实体中的数据,按照对应关系导入到数据库表中
	private void fillColumn(M m, ContentValues values) {
		// TODO Auto-generated method stub
//		values.put(DBHelper.TABLE_NEWS_TITLE, news.getTitle());
//		//此处省略N行代码
//		m.getClass().getFields();//获取类的所有public字段
		Field[] fields = m.getClass().getDeclaredFields();//获取类的所有字段
		for(Field item : fields){
			//要有权限 要不然一定会进入IllegalArgumentException这报没有权限的异常
			item.setAccessible(true);
			Column column = item.getAnnotation(Column.class);
			if(column != null){
				String key = column.value();
				
				try {
					String value = item.get(m).toString();
					//如果该field是主键,并且是自增的,不能添加到集合中
					ID id = item.getAnnotation(ID.class);
					if(id!=null && id.autoincrement()){
						//是主键就不要给数据,一旦给予数据,数据库就认为程序猿自己接管主键数据,数据库不再自增添加
					}else{
						values.put(key, value);
					}
					
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}
	}
	//问题4:明确实体中主键,获取到主键中封装的值
	private String getid(M m) {
		// TODO Auto-generated method stub
		Field[] fields = m.getClass().getDeclaredFields();
		for(Field item : fields){
			item.setAccessible(true);
			ID id = item.getAnnotation(ID.class);
			if(id != null){
				try {
					return item.get(m).toString();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return null;
	}
	
	//问题3:将数据表中列的数据,按照对应关系导入到实体中
	private void fillField(Cursor cursor, M m) {
		// TODO Auto-generated method stub

//		int columnIndex = cursor.getColumnIndex(DBHelper.TABLE_NEWS_TITLE);
//		String title = cursor.getString(columnIndex);
//		news.setTitle(title);
//		此处省略N行代码
		
		Field[] fields = m.getClass().getDeclaredFields();
		for(Field item : fields){
			item.setAccessible(true);
			Column column = item.getAnnotation(Column.class);
			if(column != null){
				int columnIndex = cursor.getColumnIndex(column.value());
				String value = cursor.getString(columnIndex);
				//在News里面  id是int类型   在这里是String类型,所以填充数据会出错
				try {
					if(item.getType() == int.class){
						item.set(m, Integer.parseInt(value));
					}else if(item.getType() == Data.class){
						//字符串转换成时间
					}else{
						item.set(m, value);
					}
					
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
接口类实现特定的类的通用CRUD接口,接口约束规范化
package com.example.dbcommon.dao;

import java.util.List;

import com.example.dbcommon.dao.domain.News;

/**
 * 新闻表操作的接口
 * @author Administrator
 *
 */
public interface NewsDao extends DAO<News>{

//	long insert(News news);
//	int delete(int id);
//	int update(News news);
//	List<News> findAll();
}

具体类实现特定的类的CRUD接口

package com.example.dbcommon.dao.impl;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.example.dbcommon.dao.DBHelper;
import com.example.dbcommon.dao.DaoSupportt;
import com.example.dbcommon.dao.NewsDao;
import com.example.dbcommon.dao.domain.News;

public class NewsDaoImpl extends DaoSupportt<News> implements NewsDao {

	public NewsDaoImpl(Context context) {
		super(context);
		
	}
	
	/*@Override
	public long insert(News news) {
		// TODO Auto-generated method stub
		ContentValues values = new ContentValues();
		values.put(DBHelper.TABLE_NEWS_TITLE, news.getTitle());
		//此处省略N行代码
		return db.insert(DBHelper.TABLE_NEWS_NAME, null, values);
	}
	

	@Override
	public int delete(int id) {
		// TODO Auto-generated method stub
		return db.delete(DBHelper.TABLE_NEWS_NAME, DBHelper.TABLE_ID + " =?", new String[]{id+""});
	}

	@Override
	public int update(News news) {
		// TODO Auto-generated method stub
		ContentValues values = new ContentValues();
		values.put(DBHelper.TABLE_NEWS_TITLE, news.getTitle());
		//此处省略N行代码
		return db.update(DBHelper.TABLE_NEWS_NAME, values, DBHelper.TABLE_ID + " =?	", new String[]{news.getId() + ""});
	}

	@Override
	public List<News> findAll() {
		// TODO Auto-generated method stub
		List<News> result = null;
		Cursor cursor = db.query(DBHelper.TABLE_NEWS_NAME, null, null, null, null, null, null);
		if(cursor != null){
			result = new ArrayList<News>();
			while(cursor.moveToNext()){
				News news = new News();
				int columnIndex = cursor.getColumnIndex(DBHelper.TABLE_NEWS_TITLE);
				String title = cursor.getString(columnIndex);
				news.setTitle(title);
				//此处省略N行代码
				result.add(news);
			}
			//不关的话,最多提供300多个游标,超过了也不报错,但是提供的游标是空的,即便查出数据了也是空的
			cursor.close();
		}
		return null;
	}*/

}

进行测试

package com.example.dbcommon.test;

import java.util.List;

import com.example.dbcommon.dao.DBHelper;
import com.example.dbcommon.dao.domain.News;
import com.example.dbcommon.dao.impl.NewsDaoImpl;

import android.test.AndroidTestCase;

public class DBTest extends AndroidTestCase {

	public void createTable(){
		DBHelper hbHelper = new DBHelper(getContext());
		hbHelper.getWritableDatabase();
	}
	
	public void testInsert(){
		NewsDaoImpl impl = new NewsDaoImpl(getContext());
		News m = new News();
		m.setTitle("测试标题一");
		m.setSummary("测试摘要一");
		impl.insert(m);
	}

	public void testDelete(){
		NewsDaoImpl impl = new NewsDaoImpl(getContext());
		impl.delete(0);
	}
	public void testUpdate(){
		NewsDaoImpl impl = new NewsDaoImpl(getContext());
		News m = new News();
		m.setId(2);
		m.setTitle("hm28N");
		m.setSummary("PP");
		impl.update(m);
	}
	public void testFindAll(){
		NewsDaoImpl impl = new NewsDaoImpl(getContext());
		List<News> findAll = impl.findAll();
		System.out.println();
	}
}
数据库的组件。

对于数据库不同version的更新值得借鉴。

package com.example.dbcommon.dao;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.v7.internal.widget.ActivityChooserModel.HistoricalRecord;

public class DBHelper extends SQLiteOpenHelper {

	private static final String NAME = "ithm.db";
	private static final int START_VERSION = 1;
	private static final int CURRENT_VERSION = 2;
	public DBHelper(Context context) {
		super(context, NAME, null, CURRENT_VERSION);
		// TODO Auto-generated constructor stub
	}

	//新闻表: 主键 + 标题 + 摘要
	public static final String TABLE_ID = "id";
	
	public static final String TABLE_NEWS_NAME = "news";
	public static final String TABLE_NEWS_TITLE = "titile";
	public static final String TABLE_NEW_SUMMARY = "summary";
	
	
	@Override
	public void onCreate(SQLiteDatabase db) {
		// TODO Auto-generated method stub
			db.execSQL("CREATE TABLE" + TABLE_NEWS_NAME + "(" + //
			TABLE_ID + " integer primary key autoincrement, " +// 
			TABLE_NEWS_TITLE + "varchar(50), " + //
			TABLE_NEW_SUMMARY + "varchar(200))"//
		);
		onUpgrade(db, START_VERSION, CURRENT_VERSION);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub
		//更新
		//数据库版本管理:1.0(一张表),2.0(两张表)
		//模拟两种用户
		//老用户:1.0
		//新用户:2.0
		//老用户会更新,没有问题,新用户只有更新后的表,更新前的表就没有
		
		//希望:不需要总是考虑老用户,每次升级数据库操作是什么
		switch(oldVersion){
		case START_VERSION:
			
		case CURRENT_VERSION:
			
		case 3:
		case 4:
			break;
		}
	}

}




共有 人打赏支持
粉丝 11
博文 201
码字总数 109101
×
chenruibing
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: