android数据库-sqlite基础类封装

android使用数据库存储,无非有两种

1、使用原生的sqlite

2、使用第三方库

使用原生sqlite可封装成orm或者简单的封装(便于初级入手),关于sqlite orm。笔者作简单封装一下,直接上代码:

GitHub源码

一、创建一个DatabaseManager,管理数据库的打开和关闭

public class DatabaseManager {

    private AtomicInteger mOpenCounter = new AtomicInteger();
    private static DatabaseManager instance;
    private static DbOpenHelper mDatabaseHelper;
    private SQLiteDatabase mDatabase;

    public static synchronized void initializeInstance(DbOpenHelper helper) {
        if (instance == null) {
            instance = new DatabaseManager();
            mDatabaseHelper = helper;
            //启用数据库的预写日志
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                mDatabaseHelper.setWriteAheadLoggingEnabled(true);
            }
        }
    }

    public static synchronized DatabaseManager getInstance() {
        if (instance == null) {
            throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
                    " is not initialized, call initializeInstance(..) method first.");
        }

        return instance;
    }

    public synchronized SQLiteDatabase openDatabase() {

        if (mOpenCounter.incrementAndGet() == 1) {
            // Opening new database
            try {
                mDatabase = mDatabaseHelper.getWritableDatabase();
            } catch (Exception e) {
                mDatabase = mDatabaseHelper.getReadableDatabase();
            }
        }
        return mDatabase;

    }


    public synchronized void closeDatabase() {
        if (mOpenCounter.decrementAndGet() == 0) {
            // Closing database
            mDatabase.close();

        }
    }

}

关于setWriteAheadLoggingEnabled

public void setWriteAheadLoggingEnabled(boolean enabled) {
    synchronized (this) {
        if (mEnableWriteAheadLogging != enabled) {
            if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
                if (enabled) {
                    mDatabase.enableWriteAheadLogging();
                } else {
                    mDatabase.disableWriteAheadLogging();
                }
            }
            mEnableWriteAheadLogging = enabled;
        }
    }
}

这个方法的作用是:启用或禁用数据库的预写日志。

预写日志不能用于只读的数据库,因此如果数据库是以只读的方式被打开,这个标记值会被忽略。

源代码的 if (mEnableWriteAheadLogging != enabled) 的使用方法可以借鉴一下,这行代码从逻辑上是可有可无的,它的妙处在于减少了不必要的代码执行,提高了效率(如果设置的值和当前值相等,就不作任何操作)。

那么这个预写日志到底是什么?

从源码可以看到如果 enabled 的值为 true,就会调用 mDatabase.enableWriteAheadLogging(); 。

调用此方法后,只要数据库保持打开,则并行执行查询操作。用于并行执行查询的连接的最大数目取决于设备内存和其他属性。如果一个查询是事务的一部分,那么它就在同一个数据库句柄上执行。

它通过打开数据库的多个连接并为每个查询使用不同的数据库连接来实现在同一数据库中并行执行多个线程的查询,同时数据库的日志模式也被更改以启用写入与读取同时进行。

当预写日志没有启用时(默认状态),同一时间在数据库上读取和写入是不可能的。因为写入线程会在修改数据库之前隐式地获取数据库上的互斥锁,以防止写入操作完成之前其他线程读取访问数据库。

相反,当启用预写日志时,写入操作会在分离的日志文件中进行,该文件允许读取同时进行。当数据库正在进行写入操作时,其他线程上的读取操作将在写入开始前会感知数据库的状态,当写入操作完成后,其他线程上的读取操作将感知数据库的新状态。

当数据库同时被多个线程同时访问和修改时,启用预写日志是一个好办法。然而,开启预写日志功能,会比普通日记使用更多的内存,因为同一个数据库有多个连接。因此,如果一个数据库只有一个线程使用,或者优化并发不是很重要,那么应该禁用预写日志功能。
 

二、创建一个BaseDao,数据表基类

public abstract class BaseDao<T> {

