几个ORM框架的比较
先介绍一下ORM的概念,以前也一直听说,不过没详细了解啥意思。其全称叫做对象关系映射(Object Relation Mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的. 两者之间是不匹配的。而ORM作为项目中间件形式实现数据在不同场景下数据关系映射。对象关系映射是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。ORM就是这样而来的。几个Android下的ORM框架:ORMLite、greendao、ormndroid、androrm、ActiveAndroid下面对ORMLite和GreenDao做个简单的比较:
ormlite
基于注解和反射的的方式,导致ormlite性能有着一定的损失(注解其实也是利用了反射的原理)优点:文档较全面,社区活跃,有好的维护,使用简单,易上手。缺点:基于反射,效率较低
GreenDao官网中明确指明了其首要设计目标:
- Maximum performance (probably the fastest ORM for Android):性能最大化
- Easy to use APIs:便于使用
- Highly optimized for Android:对于Android高度优化
- Minimal memory consumption:最小化内存开销
- Small library size, focus on the essentials:较小的文件体积,只集中在必要的部分上
优点:效率很高,插入和更新的速度是sqlite的2倍,加载实体的速度是ormlite的4.5倍文件较小(<100K),占用更少的内存 ,但是需要create Dao操作实体灵活:支持get,update,delete等操作缺点:学习成本较高。其中使用了一个java工程根据一些属性和规则去generate一些基础代码,类似于javaBean,但会有一些规则,另外还有QueryBuilder、Dao等API,所以首先要明白整个过程,才能方便使用。没有ORMLite那样封装的完整,不过greenDao的官网上也提到了这一点,正是基于generator而不是反射,才使得其效率高的多。另外GreenDao支持Protocol buffers协议数据的直接存储 ,如果通过protobuf协议和服务器交互,不需要任何的映射。Protocol Buffers协议:以一种高效可扩展的对结构化数据进行编码的方式。google内部的RPC协议和文件格式大部分都是使用它。RPC:远程过程调用(Remote Procedure Call,RPC)是一个计算机通信协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
Activity
public class MainActivity extends ListActivity {private TextView tv_info;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);String[] array = { "添加一个用户", "获取一个用户的信息", "添加一篇文章", "获取一篇文章的信息", //"根据用户id获取此用户的全部文章", "方式二", };for (int i = 0; i < array.length; i++) {array[i] = i + "、" + array[i];}tv_info = new TextView(this);// 将内容显示在TextView中tv_info.setTextColor(Color.BLUE);tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);tv_info.setPadding(20, 10, 20, 10);getListView().addFooterView(tv_info);setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array))));}@Overrideprotected void onListItemClick(ListView l, View v, int position, long id) {int _id = new Random().nextInt(5);User user = null;Article article = null;switch (position) {case 0:user = new User();user.setName("包青天 " + new SimpleDateFormat("HH:mm:ss").format(new Date()));new UserDao(this).add(user);break;case 1:user = new UserDao(this).get(_id);if (user == null) tv_info.setText("不存在id=" + _id + "的用户");else tv_info.setText(user.toString());break;case 2:article = new Article();article.setTitle("ORMLite的使用 " + new SimpleDateFormat("HH_mm_ss").format(new Date()));article.setUser(new UserDao(this).get(_id));new ArticleDao(this).add(article);break;case 3:article = new ArticleDao(this).get(_id);if (article == null) tv_info.setText("不存在id=" + _id + "的文章");else tv_info.setText(article.toString());break;case 4:tv_info.setText("【用户id为 " + _id + " 的全部文章】");List<Article> articles = new ArticleDao(this).listByUserId(_id);if (articles != null) {for (Article article2 : articles) {tv_info.append("\n" + article2.toString());}}break;case 5:tv_info.setText("【用户id为 " + _id + " 的全部文章】");user = new UserDao(this).get(_id);if (user != null) {Collection<Article> articles3 = user.getArticles();if (articles3 != null) {for (Article article3 : articles3) {tv_info.append("\n" + article3.toString());}}}break;}}public void addStudent() {try {Dao dao = MyDatabaseHelper.getHelper(this).getDao(Student.class);BaseDaoEnabled<Student, Integer> student = new Student("学生");student.setDao(dao);student.create();} catch (SQLException e) {e.printStackTrace();}}}
DAO
/**对每个Bean创建一个Dao来处理当前Bean的数据库操作*/public class UserDao {private Dao<User, Integer> userDaoOpe;private MyDatabaseHelper helper;public UserDao(Context context) {try {helper = MyDatabaseHelper.getHelper(context);userDaoOpe = helper.getDao(User.class);//真正去和数据库打交道的对象,是通过getDao进行获取的} catch (SQLException e) {e.printStackTrace();}}/*** 增加一个用户*/public void add(User user) {try {userDaoOpe.create(user);} catch (SQLException e) {e.printStackTrace();}}/*** 获取一个用户,注意要判断是否获取到了指定id的用户*/public User get(int id) {try {return userDaoOpe.queryForId(id);} catch (SQLException e) {e.printStackTrace();}return null;}}
public class ArticleDao {private Dao<Article, Integer> articleDaoOpe;private MyDatabaseHelper helper;@SuppressWarnings("unchecked")public ArticleDao(Context context) {try {helper = MyDatabaseHelper.getHelper(context);articleDaoOpe = helper.getDao(Article.class);} catch (SQLException e) {e.printStackTrace();}}/*** 添加一个Article*/public void add(Article article) {try {articleDaoOpe.create(article);} catch (SQLException e) {e.printStackTrace();}}/*** 通过Id得到一个Article*/@SuppressWarnings("unchecked")public Article getArticleWithUser(int id) {Article article = null;try {article = articleDaoOpe.queryForId(id);if (article != null) helper.getDao(User.class).refresh(article.getUser());} catch (SQLException e) {e.printStackTrace();}return article;}/*** 通过Id得到一篇文章*/public Article get(int id) {Article article = null;try {article = articleDaoOpe.queryForId(id);} catch (SQLException e) {e.printStackTrace();}return article;}/*** 通过UserId获取所有的文章*/public List<Article> listByUserId(int userId) {try {return articleDaoOpe.queryBuilder().where().eq("user_id", userId).query();} catch (SQLException e) {e.printStackTrace();}return null;}}
Bean
@DatabaseTable(tableName = "tb_user")public class User {@DatabaseField(generatedId = true)private int id;//主键,id = true被注解对象就是主键;自增长的id,可以设置为generatedId = true来实现,当然还有很多其他的注解配置@DatabaseFieldprivate String name;@ForeignCollectionFieldprivate Collection<Article> articles;//一个作者有多个文章//******************************************************************************************public Collection<Article> getArticles() {return articles;}public void setArticles(Collection<Article> articles) {this.articles = articles;}public User() {}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "id=" + id + ", name=" + name;}}
@DatabaseTable(tableName = "tb_article")public class Article {//文章@DatabaseField(generatedId = true)private int id;@DatabaseFieldprivate String title;//文章的标题@DatabaseField(canBeNull = true, foreign = true, columnName = "user_id", foreignAutoRefresh = true)private User user;//作者。canBeNull= true 表示能为null;foreign=true表示是一个外键;columnName 列名//******************************************************************************************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 User getUser() {return user;}public void setUser(User user) {this.user = user;}@Overridepublic String toString() {return "id=" + id + ", title=" + title + "\n作者为 " + user;}}
@DatabaseTable(tableName = "tb_student")public class Student extends BaseDaoEnabled<Student, Integer> {@DatabaseField(generatedId = true)public int id;@DatabaseFieldpublic String name;public Student(String name) {this.name = name;}}
helper
public class MyDatabaseHelper extends OrmLiteSqliteOpenHelper {public static final String TABLE_NAME = "sqlite-test.db";private Map<String, Dao> daos = new HashMap<String, Dao>();//******************************************************************************************private static MyDatabaseHelper instance;//整个SqliteOpenHelper使用单例只对外公布出一个对象,保证只存在一个SQLite Connectionprivate MyDatabaseHelper(Context context) {super(context, TABLE_NAME, null, 4);}/*** 单例获取该Helper*/public static synchronized MyDatabaseHelper getHelper(Context context) {context = context.getApplicationContext();if (instance == null) {synchronized (MyDatabaseHelper.class) {if (instance == null) instance = new MyDatabaseHelper(context);}}return instance;}//******************************************************************************************@Overridepublic void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {try {TableUtils.createTable(connectionSource, User.class);TableUtils.createTable(connectionSource, Article.class);TableUtils.createTable(connectionSource, Student.class);} catch (SQLException e) {e.printStackTrace();}}@Overridepublic void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {try {TableUtils.dropTable(connectionSource, User.class, true);TableUtils.dropTable(connectionSource, Article.class, true);TableUtils.dropTable(connectionSource, Student.class, true);onCreate(database, connectionSource);} catch (SQLException e) {e.printStackTrace();}}/**getDao为一个泛型方法,会根据传入Class对象进行创建Dao,并且使用一个Map来保持所有的Dao对象,只有第一次调用时才会去调用底层的getDao()。*/@Overridepublic 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;}/*** 释放资源*/@Overridepublic void close() {super.close();for (String key : daos.keySet()) {Dao dao = daos.get(key);dao = null;}}}