Xutils框架中关于DbUtils的使用

来源:互联网 发布:中国新歌声有网络直播 编辑:程序博客网 时间:2024/06/05 06:37

  在安卓开发中,常用的数据存储方式无外乎网络存储、内存存储、file存储,而网络存储必须依赖网络,内存存储在app关闭后则荡然无存,为了更好的应对需求,持久化数据,此时我们只能选择file存储,而file存储一般形式为xml首选项(SharedPreferences)、sqlite数据库以及其他file形式。xml首选项以xml标签形式持久化数据,解析时使用pull解析,意味着过大的首选项文件将影响解析速度,键值对的形式也存在管理不便的缺点。所以,当所保存的数据结构过于复杂,且需要更加精细的管理以及更快的速度,安卓中对此类数据使用sqlite数据库则更加适宜。

  sqlite数据库与常见的mysql,orcale数据库大致无异,因为更加轻量级所以被Android和ios等web应用选作默认的数据库形式。

  sqlite支持大部分的sql语言,android为我们提供了SQLiteDatabase这个类来进行sqlite数据库的操作,并且提供了一些相对简单的增删改查api(底层依旧是对sql语句的封装),但对于很多数据库基础薄弱的同学,尤其在java语境中,sql语句的拼装要加入各种转义符的情况下,一张表的复杂结构会对sqlite的使用产生畏惧感。所以,一些第三方的ORM(关系映射)开源框架就此诞生,如xutils中的DbUtils,GreenDao等。

  ORM更加实际点解释其实就是直接将数据库中的数据转为java中的对象,让Android开发人员不在为复杂的sql查询,数据封装而生无可恋。

  下面我们以Xutils快速开发框架中的DButils来对此类ORM框架进行一次简单的使用,其他ORM框架大同小异。

  DButils使用注解的方式来更快的让开发人员来对表的结构进行建立,当然我们得首先有个数据库。

 数据库的建立

