数据库管理系统(DBMS):是系统软件,是数据库系统的核心。
常见数据库管理系统有:Access、mysql、sql server
MySQL实现了四种通信协议:
通常我们通过来连接MySQL,各种主要编程语言都是根据这个协议实现了连接模块
这个通常我们登入MySQL服务器中使用这个协议,因为要使用这个协议连接MySQL需要一个物理文件,文件的存放位置在配置文件中有定义,值得一提的是,这是所有协议中最高效的一个。
这个只有windows可以使用,使用这个协议需要在配置文件中在启动的时候使用–shared-memory参数,注意的是,使用此协议,一个host上只能有一个server,所以这个东西一般没啥用的,除非你怀疑其他协议不能正常工作,实际上微软的SQL Sever也支持这个协议
这个协议也是只有windows才可以用,同shared memory一样,使用此协议,一个host上依然只能有一个server,即使是使用不同的端口也不行,Named Pipes 是为局域网而开发的协议。内存的一部分被某个进程用来向另一个进程传递信息,因此一个进程的输出就是另一个进程的输入。第二个进程可以是本地的(与第一个进程位于同一台计算机上),也可以是远程的(位于联网的计算机上)。正因为如此,假如你的环境中没有或者禁用TCP/IP环境,而且是windows服务器,那么好歹你的数据库还能工作。使用这个协议需要在启动的时候添加–enable-named-pipe选项
注意安装过程中记录下来弹窗中的密码。如果没有记住密码需要进入mysql修改,请查看后续。
open .bash_profile
(没有需要touch该文件)在该文件中添加mysql/bin的目录
PATH=$PATH:/usr/local/mysql/bin
source ~/.bash_profile
mysql -uroot -p
登录mysql, 输入之前保存的密码重置mysql初始密码:
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpassword');
$ cd /usr/local/mysql/bin
$ sudo su
输入mac管理员密码。
sh-3.2#
时输入sh-3.2#./mysqld_safe --skip-grant-tables &
mysql -u -root
首先执行下面命令为了能够修改任意的密码
mysql> FLUSH PRIVILEGES;
之后执行修改密码的SQL语句:
mysql> SET PASSWORD FOR root@'localhost' = PASSWORD('newPsw');
FLUSH PRIVILEGES;
Control+D退出mysql
mysql -u root -p
输入新修改的密码。#
sql语句基本和正常的语句相同。
cd /usr/local/mysql/bin
mysql -u root -p
输入密码即可进入mysql
建库:create database testDB character set utf8;
修改库编码:alter database app_relation character set utf8;
表的属性:
id int AUTO_INCREMENT primary key not null
i> 打开Terminal,输入mysqldump,发现Terminal提示mysqldump: command not found
则进入ii,否则进入iii
ii> 之所以会出现mysql或者mysqldump这样的命令找不到,我们可以打开/usr/bin文件夹,发现bin目录中并没有Mysql打头的UEF文件,而在/usr/local/mysql/bin中可以找到这样的文件,说明mysql的命令默认安装路径是不在bin目录中的,因而我们需要在环境变量中配置mysql的所有命令。按照如下步骤配置:
打开terminal输入 open ~/.bash_profile
添加如下代码:
#mysql
PATH=$PATH:/usr/local/mysql/bin
export
保存并关闭。Terminal中执行以下代码:
source ~/.bash_profile
再次输入mysqldump确定可以使用。
iii> 备份
cd 要导出到的目录 (如:cd /Users/lwh/Desktop)
mysqldump -u root -p databaseName>test.sql
iv>还原
进入mysql(由于修改过~/.bash_profile,所以可以直接在终端输入以下代码):
mysql -u root -p
use newDatabaseName;
source /Users/lwh/Desktop/test.sql;
免费的工具。这个工具界面比较简单。
先创建数据库characterDB,然后进行连接,如下图所示:
其中3306为默认端口。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190109111404190.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1N1bnNoaW5lVGFu,size_16,color_FFFFFF,t_70
Github下载,开源免费。这个界面比较丰富。
支持主流操作系统:Windows,Linux,Mac OS X,Solaris
支持所有流行的数据: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, Teradata, MongoDB, Cassandra, Redis, etc.
本地数据库连接:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190109155304477.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1N1bnNoaW5lVGFu,size_16,color_FFFFFF,t_70
打开SQL Server 配置管理器:运行SQLServerManager10.msc命令。
SQL Server默认端口:1433
备份:数据库右击 -> 任务 -> 备份 -> 添加 -> 选择文件地址(文件类型选择所有文件) -> 依次确定
还原:新建数据库 右击 -> 任务 -> 还原 -> 数据库 -> 选项 -> 覆盖现有数据库 -> 常规 -> 源设备 -> 添加(文件类型选择全部文件,然后选择之前备份的文件) -> 还原
备份:数据库右击 -> 任务 -> 生成脚本 -> 选择特定数据库对象 -> 选择表,然后下一步 -> 高级(在最后的要编写脚本的数据的类型,选择架构和数据) -> 选择文件名,依次下一步至完成。
还原:新建数据库,文件 -> 打开 -> 文件 -> 打开对应sql文件,执行即可。
sqlite是一款轻量级数据库,是遵守ACID(指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability))的关系型数据库管理系统。在嵌入式设备中,可能只需要几百K的内存就够了。
SQLite默认是打开事务的。
android手机root之后,就可以在/data/data/包名/database/目录中查看sqlite数据库。所以,对于敏感信息,应该考虑加密。
SQLite不支持加密,所以我们针对数据库文件加密。现有两种解决方案:
①优点:
加密速度快。
程序无须变动,只针对数据进行加密。
②缺点:
来回加密,造成处理数据缓慢。
仅对数据加密,依然可以看到数据表的sql语句,可能猜测到表的作用。
③实现:
一是:对明文数据进行加密返回密文数据
二是:对密文数据进行解密返回明文数据
①优点
对整个文件进行了加密,用户通过编辑器看不到任何有用的数据。
进行数据库打开时,使用程序即可解密文件。
②缺点
需要修改sqlite源码,这个工作难度比较大。
③实现(太难,本人并没有进行实验)
a.修改sqlite源代码,追加对数据库文件进行加密的功能。
b.编译含有加密功能的程序源代码,生成各自平台需要使用的库文件。
c.将加密sqlite库文件引入各自平台中,修改数据库访问层代码。
d.进行程序的部署,测试。
Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的api。
我们往往不会直接操作SQLiteDatabase这个类,而是自己创建一个继承自SQLitOpenHelper的子类来实现数据库操作。
这样做的目的一是为了以后如果数据库升级不至于要改动太多代码,已实现封装;二则是为了我们使用更方便。
通过getWriteableDatabase和getReadableDatebase()方法生成一个数据库,并对数据库进行管理。
需要实现两个抽象方法:OnCreate和OnUpgrade。
当Android应用运行时,SQLiteOpenHelper会先检查是否已经存在数据库,如果不存在,就创建数据库,然后打开数据库,最后调用OnCreate方法,所以我们需要再OnCreate中创建表(视图等);如果数据库已存在,而版本号比上次创建的数据库版本号高,就调用OnUpgrade,用于升级。
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class MyHelper extends SQLiteOpenHelper {
private String Tag = "MyHelper";
private static String DB_NAME = "luoDB.db"; //数据库名称
public static String TABLE_NAME_TASK = "Task"; //联班任务_fra_task表名
/**super(参数1,参数2,参数3,参数4),其中参数4是代表数据库的版本,
* 是一个大于等于1的整数,如果要修改(添加字段)表中的字段,则设置
* 一个比当前的 参数4大的整数 ,把更新的语句写在onUpgrade(),下一次
* 调用
*/
public MyHelper(Context context) {
super(context, DB_NAME, null, 1);
}
//用于第一次创建数据库
@Override
public void onCreate(SQLiteDatabase db) {
//Create table
try{
String sql = "CREATE TABLE "+TABLE_NAME_TASK + "("
+ "TaskCode TEXT PRIMARY KEY,"
+ "TaskState TEXT,"
+ "TaskName TEXT"
+ ");";
db.execSQL(sql); //创建表
}catch(Exception e){
LogUtil.i(Tag, "onCreate" + e.getMessage());
}
}
//用于数据库升级
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
数据库升级增加表和删除表都不涉及数据迁移,但是修改表涉及到对原有数据进行迁移。升级的方法如下所示:
将现有表命名为临时表。
创建新表。
将临时表的数据导入新表。
删除临时表。
如果是跨版本数据库升级,可以由两种方式,如下所示:
逐级升级,确定相邻版本与现在版本的差别,V1升级到V2,V2升级到V3,依次类推。
跨级升级,确定每个版本与现在数据库的差别,为每个case编写专门升级大代码。
MyHelper类中:
public void insert(String table, String nullColumnHack, ContentValues values){
SQLiteDatabase db = this.getWritableDatabase();
db.insert(table, nullColumnHack, values);
}
参数说明:
table:表名,直接使用字符串指定;
nullColumnHack:指定null值的列,SQLite里不允许空行,使用这个参数可以指定一个列的值为null,当存入行为空时,这个列的值就被指定为null;
values:使用类似map键值对映射的数据结构ContentValues来指定插入的数据
举例:
String[] args = {
today,
content,
Boolean.toString(checked)
};
String[] column = {
"[_Date]",
"[Item]",
"[Check]"
};
//数据库中添加数据
ContentValues c = new ContentValues();
for(int i=0;i
MyHelper类中:
public void delete(String table , String whereClause , String[] whereArgs){
SQLiteDatabase db = this.getWritableDatabase();
db.delete(table, whereClause, whereArgs);
Log.d("Delete",whereClause);
}
参数说明:
table:表名;
whereClause:可选,指定删除条件,相当于SQL语句WHERE语句之后的类容,可通过?来指定参数;
whereArgs:当whereClause指定了?参数,这个字符串数组里就是?所代表的参数,个数应与?数一致;
举例:
String args[] ={
today,
content,
Boolean.toString(checked)
};
dbServices.delete("_today_plan", "[_Date]=? and [Item]=? and [Check]=?"
,args);
MyHelper类中:
public void update(String table, ContentValues values,
String whereClause, String[] whereArgs){
SQLiteDatabase db = this.getWritableDatabase();
db.update(table, values, whereClause, whereArgs);
}
参数说明:
table:表名;
values:同上,是需要修改的列和值的映射集合;
whereClause:修改的行所需符合的条件;
whereArgs:指定条件里的参数;
示例:
String args[] ={
today,
content,
Boolean.toString(!m)
};
ContentValues c = new ContentValues();
c.put("[Check]", Boolean.toString(m));
dbServices.update("_today_plan", c,"[_Date]=? and [StartTime]=? and [Item]=? and [Check]=?"
,args);
MyHelper类中:
和前面有所不同了,读取数据所用的方法是直接执行查询语句,获取游标,然后通过游标来遍历数据库,方法如下:
public Cursor read(String sql ,String[] args){
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(sql, args);
Log.d("Database",cursor.getColumnName(0));
return cursor;
}
方法说明:
请注意:在这里db获取的是只读的数据库(getReadableDatabase),而在上述三种操作里都是使用的可写数据库(getWritableDatabase);至于游标的用法此处就不再赘述,只需看一下API的名字就能掌握基本用法,但最后一定要记得将游标关闭(close)!
cursor = db.query(MyHelper.TABLE_NAME_TASK,
new String[] { "TaskCode","TaskName"}, "TaskName like ?",
new String[]{"%" + TaskName + "%"}, null, null, null);
Cursor c_test = mDatabase.query(tab_name,
new String[]{tab_field02},
tab_field02+" like '%" + str[0] + "%'", null, null, null, null);
String current_sql_sel = "SELECT * FROM "+tab_name
+" where "+tab_field02
+" like '%"+str[0]+"%'";
Cursor c_test = mDatabase.rawQuery(current_sql_sel, null);
cursor = db.query(MyHelper.TABLE_NAME_TASK,
new String[] { "TaskCode", "TaskName","TaskState"}, "TaskName like ?",
new String[]{"%" + TaskName+ "%"}, null, null,
"(case"
+ " when TaskState like '" + TaskState.STATE2 + "' then 2"
+ " when TaskState like '" + TaskState.STATE1 + "' then 1"
+ " else 3"
+ " end)"
+ ",TaskCode asc");
是指一个或多个更改数据库的扩展。例如,如果您正在创建一个记录或者更新一个记录或者从表中删除一个记录,那么您正在该表上执行事务。重要的是要控制事务以确保数据的完整性和处理数据库错误。
开源的关系数据库。
官方API:
https://www.postgresql.org/docs/10/
http://www.postgres.cn/docs/10/
CREATE TABLE stu_info(
FOREIGN KEY (ID) REFERENCES people_info (ID),
ID int8 PRIMARY KEY,
address VARCHAR (255) UNIQUE NOT NULL,
birthday TIMESTAMP NOT NULL
);
INSERT INTO "public"."config_info" (
"key",
"value"
) SELECT
'1',
'10'
WHERE
NOT EXISTS (
SELECT
1
FROM
"public"."config_info"
WHERE
KEY = '1'
);
当主键或者unique key发生冲突时,什么都不做(同时也适用于多个字段的唯一性约束):
INSERT INTO test.upsert_test(id, "name")
VALUES(1, 'm'),(2, 'n'),(4, 'c')
ON conflict(id) DO NOTHING;
PostgreSQL的触发器是数据库自动执行\指定的数据库事件发生时调用的回调函数。
注意:
针对字段触发:
CREATE TRIGGER stu_trigger AFTER INSERT
OR UPDATE OF birthday
OR DELETE ON stu_info FOR EACH ROW EXECUTE PROCEDURE stu_trigger_function (); --stu_trigger_function 为触发函数
行触发:
CREATE TRIGGER example_trigger AFTER INSERT ON COMPANY FOR EACH ROW EXECUTE PROCEDURE auditlogfunc();
DROP TRIGGER stu_trigger ON stu_info;
触发函数如下:
CREATE
OR REPLACE FUNCTION stu_trigger_function () RETURNS TRIGGER AS
$BODY$
DECLARE
_birthday TIMESTAMP;
_id int;
BEGIN
IF TG_OP = 'INSERT' THEN
SELECT birthday INTO _birthday FROM stu_info WHERE name= NEW .name AND class_id= NEW .class_id;
IF _birthday is NULL THEN
INSERT INTO stu_info ( ID, name, birthday , class_id) VALUES ( NEW . ID, NEW .name, NEW .first_occur_time, NEW .class_id) ;
ELSE IF NEW .birthday < _birthday THEN
UPDATE stu_info SET ID = NEW . ID, birthday = NEW .birthday ;
END IF ;
END IF ;
ELSE IF TG_OP = 'DELETE' THEN
DELETE FROM stu_info A WHERE A . ID = OLD . ID ; RETURN OLD ;
ELSE IF TG_OP = 'UPDATE' THEN
if UPDATE(birthday ) THEN
SELECT ID,birthday INTO _id, _birthday FROM stu_info WHERE class_id= OLD .class_id AND name= OLD .name;
IF ( _id != 0 AND _birthday > OLD .birthday ) THEN
UPDATE stu_info SET ID = _id, birthday = _birthday ;
END IF ;
END IF;
END IF ;
END IF ;
END IF ;
RETURN NEW;
END ;
$BODY$
LANGUAGE plpgsql;
drop FUNCTION add_stu_trigger();
序列对象(也叫序列生成器)就是用CREATE SEQUENCE 创建的特殊的单行表。一个序列对象通常用于为行或者表生成唯一的标识符。通常用于表的主键自增。
也可以
将id类型设置为:serial,pg会自动创建一个序列,同时将列设置为INT,默认值设置为nextval(‘序列’)。serial8会将列设置为int8(long)
create sequence seq1;
create table test (id int default nextval('seq1'), info text);
CREATE SEQUENCE
IF NOT EXISTS PUBLIC .role_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
/*修改表的id属性为自增*/
CREATE SEQUENCE user_info
START WITH 1 --序列开始值
INCREMENT BY 1 --递增值
NO MINVALUE
NO MAXVALUE
CACHE 1;
--给表添加自增属性
alter table user_info
alter column id set default nextval('user_info_id_seq');
alter table user add column if not exists age int4 not null default 1;
--将下一次的自增值设置成最大id+1
select setval('user_info_id_seq',(select max(id)+1 from user_info));
函数 | 函数说明 | 举例 | 备注 |
---|---|---|---|
to_char | 日期转为格式化字符串 | to_char(time,'YYYY-MM-DD hh24:mi:ss') as time1 |
|
to_date | |||
to_timestamp | |||
now() | 获取当前时间 | select now() ,或者通过now()控制返回格式: select now()::timestamp(0)without time zone |
包括时区,秒也保留到了6位小数 2014-12-24 09:28:31.545145+08 |
current_timestamp } | 获取当前时间 | 和now()一样 | |
current_time | 获取当前时间,不包括日期 | select current_time |
09:32:02.039705+08 |
current_date | 获取当前日期 | select current_date |
‘2014-12-24’ |
1.比较:date、timestamp、long可以通过>=、between and来比较
2.计算
WHERE
create_time BETWEEN (
CURRENT_TIMESTAMP - INTERVAL '3 hour' --日期计算
)
AND CURRENT_TIMESTAMP
postgresql支持两种json数据类型:json和jsonb。
主要区别在于效率:json类型存储快,使用慢;jsonb类型存储稍慢,使用较快。
json是对输入的完整拷贝,使用时再去解析,所以它会保留输入的空格,重复键以及顺序等。
jsonb是解析输入后保存的二进制,它在解析时会删除不必要的空格和重复的键,顺序和输入可能也不相同。使用时不用再次解析。
如果&&右边包含左边,那么返回true
array["+String.join(",",classId)+"] && class_id
class_id 为jsonb 格式:{1},{1, -1}, 上述取出所有class_id包含classId种的一个或几个。相当于:(class_id@> array[-1] or class_id@>ARRAY[1])
--又找到一个好的方案,主要用于参数注入,防止sql注入
'{ 1 }':: int[] && class_id
在其他图模型中称作“点”、“顶点”、“对象”。
语法:
节点必须包含在括号 () 内;
节点可以有属性:(n:Label {prop: 'value'})
在其他图模型中也称作“边”、“弧”、“线”。关系拥有类型,关系在创建时必须指定方向 ,关系在查询时可以不指定方向表示双向关系。
语法:
关系两端各有一个短横线“-”,用方括包含关系类型,关系类型名前面必须有冒号 ( 。在其中一端用 >或 < 代表关系的方向,也可以没有方向:
- - ,<- -,- ->
-[:DIRECTED]- ->
关系也可以有属性:-[:KNOWS {since: 2010}]
可以定义在节点和关系上。
语法:
包含在{}中。
代表节点的类别,节点可以没有标签或者有多个标签。
标签对节点进行分类,似关系数据库中的表 标签对节点进行分类,类似关系数据库中的表。
语法:
标签名前必须有冒号;
模式是由关系连接起来的节点构成的表达式。
() -[] -() #没有方向的关系
() -[] ->() #有方向的关系
()< -[] -() #双向的关系
(n:Label {prop:'value'})-[:TYPE]- >(m:Label)
Neo4j图形数据库的查询语言是Cypher(CQL), CQL看似简单,但由于图的结构可能在实际应用中比较复杂。
CQL命令 | 用法 |
---|---|
CREATE创建 | 创建节点,关系和属性 |
MATCH匹配 | 检索有关节点,关系和属性数据 |
RETURN返回 | 返回查询结果 |
WHERE哪里 | 提供条件过滤检索数据 |
DELETE删除 | 删除节点和关系 |
REMOVE移除 | 删除节点和关系的属性 |
ORDER BY以…排序 | 排序检索数据 |
SET组 | 添加或更新标签 |
limit 10 | 只显示10条数据 |
MATCH (m:Movie) #Movie为标签,m为节点变量
RETURN m, m.title #属性以{variable}.{property_key}的方式访问 .title返回属性
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie) #r是变量,保存关系;ACTED_IN为关系类型
RETURN p, r, m
MATCH path = (:Person)-[:ACTED_IN]->(:Movie) #path是变量,保存路径
RETURN path
函数 | 用法 |
---|---|
String字符串 | 用于使用String字面量。 |
Aggregation聚合 | 用于对CQL查询结果执行一些聚合操作。 |
Relationship关系 | 用于获取关系的细节,如startnode,endnode等。 |