buildscript {
repositories {
google()
jcenter()
mavenCentral()//greendao的配置仓库
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'//greendao需要的插件
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
在Module app的build.gradle中配置
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'//应用greendao的插件
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.view.pro20180226"
minSdkVersion 17
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//配置greendao的自动生成操作类的路径,默认是build文件下,可以自己指定
greendao {
schemaVersion 1//数据库版本号
daoPackage 'com.view.pro20180226.greenDao'//设置DaoMaster、DaoSession、Dao包名
targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
//greendao的依赖库
compile 'org.greenrobot:greendao:3.2.2'
}
到此配置就完成了
package com.view.pro20180226.greenDao;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Generated;
/**
* Entity标识当前实体类为一个表,greendao插件会对此标识的实体类进行操作类生成
*
* @Entity( schema:告知GreenDao当前实体属于哪个schema
* active:标记一个实体处于活跃状态,活动实体有更新、删除和刷新方法
* nameInDb:在数据库中使用的别名,默认使用的是实体的类名
* indexes:定义索引,可以跨越多个列
* createInDb:标记创建数据库表
* )
* @Id:主键 Long 型,其他类型会报错,可以通过@Id(autoincrement = true)设置自增长,不然会使用旧值
* @Property:自定义字段名,默认是使用当前字段名,例如:@Property(nameInDb = "name")
* @NotNull:设置数据库表当前列不能为空 * @Transient:使用该注释的属性不会被存入数据库的字段中 * @Index:使用@Index作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束 * @Unique:向数据库添加了一个唯一的约束,该属性值必须在数据库中是唯一值 * @ToOne:定义与另一个实体(一个实体对象)的关系 * @ToMany:定义与多个实体对象的关系 */
@Entity(nameInDb = "PERSON_DB")
public class Person {
@Id(autoincrement = true)
private Long id;
@NotNull
private String name;
private String pwd;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getLove() {
return love;
}
public void setLove(String love) {
this.love = love;
}
private String love;
@Generated(hash = 1852117147)
public Person(Long id, @NotNull String name, String pwd, String love) {
this.id = id;
this.name = name;
this.pwd = pwd;
this.love = love;
}
@Generated(hash = 1024547259)
public Person() {
}
}
以上是已经生成好的,自己对实体类注解好以后,点解菜单栏build下的Make Module 'app' 就可生成操作类
package com.view.pro20180226;
import android.app.Application;
import android.database.sqlite.SQLiteDatabase;
import com.view.pro20180226.greenDao.DaoMaster;
import com.view.pro20180226.greenDao.DaoSession;
/**
* 在Application中初始化数据库GreenDao
*/
public class MyApplication extends Application {
private static DaoSession daoSession;//数据库管理者
@Override
public void onCreate() {
super.onCreate();
//配置数据库
initGreenDaoDb();
}
private void initGreenDaoDb() {
//创建指定名称的数据库
DaoMaster.DevOpenHelper devopenhelper = new DaoMaster.DevOpenHelper(this, "demo.db", null);
//获取可写的数据库
SQLiteDatabase writableDatabase = devopenhelper.getWritableDatabase();
//获取可写数据库对象
DaoMaster daoMaster = new DaoMaster(writableDatabase);
//获取操作数据库的管理者
daoSession = daoMaster.newSession();
}
//添加获取操作数据的管理者方法,方便调用
public static DaoSession getDaoSession() {
return daoSession;
}
}
第四步:对数据进行增删改查,都有单条数据或者多条数据操作方法
//增加数据
private void addData() {
//获取Person表操作类
PersonDao personDao = MyApplication.getDaoSession().getPersonDao();
//创建添加的数据
Person person = new Person();
person.setName("张三丰");
person.setPwd("123456");
person.setLove("太极拳");
//插入数据到数据库
long insertId = personDao.insert(person);
Toast.makeText(this, "插入数据成功", Toast.LENGTH_SHORT).show();
}
private void deleteData() {
//获取Person表操作类
PersonDao personDao = MyApplication.getDaoSession().getPersonDao();
//删除数据可以根据实体类(必须有id)删除,
Person person = new Person();
person.setId((long) 3);
person.setName("张三丰");
person.setPwd("123456");
person.setLove("太极拳");
personDao.delete(person);
//根据数据的主键id删除...
personDao.deleteByKey((long) 4);
//删除所有
personDao.deleteAll();
}
3:修改更新数据
private void updateData() {
//获取Person表操作类
PersonDao personDao = MyApplication.getDaoSession().getPersonDao();
//创建修改后的数据,主键不变
Person person = new Person((long)6,"李四","666666","淘宝");
//更新第6条数据为...
personDao.update(person);
}
4:查询数据
private void queryData() {
//获取Person表操作类
PersonDao personDao = MyApplication.getDaoSession().getPersonDao();
//根据条件进行查找,查找字段name为马云的人
List<Person> list = personDao.queryBuilder().where(PersonDao.Properties.Name.eq("马云")).list();
//查询出id从1到3中的前两条数据
List<Person> personList = personDao.queryBuilder().where(PersonDao.Properties.Id.between(1, 3)).limit(2).list();
tip.setText(list.toString());
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/**
* Created by qingli on 2018/3/2
* 创建一个外键,用于关联另一张表的主键
* 使用@ToOne(joinProperty = "外键")
*/
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
//创建的关联外键,也就是所关联的另一张表的主键
private Long account_id;
//将此外键关联另一张表
@ToOne(joinProperty = "account_id")
private Card card;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 1507654846)
private transient UserDao myDao;
@Generated(hash = 1892899819)
public User(Long id, Long account_id) {
this.id = id;
this.account_id = account_id;
}
@Generated(hash = 586692638)
public User() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public Long getAccount_id() {
return this.account_id;
}
public void setAccount_id(Long account_id) {
this.account_id = account_id;
}
@Generated(hash = 10293163)
private transient Long card__resolvedKey;
/** To-one relationship, resolved on first access. */
@Generated(hash = 1969122530)
public Card getCard() {
Long __key = this.account_id;
if (card__resolvedKey == null || !card__resolvedKey.equals(__key)) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
CardDao targetDao = daoSession.getCardDao();
Card cardNew = targetDao.load(__key);
synchronized (this) {
card = cardNew;
card__resolvedKey = __key;
}
}
return card;
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 1904148139)
public void setCard(Card card) {
synchronized (this) {
this.card = card;
account_id = card == null ? null : card.getId();
card__resolvedKey = account_id;
}
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 2059241980)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getUserDao() : null;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", account_id=" + account_id +
", card=" + card +
", daoSession=" + daoSession +
", myDao=" + myDao +
", card__resolvedKey=" + card__resolvedKey +
'}';
}
}
创建第二张表,也就是被关联的表
@Entity
public class Card {
@Id
private Long id;
private String carn;
@Generated(hash = 1207410570)
public Card(Long id, String carn) {
this.id = id;
this.carn = carn;
}
@Generated(hash = 52700939)
public Card() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getCarn() {
return this.carn;
}
public void setCarn(String carn) {
this.carn = carn;
}
@Override
public String toString() {
return "Card{" +
"id=" + id +
", carn='" + carn + '\'' +
'}';
}
}
//插入一条一对一关联数据
DaoSession daoSession = MyApplication.getDaoSession();
User user = new User();
user.setAccount_id((long) 18);
daoSession.getUserDao().insert(user);
Card card = new Card();
card.setCarn("6123546988749999");
card.setId((long) 18);
daoSession.getCardDao().insert(card);
Toast.makeText(this, "插入成功!", Toast.LENGTH_SHORT).show();
//查询一对一的数据,通过user查询到关联的card
DaoSession daoSession = MyApplication.getDaoSession();
User user = new User();
user.setId((long) 1);
user.setAccount_id((long) 18);
Card card = daoSession.getUserDao().loadDeep((long) 1).getCard();
Log.d("views","card: "+card.toString());
5:一对多的关联(一张表的数据关联另一张表的多条数据)
/**
* Created by qingli on 2018/3/2
* 一对多的方式就是当前表的一条数据关联另一张表的多个数据
* 其实就是另一张表的多条数据关联当前表的数据主键id
* @ToMany(referencedJoinProperty = "其他多条数据定义的统一变量名")
*/
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
//关联拥有userId字段的Card表的多条数据
@ToMany(referencedJoinProperty = "userId")
private List<Card> cards;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 1507654846)
private transient UserDao myDao;
@Generated(hash = 1248599927)
public User(Long id) {
this.id = id;
}
@Generated(hash = 586692638)
public User() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
/**
* To-many relationship, resolved on first access (and after reset).
* Changes to to-many relations are not persisted, make changes to the target entity.
*/
@Generated(hash = 1374403364)
public List<Card> getCards() {
if (cards == null) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
CardDao targetDao = daoSession.getCardDao();
List<Card> cardsNew = targetDao._queryUser_Cards(id);
synchronized (this) {
if (cards == null) {
cards = cardsNew;
}
}
}
return cards;
}
/** Resets a to-many relationship, making the next get call to query for a fresh result. */
@Generated(hash = 189953180)
public synchronized void resetCards() {
cards = null;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 2059241980)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getUserDao() : null;
}
}
创建第二个数据表,也就是多条数据的
@Entity
public class Card {
@Id(autoincrement = true)
private Long id;
//用于对应关联的主表标识id
private Long userId;
private String carn;
@Generated(hash = 787054998)
public Card(Long id, Long userId, String carn) {
this.id = id;
this.userId = userId;
this.carn = carn;
}
@Generated(hash = 52700939)
public Card() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return this.userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getCarn() {
return this.carn;
}
public void setCarn(String carn) {
this.carn = carn;
}
@Override
public String toString() {
return "Card{" +
"id=" + id +
", userId=" + userId +
", carn='" + carn + '\'' +
'}';
}
}
插入数据测试:
private void create() {
DaoSession daoSession = MyApplication.getDaoSession();
//插入一条User数据
User user = new User();
daoSession.getUserDao().insert(user);
//插入多条Card数据
for (int i = 0; i < 10; i++) {
Card card = new Card();
card.setCarn("622190645581" + i + i + i + i);
card.setUserId(user.getId());
daoSession.getCardDao().insert(card);
}
Toast.makeText(this, "插入成功!", Toast.LENGTH_SHORT).show();
}
查询数据测试,跟据一条查询多条
private void query() {
DaoSession daoSession = MyApplication.getDaoSession();
List<Card> cards = daoSession.getUserDao().load((long) 1).getCards();
Log.d("views", "card: " + cards.toString());
}
schemaVersion 1 的,再次安装就会进行表升级,但是会清空原有数据
** * Created by qingli on 2018/3/1 */ public class GreenDaoUpdateHelp { public static boolean DEBUG = false; private static String TAG = "MigrationHelper"; private static final String SQLITE_MASTER = "sqlite_master"; private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master"; public static void migrate(SQLiteDatabase db, Classextends AbstractDao>... daoClasses) { Database database = new StandardDatabase(db); printLog("【The Old Database Version】" + db.getVersion()); printLog("【Generate temp table】start"); generateTempTables(database, daoClasses); printLog("【Generate temp table】complete"); dropAllTables(database, true, daoClasses); createAllTables(database, false, daoClasses); printLog("【Restore data】start"); restoreData(database, daoClasses); printLog("【Restore data】complete"); } private static void generateTempTables(Database db, Classextends AbstractDao>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { String tempTableName = null; DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String tableName = daoConfig.tablename; if (!isTableExists(db, false, tableName)) { printLog("【New Table】" + tableName); continue; } try { tempTableName = daoConfig.tablename.concat("_TEMP"); StringBuilder dropTableStringBuilder = new StringBuilder(); dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";"); db.execSQL(dropTableStringBuilder.toString()); StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName); insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";"); db.execSQL(insertTableStringBuilder.toString()); printLog("【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig)); printLog("【Generate temp table】" + tempTableName); } catch (SQLException e) { Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e); } } } private static boolean isTableExists(Database db, boolean isTemp, String tableName) { if (db == null || TextUtils.isEmpty(tableName)) { return false; } String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER; String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?"; Cursor cursor=null; int count = 0; try { cursor = db.rawQuery(sql, new String[]{"table", tableName}); if (cursor == null || !cursor.moveToFirst()) { return false; } count = cursor.getInt(0); } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) cursor.close(); } return count > 0; } private static String getColumnsStr(DaoConfig daoConfig) { if (daoConfig == null) { return "no columns"; } StringBuilder builder = new StringBuilder(); for (int i = 0; i < daoConfig.allColumns.length; i++) { builder.append(daoConfig.allColumns[i]); builder.append(","); } if (builder.length() > 0) { builder.deleteCharAt(builder.length() - 1); } return builder.toString(); } private static void dropAllTables(Database db, boolean ifExists, @NonNull Classextends AbstractDao>... daoClasses) { reflectMethod(db, "dropTable", ifExists, daoClasses); printLog("【Drop all table】"); } private static void createAllTables(Database db, boolean ifNotExists, @NonNull Classextends AbstractDao>... daoClasses) { reflectMethod(db, "createTable", ifNotExists, daoClasses); printLog("【Create all table】"); } /** * dao class already define the sql exec method, so just invoke it */ private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Classextends AbstractDao>... daoClasses) { if (daoClasses.length < 1) { return; } try { for (Class cls : daoClasses) { Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class); method.invoke(null, db, isExists); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } private static void restoreData(Database db, Classextends AbstractDao>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String tableName = daoConfig.tablename; String tempTableName = daoConfig.tablename.concat("_TEMP"); if (!isTableExists(db, true, tempTableName)) { continue; } try { // get all columns from tempTable, take careful to use the columns list List<String> columns = getColumns(db, tempTableName); ArrayList<String> properties = new ArrayList<>(columns.size()); for (int j = 0; j < daoConfig.properties.length; j++) { String columnName = daoConfig.properties[j].columnName; if (columns.contains(columnName)) { properties.add(columnName); } } if (properties.size() > 0) { final String columnSQL = TextUtils.join(",", properties); StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" ("); insertTableStringBuilder.append(columnSQL); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(columnSQL); insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); db.execSQL(insertTableStringBuilder.toString()); printLog("【Restore data】 to " + tableName); } StringBuilder dropTableStringBuilder = new StringBuilder(); dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); db.execSQL(dropTableStringBuilder.toString()); printLog("【Drop temp table】" + tempTableName); } catch (SQLException e) { Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e); } } } private static List<String> getColumns(Database db, String tableName) { List<String> columns = null; Cursor cursor = null; try { cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null); if (null != cursor && cursor.getColumnCount() > 0) { columns = Arrays.asList(cursor.getColumnNames()); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) cursor.close(); if (null == columns) columns = new ArrayList<>(); } return columns; } private static void printLog(String info){ if(DEBUG){ Log.d(TAG, info); } } }
public class MyOpenHelper extends DaoMaster.OpenHelper {
public MyOpenHelper(Context context, String name) {
super(context, name);
}
public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
GreenDaoUpdateHelp.migrate(db,PersonDao.class);//数据版本变更才会执行,第二个参数为所有数据表实体类的dao操作类,有多少,填多少
}
}
/**
* 在Application中初始化数据库GreenDao
*/
public class MyApplication extends Application {
private static DaoSession daoSession;//数据库管理者
@Override
public void onCreate() {
super.onCreate();
//配置数据库
initGreenDaoDb();
}
private void initGreenDaoDb() {
//创建指定名称的数据库
//使用自己定义的数据库升级帮助类
DaoMaster.OpenHelper devopenhelper = new MyOpenHelper(this, "demo.db", null);
//获取可写的数据库
SQLiteDatabase writableDatabase = devopenhelper.getWritableDatabase();
//获取可写数据库对象
DaoMaster daoMaster = new DaoMaster(writableDatabase);
//获取操作数据库的管理者
daoSession = daoMaster.newSession();
}
//添加获取操作数据的管理者方法,方便调用
public static DaoSession getDaoSession() {
return daoSession;
}
}
//greendao的依赖库
compile 'org.greenrobot:greendao:3.2.2'
//greendao数据加密依赖
compile 'net.zetetic:android-database-sqlcipher:3.5.7@aar'
然后在自定义的MyApplication中修改下配置,这样既能升级迁移数据,又能安全加密数据
**
* 在Application中初始化数据库GreenDao
*/
public class MyApplication extends Application {
private static DaoSession daoSession;//数据库管理者
@Override
public void onCreate() {
super.onCreate();
//配置数据库
initGreenDaoDb();
}
private void initGreenDaoDb() {
//创建指定名称的数据库
//使用自己定义的数据库升级帮助类
MyOpenHelper devopenhelper = new MyOpenHelper(this, "demo.db", null);
//创建加密类型的数据库DaoMaster
DaoMaster daoMaster = new DaoMaster(devopenhelper.getEncryptedWritableDb(getString(R.string.app_name)));
//获取操作数据库的管理者
daoSession = daoMaster.newSession();
}
//添加获取操作数据的管理者方法,方便调用
public static DaoSession getDaoSession() {
return daoSession;
}
}
升级数据库帮助类 GreenDaoUpdateHelp.java(https://download.csdn.net/download/xu10281/12294474)