public static DbUtils getDb(Activity activity) {        if (db == null) {            MyApplication application = (MyApplication) activity.getApplication();            db = DbUtils.create(activity, application.getPath(), "RunWold.db");        }        return db;    }
  这是开发者自己封装的单例类,DbUtils的核心类是DbUtils,执行DbUtils.create()方法后,当数据库已经存在,则直接返回此数据库对应的DbUtils,如果不存在则会去创建一个sqlite数据库,再返回DbUtils,注意数据库的创建需要读写权限。

  当获得指定名字的DbUtils之后,我们就可以对此数据库进行数据库操作,首先我们需要建数据库表,而表结构在Android开发中大部分直接参照Bean结构来进行创建,DbUtils的注解形式可以让我们对Bean中的对象名,类名直接进行注解,然后调用save()方法就直接生成了与这个Bean相同结构的表,而通过查询方法之后,所返回直接就是这个Bean对象,这就是ORM的简便之处。

 数据库表结构的建立

 @Table(name = "cases")        public static class DatasBean {                   @Column(column = "before")            private String before;            @Column(column = "after")            private String after;            @Id            @NotNull            private String casesId;            @Column(column = "introduction")            private String introduction;            @Column(column = "createDate")            private String createDate;            @Transient            private List<Integer> expertId;            @Transient            private List<String> name;            @Transient            private List<String> photo;
  我们在类名上面注明@Table注解并填写名称(当然后面还能添加更多的属性,如索引),这就表明这将在数据库中是一张表。

  在变量上面定义@Column并填写名称,这就表明这是这张表的一个列,列的数据类型直接就是你定义的变量的数据类型,如Int string(text)等(当然,只能是基本数据类型)。

  在casesId上面定义一个@Id标签,表明这是主键,主键应当保持唯一性,如果你的Bean结构中没有这种唯一性的数据,可以自己随意定义一个int类型的变量并赋予@Id的注解,这个@id的存在是必须的。

  @Transient表示忽略,这个变量不参与表的结构,在这里,我们可以看到忽略的都是一些list集合,数据库是不支持数组的,这在下面我们会解决这个问题。

 还有其他注解,包括主键的自增自减,各种约束类型等,在这里有更加详细的解释,其实也不多。

 还有一个要注意的问题,这些你即将创建表的Bean必须含有空的构造函数,其他get()、set()方法与平常无异。

  到了这里,我们对数据库结构进行了设计,其实这一部分一般都是数据库的重点操作需要很大一串的Sql语句,但是可以看到ORM框架直接方便了很多,那么下面我们就开始继续数据库的主要功能,增删改查。

  当我们有了一个Bean的对象,也拥有了一个Dbutils对象之后,我们就可以对数据库进行操作了。

  
 

   public void  refreshDatas(List<MainBean.DataBean.DatasBean> datas) throws DbException {     dbUtils.save(datas.get(0));//保存一个对象,但不会给主键赋值        dbUtils.saveAll(datas);//保存一个集合,但不会给主键赋值        dbUtils.saveBindingId(datas.get(0));//保存一个对象,会给你@Id的那个主键进行赋值        dbUtils.saveBindingIdAll(datas);//保存一个集合,会给你@id的那个主键进行赋值也就是casesID }


  可以看到dbutils可以对数据集合一次性的进行的保存,当然保存的对象必须是你定义的表的那个对象,这里有两种情况一种是不给主键赋值,另一种反之,这里要注意,不给主键赋值就必须要求表中有一个自增或自检的主键(如上文提到的自定义的id变量),如果你的bean结构中有@id的属性,那么就选择saveBindId(),此时主键的值就是bean对象中的值(当然上文提过,@id的主键变量你必须确定是唯一的)
 当调用save方法后如果不存在表则会先创建表然后再写入数据,如果存在表则会直接在表中写入数据,不需要单独调用cretable()方法。
 

  
 

public void  refreshDatas(List<MainBean.DataBean.DatasBean> datas) throws DbException {   dbUtils.delete(datas.get(0));        /**         * 基于where条件的查询,第一个参数为你想要在那个表(也就是Bean)进行操作,第二个参数为where子语句         * where子语句在sql作为查询规范来应用,也就是你想要删除什么样的数据         * WhereBuilder.b()封装了where语句,第一个参数以什么列名进行对比,第二个是对比符号比如“=”、“<”、“>"         * 第三个就是你拿来对比的值 这句话的意思就是删除一个casesId为2的列。         */        dbUtils.delete(MainBean.DataBean.DatasBean.class,WhereBuilder.b("casesId","=","2"));        dbUtils.deleteById(MainBean.DataBean.DatasBean.class,datas.get(0).getCasesId());        dbUtils.deleteAll(MainBean.DataBean.DatasBean.class);



   删操作同样很简便,基于对象的删除,直接删除这个对象所对应的数据库数据,基于where查询删除 ,删除一个集合或者整个表中的数据都删除。


   改
  

 dbUtils.update(datas.get(0),"before");        /**         * 此语句同理 where为查询标准,也就是把casesid=2的这条数据中的befroe值         * 改为第一个参数对象中对应的变量值         */        dbUtils.update(datas.get(0),WhereBuilder.b("casesId","=","2"),"before");                dbUtils.updateAll(datas,"before");
  改同上


 

 //查询该表所有数据        dbUtils.findAll(MainBean.DataBean.DatasBean.class);        /**         * 基于selector查询 select是sql语句中的查询语句 sql语句中的查询一般结构为select-from-where         * 所以这里其实跟sql结构一样 from表示从什么表中查询 where为查询规范         * 这里就是从表中查出所有casesId为2的值(当然 因为casesId唯一性 只会有一条数据)         */        dbUtils.findAll(Selector.from(MainBean.DataBean.DatasBean.class).where("casesId","=","2"));        //查询一个主键值为2的列        dbUtils.findById(MainBean.DataBean.DatasBean.class,"2");        //查询此表中第一条数据        dbUtils.findFirst(MainBean.DataBean.DatasBean.class);        //查询此表中符合条件的第一条数据        dbUtils.findFirst(Selector.from(MainBean.DataBean.DatasBean.class).where("casesId","=", "2"));


 到这里,增删改查的基本操作已经讲解完毕,如果能熟练运用这些,一些简单的需求已经可以顺利完成,比如以userId为主键的头像保存,这样每次用户列表的头像就不需要频繁进行网络访问了,当用户通知头像改变后更新数据就可。

 进阶

 在上面的注解介绍中,我们忽略了一些List<String>集合,因为数据库是不支持数组保存的,那么如何解决这个问题?
  其实方法有很多种,也是一般数据库操作人员保存数组的几种处理方式。
 1.如果 泛型中是基本数据类型,如String,int可以使用字符串拼接,并用间隔号隔开。
 2.如果泛型中是别的对象,可以序列化成json字符串进行保存。
 3.使用关联表,这也是最正规也是最具Geek范儿的方式(虽然过程较为繁琐一点)。

在1,2两种方法中,我们需要修改bean的结构,比如当你List<String> photo和name<String> name被忽略,如果你想在表中存在这两个string类型的列,就得在bean中定两个string常量用来当作列名。
   

    @Transient            private List<String> name;            @Transient            private List<String> photo;                        @Column(column = "photo")            private String photoDb;                        @Column(column = "photo")            private String nameDb;            /**             * 手动设置的两个变量无法被fastJson或者Gson解析 所以当你获得数据之后 还需要在p层或者m层             * 手动调用这些set或者get方法              * 比如当你从数据库中取得一个本类对象之后 list<String> photo其实是空的 photoDb是有数据的             * 需要在数据处理层中将photoDb数据反序列化再设置到这个对象中              * @return             */            public String getPhotoDb() {                return photoDb;            }            /**             *              * @param photoDb 你在外部进行拼接或者序列化之后的string字符串             */            public void setPhotoDb(String photoDb) {                this.photoDb = photoDb;            }            public String getNameDb() {                return nameDb;            }


 拼接字符串或者序列化从过程到思想都是比较简单的,但总给人感觉一种不规范之感,所以我们运用数据库设计中的关联表的思想去处理这些数组数据。
 所谓关联表就是一张表与另一张表存在着某种关联关系(废话),具体到这个案例就是,我们需要建立另外三张表,photo表,name表,expertId表,简单理解就是你忽略了多少list集合就有几张表(当然作为app的数据来说,不是每个变量都需要进行本地持久化),既然要建表我们就需要新建Bean,例如list<String> photo
@Table(name = "photo")        public static class Photo {            @Id            @NotNull            private int id;            @Column(column = "casesId")            private String casesId;            @Column(column = "photo")            private String photo;            public Photo() {            }            public int getId() {                return id;            }            public void setId(int id) {                this.id = id;            }            public String getPhoto() {                return photo;            }            public void setPhoto(String photo) {                this.photo = photo;            }            public String getCasesId() {                return casesId;            }            public void setCasesId(String casesId) {                this.casesId = casesId;            }            public String getPhtoto() {                return photo;            }            public void setPhtoto(String photo) {                this.photo = photo;            }        }


好了,在这个表中我们可以看到一个String类型的photo列 String类型casesId列 一个自定义的int id列,其中我们所谓的关联关系就是这个casesId,简单说来我们可以通过上一张表中的casesId查到这一层有关所有这个casesId的photo,而为什么我们不把casesId定为这个表的主键(@id)呢,因为这个表中的casesId会存在多个,一个photo就会有一个列,但这个列中casesId并不唯一。
当我们建立好这个表之后,我们还是在上一个Bean中写出调用DbUtils增删改查数据的方法。
  
 public void setDbPhoto(DbUtils dbUtils) throws DbException {                //遍历集合将数据保存在数据库                List<Photo> photos =new ArrayList<>();                for (String s : photo) {                    Photo photo = new Photo();                    photo.setCasesId(casesId);                    photo.setPhtoto(s);                    photos.add(photo);                }                dbUtils.saveAll(photos);            }              public List<String> getDbPhoto(DbUtils dbUtils) throws DbException {List<DbModel> dbModelAll = dbUtils.findDbModelAll(Selector.from(Photo.class)  .where("casesId", "=",casesId)  .select("photo"));                for (DbModel dbModel : dbModelAll) {                    String photoData = dbModel.getString("photo");                    this.photo.add(photoData);                }                return photo;            };        }


好了这就是关联表的设计,到这里Dbutils差不多基本讲解完毕,还有一些其他api比如判断表存不存在之类的,这里不做深入的介绍。
纵观整个DbUtils,包括同类型的GreenDao,其实在安卓中数据库的使用与其他平台中数据库应用并无二致,增删改查的api无非是为了简化数据库的操作难度,真正的数据库设计思想并不是一个框架就能提供的。
编程语言千变万化,唯有思想万古留存,GG。

1 0
原创粉丝点击