網站首頁 編程語言 正文
介紹
Android內帶SQLite內嵌式數據庫了。這對于我們存儲一些更復雜的結構化數據帶來了極大的便利。比如說我們要存儲應用內的常用聯系人,購物車暫存信息,常量。必竟從xml或者是json里取數據都沒有一條Select語句來得簡單。
SQLite常用有五種數據類型:
- NULL
- INTEGER
- REAL(浮點數)
- TEXT(字符串文本)
- BLOB(二進制對象)
雖然只有五種,但是對于varchar,char等其他數據類型都是可以保存的,如下create table語句依然是可以生效的:
create table user(name varchar(20))
SQLite常用的三個類介紹
- SQLiteOpenHelper:抽象類,我們通過繼承該類,然后重寫數據庫創建以及更新的方法, 我們還可以通過該類的對象獲得數據庫實例,或者關閉數據庫;
- SQLiteDatabase:數據庫訪問類:我們可以通過該類的對象來對數據庫做一些增刪改查的操作;
- Cursor:游標,有點類似于JDBC里的resultset,結果集!可以簡單理解為指向數據庫中某 一個記錄的指針;
這三個類我們直接來看下面的Sample代碼各位就知道是什么樣的組合應用了。
private SQLiteDatabase db;
private Context context = null;
private DBOpenHelper dbOpenHelper;
private String DB_NAME="user.db";
private static final String DB_TABLE = "t_user_login";
dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
try {
db = dbOpenHelper.getWritableDatabase();
db.open();
StringBuilder sqlStr = new StringBuilder();
sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
Cursor cur = db.rawQuery(sqlStr.toString(), null);
while (cur.moveToNext()) {
String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
String password = cur.getString(cur.getColumnIndexOrThrow("password"));
String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
UserBean user = new UserBean();
user.setLoginId(loginId);
user.setPassword(password);
user.setUserName(userName);
userList.add(user);
}
} catch (SQLiteException ex) {
Log.e(TAG, ">>>>>>open db error: " + ex.getMessage(), ex);
}finally {
try{
db.close();
}catch(Exception e){}
}
使用上和JDBC幾乎一樣,此處的Cursor相當于JDBC里的ResultSet。
敲黑板重要提醒-Android中如何正確使用db.open()/db.close()
在我們的例子里我們在每一個業務方法操作都會使用db.open一下,在finally塊里db.close一下。
同時要在Activity的onStop方法中去dbclose()掉它。
記得,它就和水龍頭一樣,用完就要關。
SQLiteOpenHelper類的使用
這個類通常我們都要新建一個其它的類來extends這個類才能使用,主要的是這個類里有這么兩個方法是很有用的。
public void onCreate
方法全簽名:public void onCreate(SQLiteDatabase db)
這個類的作用就是當SQLiteOpenHelper被實例化時,第一次用來做“初始化數據庫”用的。比如說我們有一個類如下
private static class DBOpenHelper extends SQLiteOpenHelper {
然后當你實例化這個類時
dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
它會自動觸發這個onCreate方法,在onCreate方法中我們可以做表創建以及數據初始化操作如:
private static final String DB_CREATE = "create table " +
DB_TABLE + " (" + KEY_ID + " VARCHAR(20) primary key , " +
KEY_PASSWORD + " text not null, " + KEY_NAME + " text not null);";
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, ">>>>>>execute create table->" + DB_CREATE);
db.execSQL(DB_CREATE);
StringBuilder initDataSql = new StringBuilder();
initDataSql.append("INSERT INTO ").append(DB_TABLE).
append("(").append(KEY_ID).append(",").append(KEY_PASSWORD).
append(",").append(KEY_NAME).append(")").append("values(?,?,?)");
Log.i(TAG, ">>>>>>execute initDataSql->" + initDataSql.toString());
db.execSQL(initDataSql.toString(), new String[]{"root", "111111", "root"});
Log.i(TAG, ">>>>>>db init successfully");
}
public void onUpgrade
方法全簽名:public void onUpgrade(SQLiteDatabase db, int _oldVersion, int _newVersion)
它有一個_newVersion這么一個參數,這個參數也很有意思。當你在實例化SQLiteOpenHelper類傳入的DB_VERSION參數>就近一次實例化這個類傳入的DB_VERSION參數時,它就會觸發這個onUpgrade()方法,在這個方法里我們一般是根據業務場景的需要,沒有一概而論該怎么辦,通用的做法有:
- 重新執行一遍onCreate();此時所有的數據會被清空并初始化;
- 有些Android發版時不需要做全數據庫清除,往往太過危險,而是會執行alter更改表結構、新建表、新插入-insert一些數據或者是稍帶著update一些數據;
因此我才說,不一概而論而是需要依賴于你的實際業務場景來做操作。在我們的例子里我們會在onUpgrade里再執行一下onCreate()。
使用SQLite操作數據庫方法介紹
這一塊在使用上分兩塊。它類似Hibernate一樣,也有API和原生SQL之分。
API的使用
即不需要書寫SQL,如下樣例:
public long addItem(UserBean user) throws Exception {
try {
ContentValues newValues = new ContentValues();
newValues.put(KEY_ID, user.getLoginId());
newValues.put(KEY_PASSWORD, user.getPassword());
newValues.put(KEY_NAME, user.getUserName());
Log.i(TAG, "addItem successfully with loginId->" + user.getLoginId() + " password->" + user.getPassword());
return db.insert(DB_TABLE, null, newValues);
} catch (Exception e) {
Log.e(TAG, "addItem error: " + e.getMessage(), e);
throw new Exception("addItem error: " + e.getMessage(), e);
}
}
我們可以看到全程沒有使用SQL。
原生SQL的使用
public List<UserBean> queryAll() {
List<UserBean> userList = new ArrayList<UserBean>();
try {
StringBuilder sqlStr = new StringBuilder();
sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
Cursor cur = db.rawQuery(sqlStr.toString(), null);
while (cur.moveToNext()) {
String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
String password = cur.getString(cur.getColumnIndexOrThrow("password"));
String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
UserBean user = new UserBean();
user.setLoginId(loginId);
user.setPassword(password);
user.setUserName(userName);
userList.add(user);
}
} catch (Exception e) {
Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
}
return userList;
}
區分何時使用API何時使用原生SQL
如何區分呢?
答案很簡單,以下是最佳實踐 :
- 單表操作,就使用API好了;
- 跨表(>1個表)的操作或者是較復雜的邏輯如果使用API會產生循環套來套去不如寫一條長點的SQL那么請直接使用原生SQL;
在樣例前我們最后要了解一下,SQLite數據庫管理工具。
SQLite數據庫管理
Android里的SQLite一旦生成后它必須導出到AndroidStudio外部才能管理。按照如下步驟來導出SQLite數據庫
先使用Device File Explorer打開data->data->你的包全路徑下/databases,這里面有一個.db文件就是SQLite數據庫文件。另一個.db-journal是Transaction日志,我們后面講SQLite的Transaction時會講到。
選擇這個user.db右鍵選->save as,就可以導出到本地磁盤了。
然后你可以使用如下工具去管理SQLite數據庫文件。
Windows下的SQLite管理工具
請使用SQLite Expert Professional,我使用的是5.4.4。不過這個是收費的,它長這個樣但相當專業(收費的當然專業)。
MAC下的SQLite管理工具
請使用SQLiteManager,完全免費并且和Windows的SQLite Expert Professional收費的一樣功能全。為什么呢?難道因為MAC貴。。。所以。。。有預收費之說:)?
好了,原理介紹完畢,我們要進入實踐課程了。
課程目標
1.該APP啟動會創建user.db數據庫,新建一張t_user_login表并初始化一條root/111111數據進入內嵌SQLite數據庫;
2.用戶名密碼輸入root/111111點【登錄】按鈕可以得到登錄成功,如果輸入其它的不存在的帳戶信息會以Toast顯示“登錄失敗請校驗你的用戶名和密碼”;
3.用戶名密碼輸入任意值,點擊【增加一條記錄】按鈕,可以插入一條數據到內嵌SQLite;
4.點擊【查詢所有記錄】會以Log和Toast顯示目前所有的相對應的表內的數據即:select *操作;
5.例子中對于單表的插入操作我們使用的是Android自帶的SQLiteOpenHelper的原生API;
6.校驗登錄和查詢所有記錄我們用的是原生SQL+Cursor;
下面就進入代碼部分吧。
前端代碼
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="用戶登陸" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="請輸入用戶名" /> <EditText android:id="@+id/editLoginid" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="用戶名" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="請輸入密碼" /> <EditText android:id="@+id/editPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="密碼" android:inputType="textPassword" /> <Button android:id="@+id/buttonLogin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="登錄" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#dfdfdf" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/buttonAddItem" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10dp" android:text="增加一條記錄"/> <Button android:id="@+id/buttonQueryAll" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:text="查詢所有記錄"/> </LinearLayout> </LinearLayout>
后端代碼
UserBean.java
package org.mk.android.demo.demosimplesqlite;
import java.io.Serializable;
public class UserBean implements Serializable {
public String getLoginId() {
return loginId;
}
public void setLoginId(String loginId) {
this.loginId = loginId;
}
private String loginId = "";
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
private String password = "";
private String userName = "";
}
SQLite的核心操作-DBAdapter.java
package org.mk.android.demo.demosimplesqlite;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class DBAdapter {
private static final String TAG = "DemoSQLite";
private static final String DB_NAME = "user.db";
private static final String DB_TABLE = "t_user_login";
private static final int DB_VERSION = 2;
public static final String KEY_ID = "loginId";
public static final String KEY_PASSWORD = "password";
public static final String KEY_NAME = "user_name";
private SQLiteDatabase db;
private Context context = null;
private DBOpenHelper dbOpenHelper;
public DBAdapter(Context ctx) {
context = ctx;
}
public void close() {
try {
if (db != null) {
db.close();
db = null;
}
} catch (Exception e) {
}
}
public void open() {
dbOpenHelper = new DBOpenHelper(context, DB_NAME, null, DB_VERSION);
try {
db = dbOpenHelper.getWritableDatabase();
} catch (SQLiteException ex) {
Log.e(TAG, ">>>>>>open db error: " + ex.getMessage(), ex);
}
}
public long addItem(UserBean user) throws Exception {
try {
ContentValues newValues = new ContentValues();
newValues.put(KEY_ID, user.getLoginId());
newValues.put(KEY_PASSWORD, user.getPassword());
newValues.put(KEY_NAME, user.getUserName());
Log.i(TAG, "addItem successfully with loginId->" + user.getLoginId() + " password->" + user.getPassword());
return db.insert(DB_TABLE, null, newValues);
} catch (Exception e) {
Log.e(TAG, "addItem error: " + e.getMessage(), e);
throw new Exception("addItem error: " + e.getMessage(), e);
}
}
public List<UserBean> queryAll() {
List<UserBean> userList = new ArrayList<UserBean>();
try {
StringBuilder sqlStr = new StringBuilder();
sqlStr.append("select loginId,password,user_name from ").append(DB_TABLE);
Cursor cur = db.rawQuery(sqlStr.toString(), null);
while (cur.moveToNext()) {
String loginId = cur.getString(cur.getColumnIndexOrThrow("loginId"));
String password = cur.getString(cur.getColumnIndexOrThrow("password"));
String userName = cur.getString(cur.getColumnIndexOrThrow("user_name"));
UserBean user = new UserBean();
user.setLoginId(loginId);
user.setPassword(password);
user.setUserName(userName);
userList.add(user);
}
} catch (Exception e) {
Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
}
return userList;
}
public int checkLogin(String loginId, String pwd) {
int result = 0;
StringBuilder sqlStr = new StringBuilder();
sqlStr.append("SELECT COUNT(*) FROM ").append(DB_TABLE).append(" WHERE ").append(KEY_ID).append("=? AND ").append(KEY_PASSWORD).append("=?");
Log.i(TAG, ">>>>>>execute checkLogin SQL: " + sqlStr.toString());
Log.i(TAG, ">>>>>>LoginId->" + loginId + " password->" + pwd);
try {
Cursor cur = db.rawQuery(sqlStr.toString(), new String[]{loginId, pwd});
if (cur != null) {
cur.moveToFirst();
result = cur.getInt(0);
}
} catch (Exception e) {
Log.e(TAG, "checkLogin dao error: " + e.getMessage(), e);
}
return result;
}
private static class DBOpenHelper extends SQLiteOpenHelper {
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
private static final String DB_CREATE = "create table " +
DB_TABLE + " (" + KEY_ID + " VARCHAR(20) primary key , " +
KEY_PASSWORD + " text not null, " + KEY_NAME + " text not null);";
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, ">>>>>>execute create table->" + DB_CREATE);
db.execSQL(DB_CREATE);
StringBuilder initDataSql = new StringBuilder();
initDataSql.append("INSERT INTO ").append(DB_TABLE).
append("(").append(KEY_ID).append(",").append(KEY_PASSWORD).
append(",").append(KEY_NAME).append(")").append("values(?,?,?)");
Log.i(TAG, ">>>>>>execute initDataSql->" + initDataSql.toString());
db.execSQL(initDataSql.toString(), new String[]{"root", "111111", "root"});
Log.i(TAG, ">>>>>>db init successfully");
}
@Override
public void onUpgrade(SQLiteDatabase db, int _oldVersion, int _newVersion) {
//db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
//onCreate(_db);
db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
onCreate(db);
}
}
}
MainActivity.java
這個就來得相對簡單了。
package org.mk.android.demo.demosimplesqlite;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "DemoSQLite";
private SQLiteDatabase db;
private Context context;
private DBAdapter dbAdapter;
private EditText editLoginId;
private EditText editPassword;
private Button buttonLogin;
private Button buttonAddItem;
private Button buttonQueryAll;
private String strLoginId;
private String strPassword;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
buttonLogin = (Button) findViewById(R.id.buttonLogin);
buttonAddItem = (Button) findViewById(R.id.buttonAddItem);
buttonQueryAll = (Button) findViewById(R.id.buttonQueryAll);
editLoginId = (EditText) findViewById(R.id.editLoginid);
editPassword = (EditText) findViewById(R.id.editPassword);
dbAdapter = new DBAdapter(context);
buttonLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
dbAdapter.open();
strLoginId = editLoginId.getText().toString();
strPassword = editPassword.getText().toString();
int answer = dbAdapter.checkLogin(strLoginId, strPassword);
Log.i(TAG, ">>>>>>checkLogin is->" + answer);
if (answer != 1) {
Toast.makeText(context, "登錄失敗請校驗你的用戶名和密碼", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "登錄成功", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.e(TAG, ">>>>>>checkLogin error: " + e.getMessage(), e);
} finally {
dbAdapter.close();
}
}
});
buttonAddItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
dbAdapter.open();
strLoginId = editLoginId.getText().toString();
strPassword = editPassword.getText().toString();
UserBean user = new UserBean();
user.setLoginId(strLoginId);
user.setPassword(strPassword);
user.setUserName(strLoginId);
long result = dbAdapter.addItem(user);
Toast.makeText(context, "增加一條數據成功", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e("TAG", ">>>>>>addItem error: " + e.getMessage(), e);
} finally {
dbAdapter.close();
}
}
});
buttonQueryAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
dbAdapter.open();
StringBuilder sb = new StringBuilder();
List<UserBean> userList = new ArrayList<UserBean>();
userList = dbAdapter.queryAll();
if (userList != null && userList.size() > 0) {
userList.forEach(v -> {
sb.append("loginId->").append(v.getLoginId())
.append(" password->").append(v.getPassword())
.append(" userName->").append(v.getUserName())
.append("\n");
});
Log.i(TAG,sb.toString());
Toast.makeText(context, "查詢所有數據\n" + sb.toString(), Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.e(TAG, ">>>>>>queryAll error: " + e.getMessage(), e);
} finally {
dbAdapter.close();
}
}
});
}
@Override
protected void onStart(){
super.onStart();
dbAdapter.open();
}
@Override
protected void onStop() {
super.onStop();
dbAdapter.close();
}
}
運行效果
自己動一下手試試吧。
原文鏈接:https://blog.csdn.net/lifetragedy/article/details/128397767
相關推薦
- 2022-03-27 C++如何用數組模擬鏈表_C 語言
- 2022-07-16 Electron導出附件的三種方式
- 2022-04-25 Golang?字符串與字節數組互轉的實現_Golang
- 2022-08-21 利用Python制作本地Excel的查詢與生成的程序問題_python
- 2022-07-11 EasyExcel實現追加寫入文件
- 2022-03-27 Android自定義模擬時鐘控件_Android
- 2022-12-26 C語言實現十六進制轉換為十進制的方法詳解_C 語言
- 2022-06-21 分享python?寫?csv?文件的兩種方法_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支