zoukankan      html  css  js  c++  java
  • Android--数据持久化之SQLite

    前言

      对于一个应用程序而言,数据持久化是必不可少的,Android程序也不例外。这篇博客将介绍Android中关于SQLite的使用,SQLite是一种嵌入式的数据库引擎,专门适用于资源有限的设备上进行适量的数据存储,而Android就全面支持标准的SQLite数据库。在本片博客中,将说明SQLite数据库的创建以及维护,还有使用SQLite执行CRUD的两种方式,以及SQLite中事务的使用,最后都会使用示例讲解博客中所提到的概念性的内容。

    SQLite

      Android对SQLite数据库,提供了完全的支持,而所有创建的SQLite数据库,仅限于当前应用访问,如果其他应用需要访问,则必须提供的Content Provider的支持,并且SQLite数据库会随着Android应用的卸载而被删除。SQLite是一个嵌入式的数据库引擎,最后是以文件的形式保存数据的。从本质上来看,SQLite的操作方式只是一种更为便捷的文件操作,当应用程序创建或打开一个SQLite数据库时,其实只是打开一个文件准备读写。因为SQLite仅适用于资源有限的小型设备,所以本身就不应该把大量数据存储在设备的SQLite数据库里,SQLite只适合存储一些小型的数据。

       为了使SQLite和其他数据库间的兼容性最大化,SQLite支持对列上类型进行“类型近似”,列的类型近似指的是存储在列上的数据进行推荐类型存储。所以虽然SQLite内部只支持NULL、INTEGER、REAL(浮点书)、TEXT(文本)和BLOB(大二进制对象)这五种数据类型,但实际上SQLite完全可以接受varchar(n)、char(n)、decimal(p,s)、date等类型数据,只不过SQLite会在运算或保存时将它们转换为上面五种数据类型中相应的类型。大多数数据库的引擎都是使用静态的、强类型的数据类型,数据的类型是由它的容器决定的,这个容器是指被存放的特定列。而SQLite使用的是动态类型,在SQLite中,值的数据类型跟值本身相关,而不是与它的容器相关,所以SQLite允许把各种类型的数据保存到任何类型字段中,开发者可以不用关心声明该字段说使用的数据类型。但是有一种情况例外,定义为INTEGER PRIMARY KEY的字段只能存储64位整数,当向这种字段保存除整数意外的其他类型的数据时,SQLite会产生错误。

    SQLite数据库创建与维护

      从官方文档上了解到,在Android项目中,创建SQLite数据库推荐继承SQLiteOpenHelper类,然后重写其中的onCreate()方法,在onCreate()方法中,对执行数据库创建的SQL语句。而SQLiteOpenHelper不仅仅用于SQLite数据的创建,还可以对其进行维护,以及获得SQLiteDatabase这个数据库操作对象。

      SQLiteOpenHelper提供了两个构造器,用于传递当前上下文对象以及SQLite数据库版本信息,在SQLiteOpenHelper的继承类的构造函数中,会调用它,构造器的签名如下:

    • SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version).
    • SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactroy factory,int version,DatabaseErrorHandler errorHandler).

      上面的构造函数中,都是用于创建一个SQLite数据库,context为一个当前应用的上下文对象;name是数据库名称;factory是一个允许子类在查询时使用的游标,一般不用传Null;version是数据库版本号;errorHandler是一个接口,传递当数据库错误的时候,执行的补救方法。

      在SQLiteOpenHelper中,可以进行SQLite数据库的创建、维护、日志以及获取可读写的数据库对象,通过下面几个常用方法得到支持:

    • String getDatabaseName():获取数据库名。
    • SQLiteDatabase getReadableDatabase():创建或者打开一个可读的数据库对象。
    • SQLiteDatabase getWritableDatabase():创建或者打开一个可读/写的数据库对象。
    • abstract void onCreate(SQLiteDatabase db):当第一次调用SQLiteOpenHelper的时候执行,之后再次调用将不再执行,一般用于完成数据库初始化的工作。
    • void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion):当数据库版本号发生向上更新时,被执行。
    • void onDowngrade(SQLiteDatabase db,int oldVersion,int newVersion):当数据库版本号发生向下更新时,被执行。

      下面提供一个简单的SQLiteOpenHelper的继承类代码,用于创建数据库以及表结构:

     1 package com.example.sqlitedbdemo.db;
     2 
     3 import android.content.Context;
     4 import android.database.sqlite.SQLiteDatabase;
     5 import android.database.sqlite.SQLiteOpenHelper;
     6 
     7 public class DbOpenHelper extends SQLiteOpenHelper {
     8     private static String name = "mydb.db";
     9     private static int version = 1;
    10 
    11     public DbOpenHelper(Context context) {
    12         super(context, name, null, version);
    13     }
    14 
    15     @Override
    16     public void onCreate(SQLiteDatabase db) {
    17         // 只能支持基本数据类型
    18         String sql = "create table person(id integer primary key autoincrement,name varchar(64),address varchar(64))";
    19         db.execSQL(sql);
    20     }
    21     @Override
    22     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    23         // TODO Auto-generated method stub
    24         String sql="alter table person add sex varchar(8)";
    25         db.execSQL(sql);
    26     }
    27 }

       Tips:当创建好SQLite数据库的之后,可以在/data/data/<package name>/databases目录下找到SQLite数据库文件。

    执行CRUD操作

      当使用SQLiteOpenHelper的getReadableDatabase()或者getWritableDatabase()方法获取到SQLiteDatabase对象,就可以对这个数据库进行操作了。

      对于熟悉SQL语句的开发者而言,其实只需要使用两个方法,即可执行所有CRUD操作,以下方法提供多个重载方法:

    • void execSQL():通过SQL语句执行一条非查询语句。
    • Cursor rawQuery():通过SQL语句执行一条查询语句。

      下面以一个示例讲解一下单纯使用SQL语句实现CRUD操作:

      接口代码:

     1 package com.examle.sqlitedbdemo.service;
     2 
     3 import java.util.List;
     4 import java.util.Map;
     5 
     6 public interface PersonService {
     7 
     8     public boolean addPerson(Object[] params);
     9     public boolean deletePerson(Object[] params);
    10     public boolean updatePerson(Object[] params);
    11     public Map<String, String> viewPerson(String[] selectionArgs);
    12     public List<Map<String, String>> listPersonMaps(String[] selectionArgs);
    13 }

      接口的实现代码:

      1 package com.examle.sqlitedbdemo.dao;
      2 
      3 import java.util.ArrayList;
      4 import java.util.HashMap;
      5 import java.util.List;
      6 import java.util.Map;
      7 
      8 import android.content.Context;
      9 import android.database.Cursor;
     10 import android.database.sqlite.SQLiteDatabase;
     11 
     12 import com.examle.sqlitedbdemo.service.PersonService;
     13 import com.example.sqlitedbdemo.db.DbOpenHelper;
     14 
     15 public class PersonDao implements PersonService {
     16     private DbOpenHelper helper = null;
     17 
     18     public PersonDao(Context context) {
     19         helper = new DbOpenHelper(context);
     20     }
     21 
     22     @Override
     23     public boolean addPerson(Object[] params) {
     24         boolean flag = false;
     25         SQLiteDatabase database = null;
     26         try {
     27             // insert一条数据
     28             String sql = "insert into person(name,address,sex) values(?,?,?)";
     29             database = helper.getWritableDatabase();
     30             // 执行SQL
     31             database.execSQL(sql, params);
     32             flag = true;
     33         } catch (Exception e) {
     34             e.printStackTrace();
     35         } finally {
     36             if (database != null) {
     37                 // finally中关闭数据库
     38                 database.close();
     39             }
     40         }
     41         return flag;
     42     }
     43 
     44     @Override
     45     public boolean deletePerson(Object[] params) {
     46         boolean flag = false;
     47         SQLiteDatabase database = null;
     48         try {
     49             // 删除一条数据
     50             String sql = "delete from person where id=?";
     51             database = helper.getWritableDatabase();
     52             database.execSQL(sql, params);
     53             flag = true;
     54         } catch (Exception e) {
     55             e.printStackTrace();
     56         } finally {
     57             if (database != null) {
     58                 database.close();
     59             }
     60         }
     61         return flag;
     62     }
     63 
     64     @Override
     65     public boolean updatePerson(Object[] params) {
     66         boolean flag = false;
     67         SQLiteDatabase database = null;
     68         try {
     69             // 更新一条数据
     70             String sql = "update person set name=?,address=?,sex=? where id=?";
     71             database = helper.getWritableDatabase();
     72             // 执行SQL
     73             database.execSQL(sql, params);
     74             flag = true;
     75         } catch (Exception e) {
     76             e.printStackTrace();
     77         } finally {
     78             if (database != null) {
     79                 database.close();
     80             }
     81         }
     82         return flag;
     83     }
     84 
     85     @Override
     86     public Map<String, String> viewPerson(String[] selectionArgs) {
     87         Map<String, String> map = new HashMap<String, String>();
     88         SQLiteDatabase database = null;
     89         try {
     90             // 查询单条记录
     91             String sql = "select * from person where id=?";
     92             // 以只读的形式打开数据库
     93             database = helper.getReadableDatabase();
     94             // 执行SQL语句,返回一个游标
     95             Cursor cursor = database.rawQuery(sql, selectionArgs);
     96 
     97             int colums = cursor.getColumnCount();
     98             while (cursor.moveToNext()) {
     99                 for (int i = 0; i < colums; i++) {
    100                     String cols_name = cursor.getColumnName(i);
    101                     String cols_value = cursor.getString(cursor
    102                             .getColumnIndex(cols_name));
    103                     if (cols_value == null) {
    104                         cols_value = "";
    105                     }
    106                     map.put(cols_name, cols_value);
    107                 }
    108             }
    109         } catch (Exception e) {
    110             e.printStackTrace();
    111         } finally {
    112             if (database != null) {
    113                 database.close();
    114             }
    115         }
    116         return map;
    117     }
    118 
    119     @Override
    120     public List<Map<String, String>> listPersonMaps(String[] selectionArgs) {
    121         List<Map<String, String>> list = new ArrayList<Map<String, String>>();
    122         String sql = "select * from person";
    123         SQLiteDatabase database = null;
    124         try {
    125             database = helper.getReadableDatabase();
    126             Cursor cursor = database.rawQuery(sql, selectionArgs);
    127             int colums = cursor.getColumnCount();
    128             while (cursor.moveToNext()) {
    129                 Map<String, String> map = new HashMap<String, String>();
    130                 for (int i = 0; i < colums; i++) {
    131                     String cols_name = cursor.getColumnName(i);
    132                     String cols_value = cursor.getString(cursor
    133                             .getColumnIndex(cols_name));
    134                     if (cols_value == null) {
    135                         cols_value = "";
    136                     }
    137                     map.put(cols_name, cols_value);
    138                 }
    139                 list.add(map);
    140             }
    141         } catch (Exception e) {
    142             e.printStackTrace();
    143         } finally {
    144             if (database != null) {
    145                 database.close();
    146             }
    147         }
    148         return list;
    149     }
    150 }

       再写一个测试类测试这个数据操作类是否有效,Android下JUnit的配置参见另外一篇博客:Android--JUnit单元测试

     1 package com.example.sqlitedbdemo.db;
     2 
     3 import java.util.List;
     4 import java.util.Map;
     5 
     6 import com.examle.sqlitedbdemo.dao.PersonDao;
     7 import com.examle.sqlitedbdemo.service.PersonService;
     8 
     9 import android.test.AndroidTestCase;
    10 import android.util.Log;
    11 
    12 public class TestDb extends AndroidTestCase {
    13     private final String TAG = "main";
    14 
    15     public TestDb() {
    16         // TODO Auto-generated constructor stub
    17     }
    18 
    19     public void createDB() {
    20         DbOpenHelper helper = new DbOpenHelper(getContext());
    21         helper.getWritableDatabase();
    22     }
    23 
    24     public void insertDb() {
    25         PersonService service = new PersonDao(getContext());
    26         Object[] params1 = { "张龙", "beijing", "male" };
    27         boolean flag = service.addPerson(params1);
    28         Object[] params2 = { "赵虎", "shanghai", "male" };
    29         flag = flag&&service.addPerson(params2);
    30         Object[] params3 = { "王朝", "HK", "male" };
    31         flag = flag&&service.addPerson(params3);
    32         Object[] params4 = { "马汉", "beijing", "female" };
    33         flag = flag&&service.addPerson(params4);
    34         Log.i(TAG, "-----插入数据----->>" + flag);
    35     }
    36 
    37     public void deleteDb() {
    38         PersonService service = new PersonDao(getContext());
    39         Object[] params = { 1 };
    40         boolean flag = service.deletePerson(params);
    41         Log.i(TAG, "-----删除数据----->>" + flag);
    42     }
    43 
    44     public void updateDb() {
    45         PersonService service=new PersonDao(getContext());
    46         Object[] params = { "张三", "上海", "男","2" };
    47         boolean flag=service.updatePerson(params);
    48         Log.i(TAG, "---------->>" + flag);
    49     }
    50     
    51     public void getDb(){
    52         PersonService service=new PersonDao(getContext());
    53         Map<String, String> map = service.viewPerson(new String[]{"2"});
    54         Log.i(TAG, "---------->>" + map.toString());
    55     }
    56     
    57     public void listDb() {
    58         PersonService service = new PersonDao(getContext());
    59         List<Map<String, String>> list = service.listPersonMaps(null);
    60         Log.i(TAG, "---------->>" + list.toString());
    61     }
    62 }

      insertDB()后,如果是在模拟器上调试,可以使用FIle Explorer工具导出mydb.db文件,使用SQLite Expert Professional(这是一个SQLite的管理软件,博客最后提供下载地址),打开数据库:

      执行deleteDb()删除第一条数据:

      执行updateDb()更新第二条数据:

      执行getDb(),查询第二条数据,执行listDb(),查询全部数据,查看日志输出:

      

      而如果是从事Android开发,还有必要了解另外一种操作SQLite的方式,使用SQLiteDatabase所提供的方法实现CRUD操作。主要有以下几个方法:

    • long insert(String table ,String nullColumnHack,ContentValues values):插入一条数据。
    • int delete(String table ,String whereCaluse,String[] whereArgs):根据条件,删除数据。
    • int updata(String table,ContentValues values,String whereCaluse,String[] whereArgs):根据条件,更新数据
    • Cursor query(...):根据条件,查询数据。提供多种重载方法,主要查询不同的条件。

      下面以一个示例程序讲解一下使用SQLiteDatabase所提供的方法实现CRUD操作:

      接口代码:

     1 package com.examle.sqlitedbdemo.service;
     2 
     3 import java.util.List;
     4 import java.util.Map;
     5 
     6 import android.content.ContentValues;
     7 
     8 public interface PersonService2 {
     9 
    10     public boolean addPerson(ContentValues values);
    11 
    12     public boolean deletePerson(String whereClause, String[] whereArgs);
    13 
    14     public boolean updatePerson(ContentValues values, String whereClause,
    15             String[] whereArgs);
    16 
    17     public Map<String, String> viewPerson(String selection,
    18             String[] selectionArgs);
    19 
    20     public List<Map<String, String>> listPersonMaps(String selection,
    21             String[] selectionArgs);
    22 }

      实现代码:

      1 package com.examle.sqlitedbdemo.dao;
      2 
      3 import java.util.ArrayList;
      4 import java.util.HashMap;
      5 import java.util.List;
      6 import java.util.Map;
      7 
      8 import android.content.ContentValues;
      9 import android.content.Context;
     10 import android.database.Cursor;
     11 import android.database.sqlite.SQLiteDatabase;
     12 
     13 import com.examle.sqlitedbdemo.service.PersonService2;
     14 import com.example.sqlitedbdemo.db.DbOpenHelper;
     15 
     16 public class PersonDao2 implements PersonService2 {
     17     private DbOpenHelper helper = null;
     18 
     19     public PersonDao2(Context context) {
     20         helper = new DbOpenHelper(context);
     21     }
     22 
     23     @Override
     24     public boolean addPerson(ContentValues values) {
     25         boolean flag = false;
     26         SQLiteDatabase database = null;
     27         long id = -1;
     28         try {
     29             database = helper.getWritableDatabase();
     30             // 执行insert,返回当前行ID
     31             id = database.insert("person", null, values);
     32             flag = (id != -1 ? true : false);
     33         } catch (Exception e) {
     34             e.printStackTrace();
     35         } finally {
     36             if (database != null) {
     37                 database.close();
     38             }
     39         }
     40         return flag;
     41     }
     42 
     43     @Override
     44     public boolean deletePerson(String whereClause, String[] whereArgs) {
     45         boolean flag = false;
     46         SQLiteDatabase database = null;
     47         int count = 0;
     48         try {
     49             database = helper.getWritableDatabase();
     50             // 执行删除操作,返回影响行数
     51             count = database.delete("person", whereClause, whereArgs);
     52             flag = (count > 0 ? true : false);
     53         } catch (Exception e) {
     54             e.printStackTrace();
     55         } finally {
     56             if (database != null) {
     57                 database.close();
     58             }
     59         }
     60         return flag;
     61     }
     62 
     63     @Override
     64     public boolean updatePerson(ContentValues values, String whereClause,
     65             String[] whereArgs) {
     66         boolean flag = false;
     67         SQLiteDatabase database = null;
     68         int count = 0;
     69         try {
     70             database = helper.getWritableDatabase();
     71             // 执行更新操作,返回影响行数
     72             count = database.update("person", values, whereClause, whereArgs);
     73             flag = (count > 0 ? true : false);
     74         } catch (Exception e) {
     75             e.printStackTrace();
     76         } finally {
     77             if (database != null) {
     78                 database.close();
     79             }
     80         }
     81         return flag;
     82     }
     83 
     84     @Override
     85     public Map<String, String> viewPerson(String selection,
     86             String[] selectionArgs) {
     87         SQLiteDatabase database = null;
     88         Cursor cursor = null;
     89         Map<String, String> map = new HashMap<String, String>();
     90         try {
     91             database = helper.getReadableDatabase();
     92             // 设置查询条件
     93             cursor = database.query(true, "person", null, selection,
     94                     selectionArgs, null, null, null, null);
     95             int cols_len = cursor.getColumnCount();
     96             while (cursor.moveToNext()) {
     97                 for (int i = 0; i < cols_len; i++) {
     98                     String cols_key = cursor.getColumnName(i);
     99                     String cols_value = cursor.getString(cursor
    100                             .getColumnIndex(cols_key));
    101                     if (cols_value == null) {
    102                         cols_value = "";
    103                     }
    104                     map.put(cols_key, cols_value);
    105                 }
    106             }
    107         } catch (Exception e) {
    108             e.printStackTrace();
    109         }
    110         return map;
    111     }
    112 
    113     @Override
    114     public List<Map<String, String>> listPersonMaps(String selection,
    115             String[] selectionArgs) {
    116         List<Map<String, String>> list = new ArrayList<Map<String, String>>();
    117         SQLiteDatabase database = null;
    118         Cursor cursor = null;
    119         try {
    120             database = helper.getReadableDatabase();
    121             cursor = database.query(false, "person", null, selection,
    122                     selectionArgs, null, null, null, null);
    123             int cols_len = cursor.getColumnCount();
    124             while (cursor.moveToNext()) {
    125                 Map<String, String> map = new HashMap<String, String>();
    126                 for (int i = 0; i < cols_len; i++) {
    127                     String cols_key = cursor.getColumnName(i);
    128                     String cols_value = cursor.getString(cursor
    129                             .getColumnIndex(cols_key));
    130                     if (cols_value == null) {
    131                         cols_value = "";
    132                     }
    133                     map.put(cols_key, cols_value);
    134                 }
    135                 list.add(map);
    136             }
    137         } catch (Exception e) {
    138             e.printStackTrace();
    139         }
    140         return list;
    141     }
    142 
    143 }

      最后和上面一下,创建一个测试类来测试这个数据库操作:

     1 package com.example.sqlitedbdemo.db;
     2 
     3 import java.util.List;
     4 import java.util.Map;
     5 
     6 import com.examle.sqlitedbdemo.dao.PersonDao2;
     7 import com.examle.sqlitedbdemo.service.PersonService2;
     8 
     9 import android.content.ContentValues;
    10 import android.test.AndroidTestCase;
    11 import android.util.Log;
    12 
    13 public class TestDb2 extends AndroidTestCase {
    14     private final String TAG = "main";
    15 
    16     public TestDb2() {
    17         // TODO Auto-generated constructor stub
    18     }
    19 
    20     public void addPerson() {
    21         PersonService2 service2 = new PersonDao2(getContext());
    22         ContentValues values1 = new ContentValues();
    23         values1.put("name", "张龙");
    24         values1.put("address", "beijing");
    25         values1.put("sex", "male");
    26         boolean flag = service2.addPerson(values1);
    27         ContentValues values2 = new ContentValues();
    28         values2.put("name", "赵虎");
    29         values2.put("address", "shanghai");
    30         values2.put("sex", "male");
    31         flag = flag&&service2.addPerson(values2);
    32         ContentValues values3 = new ContentValues();
    33         values3.put("name", "王朝");
    34         values3.put("address", "HK");
    35         values3.put("sex", "male");
    36         flag = flag&&service2.addPerson(values3);
    37         ContentValues values4 = new ContentValues();
    38         values4.put("name", "王朝");
    39         values4.put("address", "HK");
    40         values4.put("sex", "male");
    41         flag = flag&&service2.addPerson(values4);
    42         Log.i(TAG, "----------->>" + flag);
    43     }
    44     
    45     public void deletePerson() {
    46         PersonService2 service2 = new PersonDao2(getContext());
    47         boolean flag = service2.deletePerson(" id =?", new String[]{"1"});
    48         Log.i(TAG, "----------->>" + flag);
    49     }
    50     
    51     public void updatePerson(){
    52         PersonService2 service2 = new PersonDao2(getContext());
    53         ContentValues values = new ContentValues();
    54         values.put("name", "张三"); 
    55         values.put("address", "上海");
    56         values.put("sex", "男");
    57         boolean flag=service2.updatePerson(values, " id=? ", new String[]{"2"});
    58         Log.i(TAG, "----------->>" + flag);
    59     }
    60     
    61     public void viewPerson(){
    62         PersonService2 service2 = new PersonDao2(getContext());
    63         Map<String, String> map=service2.viewPerson(" id=? ", new String[]{"2"});
    64         Log.i(TAG, "----------->>" + map.toString());
    65     }
    66     public void listPerson(){
    67         PersonService2 service2 = new PersonDao2(getContext());
    68         List<Map<String, String>> list=service2.listPersonMaps(null,null);
    69         Log.i(TAG, "----------->>" + list.toString());
    70     }
    71 }

      实现的功能和上面一样,这里就不展示效果图了,但是因为是上面两种操作数据库的方式是在一个应用中完成的,并且数据一样,执行第二个测试类的时候,需要把之前创建的数据库删除,详情参见源码。 

     SQLite事务

      SQLite的事务通过SQLiteDatabase中包含的两个方法对其进行控制:beginTransaction(),开始事务;endTransaction(),结束事务。除此之外,SQLiteDatabase还提供了一个inTransaction()方法用来判断当前上下文是否处于事务环境中。当程序执行endTransaction()方法时将会结束事务,到底是回滚事务还是提交事务取决于SQLiteDatabase是否调用了setTransactionSuccessful()方法来设置事务标志,如果程序事务执行中调用该方法设置了事务成功则提交事务,否则程序将回滚事务。

      示例源码下载

    总结

      上面就基本讲解了SQLite在Android中的时候,虽然有两种操作方式,并且直接使用SQL语句操作数据库对于熟悉SQL语句的开发者开说,是非常贴心的,但是在Android中,还是有必要了解一下使用SQLiteDatabase提供的方法操作数据库的方式,因为Android有一个内容提供者(Content Provider),可以使用外部应用访问内部应用的数据,它传递数据的形式,大部分是与SQLiteDatabase内置方法的参数一致的,所以如果同一使用SQLiteDatabase提供的方法操作数据库,是很方便的,无需额外转换SQL语句。

    SQLiteExpertSetup下载地址:part1part2

      请支持原创,尊重原创,转载请注明出处。谢谢。

  • 相关阅读:
    luoguP1871 对撞机【赛后第一题
    Deep learning-based personality recognition from text posts of online social networks 阅读笔记
    Who Am I? Personality Detection based on Deep Learning for Texts 阅读笔记
    RNN以及LSTM简介
    Compilation failed (return status=1): g++.exe: error: CreateProcess: No such file or directory错误
    Deep Learning-Based Document Modeling for Personality Detection from Text 阅读笔记
    NeuralCoref: python的共指消解工具教程
    NLTK库WordNet的使用方法实例
    matlab使用libsvm入门教程——使用matlab安装配置libsvm以及一个svm分类实例
    原型方法对软件生命周期不同阶段的支持
  • 原文地址:https://www.cnblogs.com/plokmju/p/android_SQLite.html
Copyright © 2011-2022 走看看