Android架构组件Room
Room主要包含三个部分:
- Database : 持有DB和DAO
- Entity : 定义POJO类,即数据表结构
- DAO(Data Access Objects) : 定义访问数据(增删改查)的接口
@Entity(tableName = "table_name**")
注解POJO类,定义数据表名称;@PrimaryKey
定义主键,如果一个Entity使用的是复合主键,可以通过@Entity
注解的primaryKeys
属性定义复合主键:@Entity(primaryKeys = {"firstName", "lastName"})
@ColumnInfo(name = “column_name”)
定义数据表中的字段名@Ignore
用于告诉Room需要忽略的字段或方法- 建立索引:在
@Entity
注解的indices
属性中添加索引字段。例如:indices = {@Index(value = {"first_name", "last_name"}, unique = true), ...}
,unique = true
可以确保表中不会出现{"first_name", "last_name"}
相同的数据。
1.2 Entitiy间的关系
不同于目前存在的大多数ORM库,Room不支持Entitiy对象间的直接引用。(具体原因可以参考: Understand why Room doesn't allow object references)
但Room允许通过外键(Foreign Key)来表示Entity之间的关系。
@Entity(foreignKeys = @ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "user_id"))
class Book {
@PrimaryKey
public int bookId;
public String title;
@ColumnInfo(name = "user_id")
public int userId;
}
如上面代码所示,Book对象与User对象是属于的关系。Book中的user_id,对应User中的id。 那么当一个User对象被删除时, 对应的Book会发生什么呢?
@ForeignKey
注解中有两个属性onDelete
和onUpdate
, 这两个属性对应ForeignKey
中的onDelete()
和onUpdate()
, 通过这两个属性的值来设置当User对象被删除/更新时,Book对象作出的响应。这两个属性的可选值如下:
CASCADE
:User删除时对应Book一同删除; 更新时,关联的字段一同更新NO_ACTION
:User删除时不做任何响应RESTRICT
:禁止User的删除/更新。当User删除或更新时,Sqlite会立马报错。SET_NULL
:当User删除时, Book中的userId会设为NULLSET_DEFAULT
:与SET_NULL
类似,当User删除时,Book中的userId会设为默认值
2. 创建数据访问对象(DAO)
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND "
+ "last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(List<User> users);
@Insert(onConflict = OnConflictStrategy.REPLACE)
public void insertUsers(User... users);
@Delete
void delete(User user);
@Update
public void updateUsers(List<User> users);
}
DAO 可以是一个接口,也可以是一个抽象类, Room会在编译时创建DAO的实现。
2.2 查询参数传递
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND "
+ "last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
看代码应该比较好理解, 方法中传递参数arg
, 在sql语句中用:arg
即可。编译时R
2.3 查询表中部分字段的信息
在实际某个业务场景中, 我们可能仅关心一个表部分字段的值,这时我仅需要查询关心的列即可。
定义子集的POJO类:
public class NameTuple {
@ColumnInfo(name="first_name")
public String firstName;
@ColumnInfo(name="last_name")
public String lastName;
}
在DAO中添加查询方法:
@Query("SELECT first_name, last_name FROM user")
public List<NameTuple> loadFullName();
这里定义的POJO也支持使用
@Embedded
2.4 联表查询
Room支持联表查询,接口定义上与其他查询差别不大, 主要还是sql语句的差别。
@Dao
public interface MyDao {
@Query("SELECT * FROM book "
+ "INNER JOIN loan ON loan.book_id = book.id "
+ "INNER JOIN user ON user.id = loan.user_id "
+ "WHERE user.name LIKE :userName")
public List<Book> findBooksBorrowedByNameSync(String userName);
}
2.4 联表查询
Room支持联表查询,接口定义上与其他查询差别不大, 主要还是sql语句的差别。
@Dao
public interface MyDao {
@Query("SELECT * FROM book "
+ "INNER JOIN loan ON loan.book_id = book.id "
+ "INNER JOIN user ON user.id = loan.user_id "
+ "WHERE user.name LIKE :userName")
public List<Book> findBooksBorrowedByNameSync(String userName);
}
Room提供了Migration类来实现数据库的升级:
Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, "
+ "`name` TEXT, PRIMARY KEY(`id`))");
}
};
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE Book "
+ " ADD COLUMN pub_year INTEGER");
}
};
在创建Migration类时需要指定startVersion
和endVersion
, 代码中MIGRATION_1_2
和MIGRATION_2_3
的startVersion和endVersion是递增的, Migration其实是支持从版本1直接升到版本3,只要其migrate()
方法里执行的语句正常即可。那么Room是怎么实现数据库升级的呢?其实本质上还是调用SQLiteOpenHelper.onUpgrade
,Room中自己实现了一个SQLiteOpenHelper
, 在onUpgrade()
方法被调用时触发Migration
,当第一次访问数据库时,Room做了以下几件事:
- 创建Room Database实例
SQLiteOpenHelper.onUpgrade
被调用,并且触发Migration
- 打开数据库
架构组件Room、demo了解:https://download.csdn.net/download/meixi_android/19386289
原生sqlite、demo链接:https://download.csdn.net/download/meixi_android/10710400
创建数据库版本v.1
/**
* 作者:created by meixi
* 邮箱:13164716840@163.com
* 日期:2018/10/9 11
*/
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "mall.db";
private static final int DATABASE_VERSION = 1000;
private static DBHelper instance = null;
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public synchronized static DBHelper getInstance(Context context) {
if (instance == null) {
instance = new DBHelper(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL.CREATE_TABLE_FAVORITE);
// 若不是第一个版本安装,直接执行数据库升级
// 请不要修改FIRST_DATABASE_VERSION的值,其为第一个数据库版本大小
final int FIRST_DATABASE_VERSION = 1000;
onUpgrade(db, FIRST_DATABASE_VERSION, DATABASE_VERSION);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 使用for实现跨版本升级数据库
for (int i = oldVersion; i < newVersion; i++) {
switch (i) {
default:
break;
}
}
}
}
创建数据库语句:
public class SQL {
public static final String T_FAVORITE = "favorite";
public static final String CREATE_TABLE_FAVORITE =
"CREATE TABLE IF NOT EXISTS " + T_FAVORITE + "(" +
"_id integer primary key autoincrement, " +
"title VARCHAR, " +
"url VARCHAR, " +
"createDate VARCHAR " +
")";
}
实现增删改查activity:
public class MainActivity extends AppCompatActivity {
private static String CREATE_TABLE ="create table number(_id integer primary key autoincrement ,phone real)";
int ab = 0,cd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1=findViewById(R.id.baocunid);
Button button2=findViewById(R.id.duquid);
Button button3=findViewById(R.id.shanchuid);
Button button4=findViewById(R.id.xiugaiid);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ab++;
boolean nn = baocun(MainActivity.this, new String[] { "114499title","rullll---htt;s=="+ab,"加入的xxx" });
Log.i("lgq","sbbbb---"+nn);
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getBai(MainActivity.this);
}
});
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String ss= Delete(MainActivity.this,"1");
Log.i("lgq","shanchu=g==="+ss);
}
});
button4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String ss = updata(MainActivity.this,"");
Log.i("lgq","xiugg=g==="+ss);
}
});
}
public static boolean baocun(Context context, String[] values) {
SQLiteDatabase db2=null;
DBHelper2 dbHelper = null;
try {
dbHelper =new DBHelper2(context);
db2 = dbHelper.getWritableDatabase();
db2=dbHelper.getWritableDatabase();
db2.beginTransaction();
db2.execSQL("insert into favorite (title,url,deleted) values (?,?,?)",values);
db2.setTransactionSuccessful();
db2.endTransaction();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}finally{
}
}
public List<String> getBai(Context context){
List<String> list = new ArrayList<String>();
SQLiteDatabase db2=null;
DBHelper2 dbHelper = null;
try {
dbHelper= new DBHelper2(context);
db2=dbHelper.getWritableDatabase();
Cursor cursor =db2.rawQuery("select _id,title,deleted from favorite", null);
while(cursor.moveToNext()){
cd++;
// int dbid = cursor.getInt(cursor.getColumnIndex("_id"));
int id=cursor.getInt(cursor.getColumnIndex("_id"));
String haoma = cursor.getString(cursor.getColumnIndex("title"))+"";
String names = cursor.getString(cursor.getColumnIndex("deleted"));
list.add(haoma);
System.out.println("lgqs======"+haoma+"......."+names+" "+cd+" id=== "+id);
}
db2.setTransactionSuccessful();
db2.endTransaction();
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
public static String Delete(Context context,String string){
SQLiteDatabase db2=null;
DBHelper2 dbHelper = null;
try {
dbHelper =new DBHelper2(context);
db2 = dbHelper.getWritableDatabase();
db2=dbHelper.getWritableDatabase();
db2.beginTransaction();
db2.execSQL("delete from favorite where _id=?",new String[] { string });
db2.setTransactionSuccessful();
db2.endTransaction();
return "成功";
} catch (Exception e) {
e.printStackTrace();
return "失败";
}
}
public static String updata(Context context,String string){
SQLiteDatabase db2=null;
DBHelper2 dbHelper = null;
try {
dbHelper =new DBHelper2(context);
db2 = dbHelper.getWritableDatabase();
db2=dbHelper.getWritableDatabase();
db2.beginTransaction();
db2.execSQL("update favorite set title ="+"2222999"+" where url =?",new String[]{"rullll---htt;s==3"});
db2.setTransactionSuccessful();
db2.endTransaction();
return "成功";
} catch (Exception e) {
e.printStackTrace();
return "失败";
}
}
}