大家在做安卓项目时肯定都会碰到数据库存储,原生的效率上会比较低,为了提高开发效率,大多公司会用一些框架,目前市面上比较流行的框架有ormlite、greenDao、SQLBrite、Realm等,其中ormlite是JDBC(Java数据库连接)和Android的轻量级ORM java包,而GreenDao则是一种轻快地将对象映射到SQLite数据库的ORM解决方案。
下面让我们快速的学习一下ormlite的简单使用
首先去ormlite官网下载所需的jar包,现在最新版本已经更新到5.0,分别为:ormlite-android-5.0.jar 和 ormlite-core-5.0.jar
这里我们定义两个类,父母和孩子的关系
父母类
package com.liuw.ormlite.bean;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
/**
* 父母
*/
//定义表名
@DatabaseTable(tableName = "tab_parent")
public class Parents {
//generatedId定义主键自增长,columnName定义该字段在数据库中的列名
@DatabaseField(useGetSet=true,generatedId=true,columnName="id")
private int id;
@DatabaseField(useGetSet=true, columnName = "f_id")
private String fid;//父母编号
@DatabaseField(useGetSet=true, columnName = "f_name")
private String fname;//父亲姓名
@DatabaseField(useGetSet=true, columnName = "m_name")
private String mname;//母亲姓名
public Parents() {
}
public Parents(String fid, String fname, String mname) {
this.fid = fid;
this.fname = fname;
this.mname = mname;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFid() {
return fid;
}
public void setFid(String fid) {
this.fid = fid;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public String getMname() {
return mname;
}
public void setMname(String mname) {
this.mname = mname;
}
@Override
public String toString() {
return "Parents{" +
"id=" + id +
", fid='" + fid + '\'' +
", fname='" + fname + '\'' +
", mname='" + mname + '\'' +
'}';
}
}
child类,孩子是属于某个父母,那肯定是需要parent类的主键才能找到关系,有的人可能会直接在child类里声明一个parent类里的fid属性,当做普通属性来处理,但这样就违背了面向对象思想
所以这里我们采用面向对象思想应该是这样,child属于某个parent,在child类里声明外键parent类来处理,这样的话在获取孩子信息的同时也能获取到对应父母的信息
package com.liuw.ormlite.bean;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
/**
* 孩子
*/
@DatabaseTable(tableName = "tab_child")
public class Childs {
@DatabaseField(useGetSet=true,generatedId=true,columnName="id")
private int id;
@DatabaseField(useGetSet=true, columnName = "s_name")
private String sname;//姓名
@DatabaseField(useGetSet=true, columnName = "s_gender")
private String sgender;//性别
@DatabaseField(useGetSet=true, columnName = "s_age")
private String sage;//年龄
@DatabaseField(useGetSet=true, columnName = "s_phone")
private String sphone;//联系方式
//引入外键(columnName值默认存储父类中的主键对应的值,也可以换成foreignColumnName指定父类字段,格式为foreignColumnName = "父表里的字段"
//如foreignColumnName = "f_name",此时将会存储父表里对应的字段内容)
@DatabaseField(useGetSet=true, canBeNull = true, foreign = true, columnName = "s_parent")
private Parents parents;//父母信息
public Childs() {
}
public Childs(String sname, String sgender, String sage) {
this.sname = sname;
this.sgender = sgender;
this.sage = sage;
}
public String getSphone() {
return sphone;
}
public void setSphone(String sphone) {
this.sphone = sphone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getSgender() {
return sgender;
}
public void setSgender(String sgender) {
this.sgender = sgender;
}
public String getSage() {
return sage;
}
public void setSage(String sage) {
this.sage = sage;
}
public Parents getParents() {
return parents;
}
public void setParents(Parents parents) {
this.parents = parents;
}
@Override
public String toString() {
return "Childs{" +
"id=" + id +
", sname='" + sname + '\'' +
", sgender='" + sgender + '\'' +
", sage='" + sage + '\'' +
", parents=" + parents +
'}';
}
}
原生的数据库操作,都需要继承SQLiteOpenHelper,而ormlite我们则需要继承OrmLiteSqliteOpenHelper
package com.liuw.ormlite.dao;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.Environment;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import com.liuw.ormlite.bean.Childs;
import com.liuw.ormlite.bean.Courses;
import com.liuw.ormlite.bean.Parents;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final String TABLE_NAME = "ormlite_test.db";//默认是在data/data/包名/databases/路径下
public static final String DATABASE_PATH = Environment.getExternalStorageDirectory() + "/liuw/" + TABLE_NAME;//指定路径
private static final int DB_VERSION = 3;
private Map daos = new HashMap();
private DatabaseHelper(Context context) {
super(context, DATABASE_PATH, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase database,
ConnectionSource connectionSource) {
try {
TableUtils.createTableIfNotExists(connectionSource, Childs.class);
TableUtils.createTableIfNotExists(connectionSource, Courses.class);
TableUtils.createTableIfNotExists(connectionSource, Parents.class);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase database,
ConnectionSource connectionSource, int oldVersion, int newVersion) {
//整表删除创建
// try {
// TableUtils.dropTable(connectionSource, Childs.class, true);
// TableUtils.dropTable(connectionSource, Courses.class, true);
// TableUtils.dropTable(connectionSource, Parents.class, true);
// onCreate(database, connectionSource);
// } catch (SQLException e) {
// e.printStackTrace();
// }
//更新数据库时只需添加新增字段
if (newVersion == 3) {
//数据库、表名、列名、类型
DatabaseUtil.updateColumn(database, "tab_child", "s_phone", "VARCHAR", null);
}
}
private static DatabaseHelper instance;
/**
* 单例获取该Helper
*
* @param context
* @return
*/
public static synchronized DatabaseHelper getHelper(Context context) {
context = context.getApplicationContext();
if (instance == null) {
synchronized (DatabaseHelper.class) {
if (instance == null)
instance = new DatabaseHelper(context);
}
}
return instance;
}
public synchronized Dao getDao(Class clazz) throws SQLException {
Dao dao = null;
String className = clazz.getSimpleName();
if (daos.containsKey(className)) {
dao = daos.get(className);
}
if (dao == null) {
dao = super.getDao(clazz);
daos.put(className, dao);
}
return dao;
}
/**
* 释放资源
*/
@Override
public void close() {
super.close();
for (String key : daos.keySet()) {
Dao dao = daos.get(key);
dao = null;
}
}
}
这里详细就不做介绍了,onCreate创建表,onUpgrade更新表,网上教程大多都是采用删除再创建的方式更新,这里我们可以通过自定义的DatabaseUtil类来实现表结构的更新,其实内部就是一个添加列的原生SQL语句,代码如下:
package com.liuw.ormlite.dao;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class DatabaseUtil {
public static void updateColumn(SQLiteDatabase db, String tableName,
String columnName, String columnType, Object defaultField) {
try {
if (db != null) {
Cursor c = db.rawQuery("SELECT * from " + tableName
+ " limit 1 ", null);
boolean flag = false;
if (c != null) {
for (int i = 0; i < c.getColumnCount(); i++) {
if (columnName.equalsIgnoreCase(c.getColumnName(i))) {
flag = true;
break;
}
}
if (flag == false) {
String sql = "alter table " + tableName + " add "
+ columnName + " " + columnType + " default "
+ defaultField;
db.execSQL(sql);
}
c.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void deleteRecordsWithoutForeignKey(SQLiteDatabase db, String tableName){
if (db != null) {
String sql = "DELETE from " + tableName;
db.execSQL(sql);
}
}
}
这样做的好处是不用再整表删除、创建,从而提高了工作效率
我们可以将需要的增、删、改、查等方法都放在Dao里,便于操作使用
父类Dao
package com.liuw.ormlite.dao;
import android.content.Context;
import com.j256.ormlite.dao.Dao;
import com.liuw.ormlite.bean.Parents;
import java.sql.SQLException;
public class ParentDao {
private Dao parentDao;
private DatabaseHelper helper;
public ParentDao(Context contex) {
try {
helper = DatabaseHelper.getHelper(contex);
parentDao = helper.getDao(Parents.class);
if (parentDao == null) {
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 增
* @param parent
*/
public void addParent(Parents parent) {
try {
parentDao.create(parent);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
孩子类Dao
package com.liuw.ormlite.dao;
import android.content.Context;
import com.j256.ormlite.dao.Dao;
import com.liuw.ormlite.bean.Childs;
import com.liuw.ormlite.bean.Parents;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class ChildDao {
private Dao childDao;
private DatabaseHelper helper;
public ChildDao(Context contex) {
try {
helper = DatabaseHelper.getHelper(contex);
childDao = helper.getDao(Childs.class);
if (childDao == null) {
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 增
* @param child
*/
public void addChild(Childs child) {
try {
childDao.create(child);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 删(通过实体)
* @param child
*/
public void delChild(Childs child) {
try {
childDao.delete(child);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 删(通过id)
* @param id
*/
public void delChildById(Integer id) {
try {
childDao.deleteById(id);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 改
* @param child
*/
public void updateChild(Childs child) {
try {
childDao.update(child);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 查
* @return
*/
public List queryAllChild() {
ArrayList childs = null;
try {
childs = (ArrayList) childDao.queryForAll();
} catch (SQLException e) {
e.printStackTrace();
}
return childs;
}
/**
* 获取user
* @param id child编号
* @return
*/
public Childs getChild(Integer id) {
try {
//父母信息为空
return childDao.queryForId(id);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
/**
* 获取user
* @param id child编号
* @return
*/
public Childs getChildAndParent(Integer id) {
try {
//父母信息有值,此处的refresh也可通过在数据中添加foreignAutoRefresh = true来实现
Childs child = childDao.queryForId(id);
helper.getDao(Parents.class).refresh(child.getParents());
return child;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
/**
* 获取user
* @param name child姓名
* @return
*/
public List getChildByName(String name) {
try {
List childs = childDao.queryBuilder().where().eq("s_name", name).query();
return childs;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
}
测试之前不要忘了加读写权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
package com.liuw.ormlite;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.liuw.ormlite.bean.Childs;
import com.liuw.ormlite.bean.Parents;
import com.liuw.ormlite.dao.ParentDao;
import com.liuw.ormlite.dao.ChildDao;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
private void initData() {
ParentDao parentDao = new ParentDao(getApplicationContext());
ChildDao childDao = new ChildDao(getApplicationContext());
Parents p1 = new Parents("001", "曹建华", "于晓红");
parentDao.addParent(p1);
Childs s1 = new Childs("猪小明", "男", "15");
s1.setParents(p1);
childDao.addChild(s1);
Parents p2 = new Parents("002", "余正华", "谋女郎");
parentDao.addParent(p2);
Childs s2 = new Childs("闰土", "男", "20");
s2.setParents(p2);
childDao.addChild(s2);
//id自增长默认从1开始
Childs student1 = childDao.getChild(1);
if (student1 != null) {
//结果:Childs{id=1, sname='猪小明', sgender='男', sage='15', parents=Parents{id=1,fid='null' fname='null', mname='null'}}
Log.i("liuw", student1.toString());
}
Childs student2 = childDao.getChildAndParent(2);
if (student2 != null) {
//结果:Childs{id=2, sname='闰土', sgender='男', sage='20', parents=Parents{id=2,fid='002' fname='余正华', mname='谋女郎'}}
Log.i("liuw", student2.toString());
}
List students = childDao.getChildByName("闰土");
if (students != null && students.size() > 0) {
Log.i("liuw", "数据大小为:"+students.size());
}
}
}
注意上面的两个结果的区别,具体可以看下两个方法,可以手动刷新,也可以直接在数据库的表里添加foreignAutoRefresh = true来实现;
本来是准备写一篇多表、多条件之间查询的,不过模拟数据添加起来有点麻烦,这里先介绍两篇文章做参考吧
复杂条件查询
ormlite参数及方法介绍