    /**
     * 插入或更新单条数据
     *
     * @param item
     */
    public synchronized void insertOrUpdate(T item) {
        ArrayList<T> tmpList = getListInfo();
        try {
            SQLiteDatabase db = DatabaseManager.getInstance().openDatabase();
            if (db.isOpen()) {
                //db是否存在此数据
                boolean isExist = false;
                for (T tmpInfo : tmpList) {
                    if (compareItem(item, tmpInfo)) {
                        isExist = true;
                        break;
                    }
                }
                if (isExist) {
                    updateItem(db, item);
                } else {
                    db.insert(getTableName(), null, getContentValues(item));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DatabaseManager.getInstance().closeDatabase();
        }
    }

    /**
     * 插入单条数据
     *
     * @param item
     */
    public synchronized void insert(T item) {
        try {
            SQLiteDatabase db = DatabaseManager.getInstance().openDatabase();
            if (db.isOpen()) {
                db.insert(getTableName(), null, getContentValues(item));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DatabaseManager.getInstance().closeDatabase();
        }
    }

    /**
     * 批量插入(旧数据删除)
     *
     * @param dataList
     */
    public synchronized void insert(ArrayList<T> dataList) {
        try {
            SQLiteDatabase db = DatabaseManager.getInstance().openDatabase();
            if (db.isOpen()) {
                db.beginTransaction(); // 手动设置开始事务

                deleteAll(db);

                for (T item : dataList) {
                    db.insert(getTableName(), null, getContentValues(item));

                }
                db.setTransactionSuccessful(); // 设置事务处理成功,不设置会自动回滚不提交
                db.endTransaction(); // 处理完成
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DatabaseManager.getInstance().closeDatabase();
        }
    }


    /**
     * 批量插入或更新
     */
    public synchronized void insertOrUpdate(List<T> dataList) {
        ArrayList<T> tmpList = getListInfo();

        try {
            SQLiteDatabase db = DatabaseManager.getInstance().openDatabase();
            if (db.isOpen()) {
                db.beginTransaction(); // 手动设置开始事务


                for (T item : dataList) {

                    boolean isExist = false;//db是否存在此数据

                    for (T tmpInfo : tmpList) {

                        if (compareItem(item, tmpInfo)) {
                            isExist = true;
                            break;
                        }
                    }
                    if (isExist) {
                        updateItem(db, item);
                    } else {
                        db.insert(getTableName(), null, getContentValues(item));
                    }
                }

                db.setTransactionSuccessful(); // 设置事务处理成功,不设置会自动回滚不提交
                db.endTransaction(); // 处理完成

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DatabaseManager.getInstance().closeDatabase();
        }
    }

    /**
     * 获取map集合
     *
     * @return
     */
    public Map<Object, T> getMapInfo(String key) {
        Map<Object, T> map = new HashMap<>();

        Cursor cursor = null;

        try {
            SQLiteDatabase db = DatabaseManager.getInstance().openDatabase();
            cursor = db.query(getTableName(), null, null, null, null, null, null);

            if (db.isOpen()) {
                while (cursor.moveToNext()) {

                    String id = cursor.getString(cursor.getColumnIndex(key));
                    map.put(id, getItemInfo(cursor));

                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
            DatabaseManager.getInstance().closeDatabase();
        }
        return map;

    }

    /**
     * 获取list集合
     *
     * @return
     */
    public ArrayList<T> getListInfo() {
        ArrayList<T> msgList = new ArrayList<>();

        Cursor cursor = null;

        try {
            SQLiteDatabase db = DatabaseManager.getInstance().openDatabase();
            cursor = db.query(getTableName(), null, null, null, null, null, null);
            if (db.isOpen()) {
                while (cursor.moveToNext()) {
                    msgList.add(getItemInfo(cursor));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
            DatabaseManager.getInstance().closeDatabase();
        }
        return msgList;
    }


    /**
     * 获取list集合(自定义db和cursor)
     *
     * @return
     */
    public ArrayList<T> getListInfo(SQLiteDatabase db, Cursor cursor) {
        ArrayList<T> msgList = new ArrayList<>();

        try {
            if (db.isOpen()) {
                while (cursor.moveToNext()) {
                    msgList.add(getItemInfo(cursor));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
            DatabaseManager.getInstance().closeDatabase();
        }
        return msgList;
    }

    /**
     * 获取表名
     *
     * @return
     */
    public abstract String getTableName();

    /**
     * item转ContentValues
     *
     * @param item
     * @return
     */
    public abstract ContentValues getContentValues(T item);

    /**
     * 获取item
     *
     * @param cursor
     * @return
     */
    public abstract T getItemInfo(Cursor cursor);

    /**
     * 对比两个item是否相同
     *
     * @param item1
     * @param item2
     * @return
     */
    public abstract boolean compareItem(T item1, T item2);

    /**
     * 更新item
     *
     * @param db
     * @param item
     */
    public abstract void updateItem(SQLiteDatabase db, T item);

    /**
     * 删除所有信息
     *
     * @param db
     */
    public void deleteAll(SQLiteDatabase db) {
        try {
            db.delete(getTableName(), null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除所有信息
     */
    public void deleteAll() {
        try {
            SQLiteDatabase db = DatabaseManager.getInstance().openDatabase();
            if (db.isOpen()) {
                db.delete(getTableName(), null, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DatabaseManager.getInstance().closeDatabase();
        }
    }


    public String getString(Cursor cursor, String name) {
        return cursor.getString(cursor.getColumnIndex(name));
    }

    public int getInt(Cursor cursor, String name) {
        return cursor.getInt(cursor.getColumnIndex(name));
    }

    public long getLong(Cursor cursor, String name) {
        return cursor.getLong(cursor.getColumnIndex(name));
    }

    public float getFloat(Cursor cursor, String name) {
        return cursor.getFloat(cursor.getColumnIndex(name));
    }

    public boolean getBool(Cursor cursor, String name) {
        return cursor.getInt(cursor.getColumnIndex(name)) == 1;
    }
}

在BaseDao中看到使用到事务,为什么需要是事务?

使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功

如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。

事务处理应用:

很多时候我们需要批量的向Sqlite中插入大量数据时,单独的使用添加方法导致应用响应缓慢, 因为sqlite插入数据的时候默认一条语句就是一个事务,有多少条数据就有多少次磁盘操作。如初始1000条记录也就是要1000次读写磁盘操作。同时也是为了保证数据的一致性,避免出现数据缺失等情况。
 

三、创建SQLiteOpenHelper,这里创建一个搜索历史表作为例子

public class DbOpenHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 1;
    private static DbOpenHelper instance;


    /**
     * 搜索历史数据
     */
    private static final String SEARCH_HISTORY_TABLE_CREATE = "CREATE TABLE "
            + SearchHistoryDao.TABLE_NAME + " ("
            + SearchHistoryDao.COLUMN_NAME_PRIMARY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
            + SearchHistoryDao.COLUMN_NAME_MSG + " TEXT, "
            + SearchHistoryDao.COLUMN_NAME_TIME + " DATETIME); ";


    private DbOpenHelper(Context context) {
        super(context, getUserDatabaseName(), null, DATABASE_VERSION);
    }

    public synchronized static DbOpenHelper getInstance(Context context) {
        if (instance == null) {
            instance = new DbOpenHelper(context.getApplicationContext());
        }
        return instance;
    }

    private static String getUserDatabaseName() {
        return "test.db";
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(SEARCH_HISTORY_TABLE_CREATE);
     
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      
    }

  

}

四、创建搜索历史表SearchHistoryDao

public class SearchHistoryDao extends BaseDao<String> {

    public static final String TABLE_NAME = "SearchHistory";

    public static final String COLUMN_NAME_PRIMARY_ID = "id";//主键id
    public static final String COLUMN_NAME_MSG = "msg";//String
    public static final String COLUMN_NAME_TIME = "time";//

    private static SearchHistoryDao instance;

    public synchronized static SearchHistoryDao getInstance() {
        if (instance == null) {
            instance = new SearchHistoryDao();
        }
        return instance;
    }


    @Override
    public String getTableName() {
        return TABLE_NAME;
    }

    @Override
    public ContentValues getContentValues(String item) {
        ContentValues values = new ContentValues();
        values.put(COLUMN_NAME_MSG, item);
        values.put(COLUMN_NAME_TIME, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(new Date()));

        return values;
    }

    @Override
    public String getItemInfo(Cursor cursor) {
        return getString(cursor, COLUMN_NAME_MSG);
    }

    @Override
    public boolean compareItem(String item1, String item2) {
        return item1.equals(item2);
    }

    @Override
    public void updateItem(SQLiteDatabase db, String item) {
        db.update(getTableName(), getContentValues(item), COLUMN_NAME_MSG + " = ?", new String[]{item});
    }

}

五、初始化数据库

public class MyApplication extends BaseApplication {

   @Override
    public void onCreate() {
        super.onCreate();
     DatabaseManager.initializeInstance(DbOpenHelper.getInstance(this));
    }

}

六、使用查询表

插入

SearchHistoryDao.getInstance().insert("123")

查询

searchHistoryDao.getInstance().getListInfo()


 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
大家好,个人觉得用Sqlite数据库时,经常需要进行机械性的CRUD操作,故对其进行了一下封装,希望能起到抛砖引玉的作用。 目的:封装共有的CRUD 下面简单的说一下使用步骤,如果觉得多余,可以无视。 1. 实现自己的DBHelper: /** * * @author Kee.Li * * 1. 继承了SmartDBHelper,不需要重写SQLiteOpenHelper的那两个方法 * 2. 父构造方法参数modelClasses是实体的数组,也就是需要生产表的的Class数组 * */ public class DBHelper extends SmartDBHelper { //数据库名称 private final static String DATABASE_NAME = "books.db"; //数据库版本 private final static int DATABASE_VERSION = 2; //需要生成数据库表的的数组 private final static Class<?>[] modelClasses = {Book.class,User.class}; public DBHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION,modelClasses); } } 2.创建app需要的实体,也就是对应的数据库表(这里的实体添加到DBHelper的modelClasses数组中) /** * 数据库的实体 * @author Kee.Li * 关于注解: * Table: 此对应的数据库表名 * Id:标识此属性为数据库自增长的id,应为int型 * Column:标识此属性对应的数据库字段名 */ @Table(name="t_books") public class Book{ @Id @Column(name="book_id") private int bookId; @Column(name="book_name") private String bookName; @Column(name="book_author") private String bookAuthor; //set get 方法省略.... } 3. 实现DAO,也就是对实体的CRUD /** * @author Kee.Li * * 此只需要继承TemplateDAO,在构造方法里面给父的属性dbHelper赋值,即可实现CRUD操作 * 若有复杂的操作,可以自定义方法 */ public class BookDAO extends TemplateDAO { /** * 创建DAO时初始化连接数据库对象helper * @param context */ public BookDAO(Context context) { super(new DBHelper(context)); } } 4. activity的调用 bookDAO = new BookDAO(this); List books = bookDAO.find(); 好了,到此结束,如果有什么好的建议或者意见,希望可以共同学习!谢谢大家!
一个简单的基于AndroidSqlite数据库的操作封装,它有如下的好处:便捷地创建表和增添表字段灵活的数据型处理通过操作对象来insert或者update表记录支持多种查询方式,支持多表自定义的复杂查询,支持分页查询支持事务快速开始:    1. 设计表:@Table(name="t_user") public class UserModel {     @Table.Column(name="user_id",type=Column.TYPE_INTEGER,isPrimaryKey=true)     public Integer userId;     @Table.Column(name="user_name",type=Column.TYPE_STRING,isNull=false)     public String userName;     @Table.Column(name="born_date",type=Column.TYPE_TIMESTAMP)     public Date bornDate;     @Table.Column(name="pictrue",type=Column.TYPE_BLOB)     public byte[] pictrue;     @Table.Column(name="is_login",type=Column.TYPE_BOOLEAN)     public Boolean isLogin;     @Table.Column(name="weight",type=Column.TYPE_DOUBLE)     public Double weight; }2. 初始化对象:SQLiteDatabase db = context.openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null); DbSqlite dbSqlite = new DbSqlite(db); IBaseDao userDAO = DaoFactory.createGenericDao(dbSqlite, UserModel.class);3. 创建表:userDAO.createTable(); 4. Insert 记录:UserModel user = new UserModel(); user.userName = "darcy"; user.isLogin = true; user.weight = 60.5; user.bornDate = new Date(); byte[] picture = {0x1,0x2,0x3,0x4}; user.pictrue = picture; userDAO.insert(user);5. Update 记录:UserModel user = new UserModel(); user.weight = 88.0; userDAO.update(user, "user_name=?", "darcy");6. 查询://单条结果查询 UserModel user = userDAO.queryFirstRecord("user_name=?", "darcy"); //一般查询 List userList = userDAO.query("user_name=? and weight > ?", "darcy" , "60"); //分页查询 PagingList pagingList = userDAO.pagingQuery(null, null, 1, 3);7. 事务支持:DBTransaction.transact(mDb, new DBTransaction.DBTransactionInterface() {         @Override         public void onTransact() {             // to do                 } };8. 更新表(目前只支持添加字段)@Table(name="t_user" , version=2) //修改表版本 public class UserModel {     //members above...     //new columns     @Table.Column(name="new_column_1",type=Column.TYPE_INTEGER)     public Integer newColumn;     @Table.Column(name="new_column_2",type=Column.TYPE_INTEGER)     public Integer newColumn2; } userDAO.updateTable();缺点和不足:还没支持多对一或者一多的关系没支持联合主键没支持表的外键设计其他...实例:SqliteLookup(Android内查看Sqlite数据库利器): https://github.com/YeDaxia/SqliteLookup 标签:SQLiteUtils
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值