【数据库学习】数据库总结

【数据库学习】数据库总结

1,概念

1)数据库

数据库是长期存储在计算机内、有组织的、可共享的大量数据的集合。 
数据库中存储的是数据及数据之间的关系。

2)数据库数据特点

永久存储、有组织、可共享。 
(数据的最小存取单位是数据项)

3)数据库系统的特点

①数据结构化

②数据的共享性,冗余度,易扩充

③数据独立性高

数据独立性包括:物理独立性和逻辑独立性 
a)物理独立性(外模式\模式映像): 
用户程序不需要了解,应用程序要处理的只是数据的逻辑结构,这样当数据的物理存储改变了,应用程序不用改变。 
b)逻辑独立性(模式\内模式映像): 
逻辑独立性是指用户的应用程序与数据库的逻辑结构是相互独立的,即,当数据的逻辑结构改变时,用户程序也可以不变。 
逻辑数据独立性(logical data independence)是指概念模式改变,外模式和应用程序不变。在逻辑数据独立性里,数据的逻辑结构发生改变或存储关系的选择发生改变时用户不会受到影响。改变概念模式,例如增加和删除实体、增加和删除属性、增加和删除联系,不需要改变现有的外模式或重写应用程序。在DBMS中只需要修改视图的定义和映像来支持逻辑数据独立性。对用户来说,不再关心所做的修改是非常重要的。换句话说,模式经过逻辑重构之后,根据外模式构建的应用程序还是和从前一样工作。

4)概念模型(E-R模型)

①概念

概念模型的一种表示方法:实体联系方法,用E-R方法(E-R模型)来描述。 
概念模型是用于信息世界的建模,是一种信息模型,与具体的DBMS无关。且能满足用户对数据的处理要求,易于修改。 
概念模型与具体数据模型无关且容易向数据库模型转化。

实体:举行表示
属性:椭圆表示,并用直线与实体连接
联系:菱形表示,用直线与实体连接,同时在边上标上联系的类型(1:1,1:n,m:n)。
  • 1
  • 2
  • 3

一个联系转化为一个关系模式,与该联系相连的各实体的码以及联系的属性转化为关系的属性,该关系的码则有三种情况: 
若联系为1:1,则每个实体的码均是该关系的后选码。 
若联系为1:n,则关系的码为n端实体的码。 
若联系为m:n,则关系的码为诸实体码的组合。

数据库模式定义语言DDL(Data Definition Language):是用于描述数据库中要存储的现实世界实体的语言。一个数据库模式包含该数据库中所有实体的描述定义。这些定义包括结构定义、操作方法定义等。

数据库逻辑设计: 将概念设计所得到的概念模型转换为某一具体的数据模型(层次、网状、关系、面向对象).

5)关系完整性

在关系模型中,关系完整性主要是指以下三方面:

实体完整性

所谓的实体完整性就是指关系(所谓的关系就是表)的主码不能取空值; 
比如学生表的主码通常是取学号为主码

参照完整性

是指参照关系中每个元素的外码要么为空(NULL),要么等于被参照关系中某个元素的主码; 
参照关系也称为外键表,被参照关系也称为主键表。

用户定义的完整性

指对关系中每个属性的取值作一个限制(或称为约束)的具体定义。比如 性别属性只能取”男“或”女“,再就是年龄的取值范围,可以取值0-130 ,但不能取负数,因为年龄不可能是负数。

6)关系数据库规范化

目地:使结构更合理,消除存储异常,使数据冗余尽量小,便于插入、删除和更新。 
原则:遵从概念单一化“一事一地”原则,即一个关系模式描述一个实体或实体间的一种联系。 
规范的实质:概念的单一化。 
规范化的方法:将关系模式投影分解成两个或两个以上的关系模式。

2,依赖和范式

1)依赖

①部分函数依赖

设X,Y是关系R的两个属性集合,存在X→Y,若X’是X的真子集,存在X’→Y,则称Y部分函数依赖于X。

    举个例子:通过AB能得出C,通过A也能得出C,通过B也能得出C,那么说C部分依赖于AB。
  • 1

②完全函数依赖

设X,Y是关系R的两个属性集合,X’是X的真子集,存在X→Y,但对每一个X’都有X’!→Y,则称Y完全函数依赖于X。

    举个例子:通过AB能得出C,但是AB单独得不出C,那么说C完全依赖于AB.
  • 1

③传递函数依赖

设X,Y,Z是关系R中互不相同的属性集合,存在X→Y(Y !→X),Y→Z,则称Z传递函数依赖于X。

    举个例子:通过A得到B,通过B得到C,但是C得不到B,B得不到A,那么成C传递依赖于A
  • 1

④多值依赖

设R(U)是属性集U上的一个关系模式。X,Y,Z是U的子集,并且Z=U-X-Y。关系模式R(U)中多值依赖X→→Y成立,当且仅当对R(U)的任一关系r,给定的一对(x,z)值有一组Y的值,这组值仅仅决定于x值而与z值无关。

举例: 
有这样一个关系 <仓库管理员,仓库号,库存产品号> ,假设一个产品只能放到一个仓库中,但是一个仓库可以有若干管理员,那么对应于一个 <仓库管理员,库存产品号>有一个仓库号,而实际上,这个仓库号只与库存产品号有关,与管理员无关,就说这是多值依赖。

2)范式

各个范式联系: 
5NF⊂4NF⊂BCNF⊂3NF⊂2NF⊂1NF

①1NF(满足最低要求的范式:字段不可再分,原子性)

如果一个关系模式R的所有属性都是不可分的基本数据项,则R∈1NF。 
自我理解1NF就是无重复的列。 
如:(X1,X2)→X3,X2→X3 其中x3对x2部分依赖 
如:(X1,X2)→X3,X2→X4 其中有非主属性X4部分依赖于候选键{X1,X2},所以这个关系模式不为第二范式;又因为范式之间的关系满足1NF⊇2NF⊇3NF ⊇ BCNF,所以是第一范式。

②2NF(消除部分子函数依赖:一个表只能说明一个事物)

若R∈1NF,且每一个非主属性完全函数依赖于码,则R∈2NF。 
即要求数据库表中的每个实例或行必须可以被唯一地区分。

③3NF(消除传递依赖,即消除非主属性对键的传递依赖:每列都与主键有直接关系,不存在传递依赖。任何非主属性不依赖于其它非主属性。)

若R∈3NF,则每一个非主属性既不部分依赖于码,也不传递依赖于码。 
自我理解是:表中所有的数据元素不但要能唯一地被主键所标识,而且他们之间还必须相互独立,不存在其他的函数关系。

④BCNF(修正第三范式、扩充第三范式 消除主属性对键的传递依赖)

所有非主属性对每一个码都是完全函数依赖; 
所有主属性对每一个不包含它的码,也是完全函数依赖; 
没有任何属性完全函数依赖于非码的任何一组属性。

⑤4NF

关系模式R

3,数据库平台

数据库管理系统(DBMS):是系统软件,是数据库系统的核心。 
常见数据库管理系统有:Access、mysql、sql server

1)Access

2)mysql

①通信协议

MySQL实现了四种通信协议:

i>TCP/IP协议

通常我们通过来连接MySQL,各种主要编程语言都是根据这个协议实现了连接模块

ii>Unix Socket协议

这个通常我们登入MySQL服务器中使用这个协议,因为要使用这个协议连接MySQL需要一个物理文件,文件的存放位置在配置文件中有定义,值得一提的是,这是所有协议中最高效的一个。

iii>Share Memory协议(共享内存协议)

这个只有windows可以使用,使用这个协议需要在配置文件中在启动的时候使用–shared-memory参数,注意的是,使用此协议,一个host上只能有一个server,所以这个东西一般没啥用的,除非你怀疑其他协议不能正常工作,实际上微软的SQL Sever也支持这个协议

iv>Named Pipes协议(命名管道协议)

这个协议也是只有windows才可以用,同shared memory一样,使用此协议,一个host上依然只能有一个server,即使是使用不同的端口也不行,Named Pipes 是为局域网而开发的协议。内存的一部分被某个进程用来向另一个进程传递信息,因此一个进程的输出就是另一个进程的输入。第二个进程可以是本地的(与第一个进程位于同一台计算机上),也可以是远程的(位于联网的计算机上)。正因为如此,假如你的环境中没有或者禁用TCP/IP环境,而且是windows服务器,那么好歹你的数据库还能工作。使用这个协议需要在启动的时候添加–enable-named-pipe选项

3)sql server

①应用

打开SQL Server 配置管理器:运行SQLServerManager10.msc命令。 
SQL Server默认端口:1433

4)android之sqlite

①概念

sqlite是一款轻量级数据库,是遵守ACID(指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability))的关系型数据库管理系统。在嵌入式设备中,可能只需要几百K的内存就够了。 
SQLite默认是打开事务的。

②安全性

android手机root之后,就可以在/data/data/包名/database/目录中查看sqlite数据库。所以,对于敏感信息,应该考虑加密。

SQLite不支持加密,所以我们针对数据库文件加密。现有两种解决方案:

i>对数据库中的数据进行加密

①优点: 
加密速度快。 
程序无须变动,只针对数据进行加密。 
②缺点: 
来回加密,造成处理数据缓慢。 
仅对数据加密,依然可以看到数据表的sql语句,可能猜测到表的作用。 
③实现: 
一是:对明文数据进行加密返回密文数据 
二是:对密文数据进行解密返回明文数据

ii>对数据库文件进行加密

①优点 
对整个文件进行了加密,用户通过编辑器看不到任何有用的数据。 
进行数据库打开时,使用程序即可解密文件。 
②缺点 
需要修改sqlite源码,这个工作难度比较大。 
③实现(太难,本人并没有进行实验) 
a.修改sqlite源代码,追加对数据库文件进行加密的功能。 
b.编译含有加密功能的程序源代码,生成各自平台需要使用的库文件。 
c.将加密sqlite库文件引入各自平台中,修改数据库访问层代码。 
d.进行程序的部署,测试。

③SQLiteDatabase

Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的api。

④SQLitOpenHelper

我们往往不会直接操作SQLiteDatabase这个类,而是自己创建一个继承自SQLitOpenHelper的子类来实现数据库操作。 
这样做的目的一是为了以后如果数据库升级不至于要改动太多代码,已实现封装;二则是为了我们使用更方便。 
通过getWriteableDatabase和getReadableDatebase()方法生成一个数据库,并对数据库进行管理。

i>在AndroidManifest.xml中添加权限

    <!-- 在SDCard中创建与删除文件权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />    
    <!-- 往SDCard写入数据权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • 1
  • 2
  • 3
  • 4

ii>添加继承SQLiteOpenHelper的MyHeper类,用于创建使用数据库。

需要实现两个抽象方法: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) {
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

iii>SQLite升级

数据库升级增加表和删除表都不涉及数据迁移,但是修改表涉及到对原有数据进行迁移。升级的方法如下所示:

将现有表命名为临时表。
创建新表。
将临时表的数据导入新表。
删除临时表。
  • 1
  • 2
  • 3
  • 4

如果是跨版本数据库升级,可以由两种方式,如下所示:

逐级升级,确定相邻版本与现在版本的差别,V1升级到V2,V2升级到V3,依次类推。
跨级升级,确定每个版本与现在数据库的差别,为每个case编写专门升级大代码。
  • 1
  • 2

iv>数据的增——insert

MyHelper类中:

public void insert(String table, String nullColumnHack, ContentValues values){
    SQLiteDatabase db = this.getWritableDatabase();
    db.insert(table, nullColumnHack, values);
}
  • 1
  • 2
  • 3
  • 4

参数说明: 
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<args.length;i++){
                c.put(column[i], args[i]);
            }
            dbServices.insert("_today_plan", null, c);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

v>数据的删——delete

MyHelper类中:

    public void delete(String table , String whereClause , String[] whereArgs){
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete(table, whereClause, whereArgs);
        Log.d("Delete",whereClause);
    }
  • 1
  • 2
  • 3
  • 4
  • 5

参数说明: 
table:表名; 
whereClause:可选,指定删除条件,相当于SQL语句WHERE语句之后的类容,可通过?来指定参数; 
whereArgs:当whereClause指定了?参数,这个字符串数组里就是?所代表的参数,个数应与?数一致;

举例:

String args[] ={
    today,
        content,
        Boolean.toString(checked)
};
dbServices.delete("_today_plan", "[_Date]=? and [Item]=? and [Check]=?"
,args);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

vi>数据的修改——update

MyHelper类中:

public void update(String table, ContentValues values,
        String whereClause, String[] whereArgs){
        SQLiteDatabase db = this.getWritableDatabase();
        db.update(table, values, whereClause, whereArgs);
    }
  • 1
  • 2
  • 3
  • 4
  • 5

参数说明: 
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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

vii>数据的查询——read

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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

方法说明: 
请注意:在这里db获取的是只读的数据库(getReadableDatabase),而在上述三种操作里都是使用的可写数据库(getWritableDatabase);至于游标的用法此处就不再赘述,只需看一下API的名字就能掌握基本用法,但最后一定要记得将游标关闭(close)!

④模糊查询

i>使用这种query方法%号前不能加’

            cursor = db.query(MyHelper.TABLE_NAME_TASK, 
                    new String[] { "TaskCode","TaskName"}, "TaskName like ?",
                    new String[]{"%" + TaskName + "%"}, null, null, null);      
  • 1
  • 2
  • 3

ii>使用这种query方法%号前必须加’

            Cursor  c_test = mDatabase.query(tab_name, 
                    new String[]{tab_field02},
                    tab_field02+"  like '%" + str[0] + "%'", null, null, null, null);
  • 1
  • 2
  • 3

iii>使用这种方式必须在%号前加’

            String current_sql_sel = "SELECT  * FROM "+tab_name 
                                    +" where "+tab_field02
                                    +" like '%"+str[0]+"%'";
            Cursor c_test = mDatabase.rawQuery(current_sql_sel, null);
  • 1
  • 2
  • 3
  • 4

⑤多重排序,字符串排序

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");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4,数据库语句

SQL 语言是非过程化的语言,易学习。 
SQL语言具有两种使用方式:一种是在终端交互方式下使用,称为交互式SQL; 另一种是嵌入在高级语言的程序中使用,称为嵌入式SQL,而这些高级语言可以是C、PASCAL、COBOL等,称为宿主语言。

1)基本对象

关系数据库系统支持 三级模式结构,其概念模式、外模式和内模式中的基本对象有表、视图和索引。 
三级模式结构有效地组织、管理数据,提高了数据库的逻辑独立性和物理独立性。使数据库达到了数据独立性。

①模式(schema,逻辑模式)

A.概念

是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图。是数据库系统模式结构的中间层,即不涉及数据的物理存储细节和硬件环境,也与具体的应用程序、开发工具及高级设计语言无关。 
模式是数据库数据在逻辑级上的视图,一个数据库只有一个模式。

也用于区分一个 大项目中的各个小项目,这样若有相同名字的表的话, 不同模式不会发生冲突。相当于编程时的命名空间。 
如: 
一个公司的系统,分2个子系统,分别为财务系统和人力资源系统. 
这2个子系统, 共用一个数据库。 
那么 财务系统的表, 可以放在财务的模式(schema). 
人力资源系统的表,放在人力资源系统的模式里面。 
这2个子系统,能够互相访问对方的表。 
但是又不因为 表重名 的问题,影响对方。

B.访问

访问具体的一个表,可以由 4个部分组成 
分别为 服务器名, 数据库名,模式名,表名。

对于访问本地的数据库: 
不指定模式名的话, 数据库默认使用dbo模式。 
(DBO是每个数据库的默认用户,具有所有者权限,即DbOwner )

②外模式(子模式,用户模式)

是数据库用户能够看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图,是与某一应用有关的数据的逻辑表示。 
外模式通常是模式的子集,一个数据库可以有多个外模式,但一个应用程序只能有一个外模式。 
外模式是保证数据库安全性的一个有力措施:用户只能访问外模式的数据,其余数据不可见。

③内模式(存储模式)

一个数据库只有一个内模式。 
内模式是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。

数据库管理系统在三级模式之间提供了两层映像: 
外模式/模式映像(保证数据的逻辑独立性) 
模式/内模式映像(保证了物理独立性)

④表

表分为临时表和永久表。

临时表

临时表存储在tempdb中(如下),当不再使用时会自动删除。

IF OBJECT_ID('tempdb..#ownerAnnouce') IS NOT NULL
  • 1

根据进程独立,只有进程的拥有者有表的访问权限,其它用户不能访问该表; 
不同的用户进程,创建的临时表虽然“名字”相同,但是这些表之间相互并不存在任何关系;在SQLSERVER中,通过特别的命名机制保证临时表的进程独立性。

临时表有两种类型:本地和全局。

A.本地临时表

名称以单个数字符号 (#) 打头;它们仅对当前的用户连接是可见的;当用户从 SQL Server 实例断开连接时被删除。

B.全局临时表

名称以两个数字符号 (##) 打头,创建后对任何用户都是可见的,当所有引用该表的用户从 SQL Server 断开连接时被删除。

临时表优点

真正的临时表利用了数据库临时表空间,由数据库系统自动进行维护,因此节省了表空间。并且由于临时表空间一般利用虚拟内存,大大减少了硬盘的I/O次数,因此也提高了系统效率。

临时表的创建

A. create table #临时表名 
B.select * into #临时表名 from 表名(永久表或临时表)

⑤视图

A.概念

视图是一张虚拟表,视图的字段是自定义的,视图只支持查询,查询数据来源于实体表。

B.优点

视图可以将多个复杂关联表提取信息,优化查询速度。

④索引

为了改变数据库的性能和可访问性所增加的一组辅助性数据。 
详细介绍见下文。

2)数据创建

在mysql中: 
查看数据库:

show databases;
  • 1

建库:

create database children;
  • 1

调用数据库

use children;
  • 1

建表 
主键、非空、唯一取值。

create table product
(
no char(10) primary key,
code char(10) not null unique,
online char(1),
bind  char(1)
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

外键:

foreign key(no) references product(no) //一个外键

//两个属性构成主键 这两个主键是外键
primary key(Sno,Cno),
foreign key(Sno) references Student(Sno) 
foreign key(Cno) references Course(Cno) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3)数据查询

数据库处理一个查询的步骤: 
客户端连接->查询缓存->解析器->预处理器->查询优化器->查询执行引擎->数据

1. 客户端发送一条查询给服务器;
2. 服务器先会检查查询缓存query cache,如果命中了缓存,则立即返回存储在缓存中的结果。否则进入下一阶段;
3. 服务器端进行SQL解析parsing、预处理transition,再由优化器optimization生成对应的执行计划;
4. 根据优化器生成的执行计划,调用存储引擎的API来执行分布distribution查询;
5. 将结果返回给客户端。
  • 1
  • 2
  • 3
  • 4
  • 5

①查询条件

等于:= 
不等于:<>或!= 
不大于:!> 
空值:is null,is not null 
确定集合:in,not in 
确定范围:between and,not between and 
//X BETWEEN 20 AND 30 等价的表达式是X>=20 AND X<=30

字符匹配:like,not like 模糊查询使用 
%代表任意长度(可为0)的字符串; 
_(下划线):代表任意单个字符。(汉字代表2个字符,所以一个汉字用两个下划线) 
\为转义字符

②排序查询

默认为asc:升序排列。desc:降序排序。 
单个排序:

select name,age from student order by age desc;/*desc倒序 asc表示正序*/
  • 1

多重排序:

order by 字段5,字段6 asc  //先按字段5排序,再按字段6排序
  • 1

③联表查询

     select a.title,b.type_name
     from news_table as a,name_table as b
     where a.type_id=b.type_id ;
     select 字段1,字段2,字段3,字段4 from 表
  • 1
  • 2
  • 3
  • 4

④case when then查询

--简单case函数
case sex
  when '1' then '男'
  when '2' then '女’
  else '其他' end
--case搜索函数
case when sex = '1' then '男'
     when sex = '2' then '女'
     else '其他' end  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

应用:

select (case sex
          when '1' then '男'
          when '2' then '女’
          else '其他' end)sex from student where class = 11;
  • 1
  • 2
  • 3
  • 4

⑤where、group by、having

having只能用在group by之后(即having后面紧跟组条件表达式),对分组后的结果进行筛选,筛选行(即使用having的前提条件是分组).

select class,avg(age) as age from student 
group by class 
having avg(age)>23 /*要求平均年龄大于23*/
  • 1
  • 2
  • 3

where肯定在group by 之前 
where后的条件表达式里不允许使用聚合函数,而having可以。

⑥查询语句

count:

select count(class)from student;
/*数量 因为使用了92标准,所以null不计入count*/
count(*) 跟count(1) 的结果一样,返回记录的总行数,都包括对NULL 的统计,
count(column) 是不包括NULL 的统计。
  • 1
  • 2
  • 3
  • 4
select distinct(class)from student;/*去重复,出现所有不同的内容*/
select count(distinct(class)) from student;

select avg(age) from student;/*平均数*/
select min(age) from student;
select max(age) from student;
select sum(age) from student;/*和*/

select class,avg(age) as age from student group by class order by age desc;/*对每个班级求年龄平均值*/
LEFT(“123456789”,LEN(“数据库”))/*分两步运算,第一步是运算LEN函数,结果是3。第二步针对123456789这个字符从左边开始连续取三个数*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

⑦查询功能函数

select * from student
select top 100 * from student where no=11;/*显示前100行*/
select isnull(name,'无') as name,age,class from student;/*isnull之后就无列名了 用as给列重命名*/
select name,age,class,'the name is' + name as introduce from student;/*用加号形成一个自定义列*/
select * from student where name like '%丽%';/*like模糊查询*/

select * from student where age in(21,23);/*找出所有年龄为21、23的人*/
select * from student where age not in(21,23);

select * from student where class is not null;

select * from student where class is not null or age in(21,23);
select * from student where class is not null and age in(21,23);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

⑤SQL-92 规则

是数据库的一个标准。以下代码 写在存储过程前面,表示遵从SQL-92 规则。 
SQL-92 标准要求在对空值进行等于 (=) 或不等于 (<) 比较时取值为 FALSE。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
  • 1
  • 2
  • 3
  • 4

SET ANSI_NULLS ON 
即使 column_name 中包含空值,使用 WHERE column_name = NULL 的 SELECT 语句仍返回零行。 
即使 column_name 中包含非空值,使用 WHERE column_name < NULL 的 SELECT 语句仍会返回零行。

SET QUOTED_IDENTIFIER ON 
为ON:标识符可以由双引号分隔,而文字必须由单引号分隔。 
为OFF:标识符不可加引号。

⑥多层查询 EXISTS

如果内层查询语句查询到符合条件的记录,就返回一个真值(true),否则,将返回 
一个假值(false)。

SELECT * FROM employee
WHERE EXISTS
(SELECT d_name FROM department WHERE d_id=1003);
  • 1
  • 2
  • 3

同理还有:NOT EXISTS。

4)数据更新

①数据插入

insert into tableName(no,name) values('1','kate');
insert into product values('001','001','N','N');
  • 1
  • 2

有自增长主键(id)的插入: 
i>可以把id的值设置为null或者0,这样mysql会自己做处理 
ii>手动指定需要插入的列,不插入这一个字段的数据!

②数据修改

update tableName set name = 'Tom' where name='kate';
update tableName set age = age + 1;
  • 1
  • 2

③数据列的增删

增加列:
alter table tableName add (column)columnName varchar(30) 
删除列:
alter table tableName drop (column) columnName
  • 1
  • 2
  • 3
  • 4

5)数据删除

删除表中几行:

DELETE FROM Person WHERE LastName = 'Wilson' 
  • 1

删除表中所有行,保留表、不释放空间。所删除的每行记录都会进日志,可以回滚。

DELETE FROM table_name
  • 1

删除表:删除内容和定义,释放空间

drop table user;
  • 1

删除表中所有数据,保留表、同时释放空间(速度比delete快,但是无法撤回,日志里面只记录页释放):

truncate table book;
  • 1

6)其他注意

①加中括号

列名、表名、存储过程名、函数名等都可以按需要加中括号。防止某些关键字在应用中引起歧义。

select [select] from 表名;
  • 1

7)数据库授权

①授权GRANT

    GRANT <权限>
    ON <对象类型>  <对象名>
    TO <用户>
    [WITH GRANT OPTION]  // 如果指定了WITH GRANT OPTION子句,则获得某种权限的用户还可以把这种权限再授予其他用户,允许用户传递权限,但是不允许循环授权。
  • 1
  • 2
  • 3
  • 4

举例:

例1:把查询Student表的权限授给用户U1
GRANT SELECT
ON TABLE Student
TO U1;

例2:把全部操作权限授予用户U2和U3
GRANT ALL PRIVILEGES
ON TABLE Student,Course
TO U2,U3;

例3:把查询权限授予所有用户
GRANT SELECT
ON TABLE SC
TO PUBLIC;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

③权限的收回 REVOKE

REVOKE <权限>
ON <对象类型>  <对象名>
FROM <用户>
  • 1
  • 2
  • 3

举例:

例6:收回所有用户对表sc的查询权限
REVOKE SELECT
ON TABLE SC
FROM PUBLIC;
  • 1
  • 2
  • 3
  • 4

③对用户模式的授权

由DBA(数据库管理员,Database Administrator,简称DBA)在创建用户时实现。

CREATE USER <username>
[WITH] [DBA|RESOURCE|CONNECT]
  • 1
  • 2

只有系统的超级用户才有权创建一个新的数据库用户 
新创建的用户有三种权限:DB,|RESOURCE,CONNECT

④数据库角色创建及授权

CREATE ROLE <角色名>
  • 1

给角色授权:

GRANT <权限>
ON <对象类型>  对象名
TO <角色>
  • 1
  • 2
  • 3

将一个角色授予其他的角色或用户

GRANT <角色1>
TO <角色3>
[WITH ADMIN OPTION]//如果指定了WITH ADMIN OPTION 子句,则获得某种权限的角色或用户还可以把这种权限再授予其他角色
  • 1
  • 2
  • 3

角色权限的收回

REVOKE <权限>
ON <对象类型>  <对象名>
FROM <角色>
  • 1
  • 2
  • 3

⑤DENY 拒绝账户访问

在安全系统中创建一项,以拒绝给当前数据库内的安全帐户授予权限并防止安全帐户通过其组或角色成员资格继承权限。

DENY { ALL | statement [ ,...n ] }
TO security_account [ ,...n ]
  • 1
  • 2

和授权区别: 
不授权是没有权限,但是如果这个用户属于某个角色,这个角色有了权限,那么这个用户可以从角色继承这个权限。如果选择了deny,即使这个用户属于某个具有权限的角色,他也没有权限。

8)数据类型

①uniqueidentifier

可存储16字节的二进制值,其作用与全局唯一标记符(GUID)一样。GUID是唯一的二进制数:世界上的任何两台计算机都不会生成重复的GUID值。GUID主要用于在用于多个节点,多台计算机的网络中,分配必须具有唯一性的标识符。

9)函数

①OBJECT_ID

A. 返回指定对象的对象 ID

USE master;
GO
SELECT OBJECT_ID(N'AdventureWorks.Production.WorkOrder') AS 'Object ID';
GO
  • 1
  • 2
  • 3
  • 4

B. 验证对象是否存在

USE AdventureWorks;
GO
IF OBJECT_ID (N'dbo.AWBuildVersion', N'U') IS NOT NULL
DROP TABLE dbo.AWBuildVersion;
GO
  • 1
  • 2
  • 3
  • 4
  • 5

N是显式的将非unicode字符转成unicode字符,它来自 SQL-92 标准中的 National(Unicode)数据类型,用于扩展和标准化,在这里可以不用,写作object_id(PerPersonData)。

5,索引

1)概念

建立索引是加快查询速度的有效手段。 
索引建立后,系统在存取数据时会自动选择合适的索引作为存取路径,用户不能显示的选择索引。

①唯一索引

在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中不可以重复。 
MySQL 在处理主键约束以及唯一性约束时,考虑周全。数据库用户创建主键约束的同时, MySQL 自动创建主索引( primary index ),且索引名称为 Primary ; 
数据库用户创建唯一性索引时, MySQL 自动创建唯一性索引( unique index ),默认情况下,索引名为唯一性索引的字段名。

②非唯一索引

在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中可以重复,不要求唯一。

③聚集索引(聚簇索引)

i>概念

表中记录的物理顺序与键值的索引顺序相同。一个表只能有一个聚集索引。

ii>优缺点

优点: 
查询速度快,因为一旦具有第一个索引值的记录被找到,具有连续索引值的记录也一定物理的紧跟其后。 
缺点: 
对表进行修改速度较慢,这是为了保持表中的记录的物理顺序与索引的顺序一致,而把记录插入到数据页的相应位置,必须在数据页中进行数据重排,降低了执行速度。在插入新记录时数据文件为了维持B+Tree 的特性而频繁的分裂调整,十分低效。

iii>聚集索引和非聚集索引的区别?

a) 聚集索引和非聚集索引的根本区别是表中记录的物理顺序和索引的排列顺序是否一致。 
b) 聚集索引和非聚集索引都采用了B+树的结构,但非聚集索引的叶子层并不与实际的数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针的方式。聚集索引的叶节点就是数据节点,而非聚集索引的叶节点仍然是索引节点。 
c) 非聚集索引添加记录时,不会引起数据顺序的重组。

iii>场景

A.某列包含了小数目的不同值。 
B.排序和范围查找。

④联合索引(组合索引)

基于多个字段而创建的索引就称为组合索引。

create index idx1 on table1(col1,col2,col3) //创建
  • 1

组合索引查询:最左前缀原则,即最左优先。 
组合索引的第一个字段必须出现在查询组句中,这个索引才会被用到。只要组合索引最左边第一个字段出现在Where中,那么不管后面的字段出现与否或者出现顺序如何,MySQL引擎都会自动调用索引来优化查询效率。

2)优缺点

①缺点

增加了数据库的存储空间; 
在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。

②优点

i>保证数据库每一行的唯一性

通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。

ii>加快数据的检索速度

这也是创建索引的最主要的原因。

iii>加速表和表之间的连接

特别是在实现数据的参考完整性方面特别有意义。

iv>减少查询中分组和排序的时间

在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

v>优化隐藏器

通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。 
优化隐藏就是指在执行查询语句、使用多表连接检索或者指定查询语句操作的对象表时,明确地指出应该使用的查询方法、连接算法或者对表的操作方式。

3)场景

应尽量避免全表扫描,首先应考虑在where 及order by ,group by 涉及的列上建立索引。

①什么时候建立的索引将失效或效率不高

(假设在字段name上建立了索引): 
i> 使用了运算符!=,以及关键字not in, not exist等,认为产生的结果集很大,往往导致引擎不走索引而是走全盘扫描 
ii> 对索引字段使用了函数,如where substr(name, 1, 3)=‘mark’, 导致索引无效 
iii> 使用like和通配符,第一个字符是%将导致索引失效,如where name like “%ark“ (如果是ark%,则可以利用索引) 
iv> order by与索引 
如果order by中的字段有建立索引,同时: 
1、该字段没有出现在where中,则在排序的时候需要正常排序,默认order by是升序排序, 故索引没有对排序产生有利帮助 。 
2、该字段同时同时出现在where中,则在获取记录后不进行排序,而是直接利用索引, 效率变高。如select a,b,c from T WHERE a='2015-10-25' ORDER BY a,b;

②索引建立原则

i>最左前缀匹配原则

mysql 会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,范围查询会导致组合索引半生效。 
比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,c 可以用到索引,d 是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d 的顺序可以任意调整。 
where 范围查询要放在最后(这不绝对,但可以利用一部分索引)。 
特别注意:and 之间的部分可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql 的查询优化器会帮你优化成索引可以识别的形式。 
where 字句有or 出现还是会遍历全表。

ii>尽量选择区分度高的字段作为索引

表的某个字段值的离散度越高,该字段越适合选作索引的关键字。 
主键字段以及唯一性约束字段适合选作索引的关键字,原因就是这些字段的值非常离散。尤其是在主键字段创建索引时, cardinality (基数,集的势)的值就等于该表的行数。 
考虑列中值的分布,列的基数越大,索引的效果越好。

iii>不在索引列做运算或者使用函数

更新频繁的字段不适合创建索引,不会出现在 where 子句中的字段不应该创建索引。

iv>尽量扩展索引,不要新建索引。

比如表中已经有a 的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

v>Where 子句中经常使用的字段应该创建索引,分组字段或者排序字段应该创建索引,两个表的连接字段应该创建索引。

vi>like 模糊查询中,只有右模糊使用索引

右模糊查询(321%)会使用索引,而%321 和%321%会放弃索引并使用全局扫描。

vii>占用存储空间少且较为固定的字段更适合选作索引

例如: 
与字符串相比,整数字段占用的存储空间较少,因此,较为适合选作索引关键字。 
与 text 类型的字段相比,char 类型的字段较为适合选作索引关键字。

6,关系运算

1)集合运算符

并(∪)、差(-)、交(∩)、笛卡尔积(×)

笛卡尔积(直积):表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。
例如,A={a,b}, B={0,1,2},则
A×B={(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}
  • 1
  • 2
  • 3

2)专门的关系运算符

①选择(限制、σ)

在关系R中选择满足给定条件的诸元组。

②投影(π)

关系R上的投影是从R中选择出若干属性列组成新的关系。 
这里写图片描述
投影之后可既改变行,又改变元组的数量。

③连接(θ连接、⋈)

从两个关系的笛卡尔积中选取属性间满足一定条件的元组。(连接由乘积(笛卡尔积)、选择、投影组成) 
分为等值连接(=)、自然连接(要求比较的分量是相同的属性组,并在结果中把重复的属性列去掉)。 
这里写图片描述

④除运算(➗)

RS÷S的意义就是:“在R和S的联系RS中,找出与S中所有的元组有关系的R元组”。

3)算术比较符

4)逻辑运算符

非与或

7,数据库完整性

1)实体完整性

主键唯一且不为空。

2)参照完整性

不允许修改外码 
级连操作:当删除或修改被参照表时,同时删除或修改参照表中的不一致元祖。

3)用户定义的完整性

4)触发器(Trigger)

是用户定义在关系表上的一类由事件驱动的特殊过程。一旦定义,任何用户对标的增删改操作均由服务器自动激活相应触发器,在DBMS核心层进行集中的完整性控制。

8,存储过程(Stored Procedure)

1)概念

存储过程是一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。

2)优点

①执行效率高

存储过程因为SQL 语句已经预编译过了,因此运行的速度比较快。

②降低了客户机和服务器之间的通信

存储过程在服务器端运行,减少客户端的压力。 
减少网络流量,客户端调用存储过程只需要传存储过程名和相关参数即可,与传输SQL 语句相比自然数据量少了很多。

③方便实施企业规则(提高了可维护性、安全性)

可以把企业规则的运算程序写成存储过程放入数据库服务器中,由RDBMS管理,既有利于集中控制,又能够方便地进行维护。 
当用户规则发生变化时,只要修改存储过程,无须修改其他应用程序。

允许模块化程序设计,就是说只需要创建一次过程,以后在程序中就可以调用该过程任意次,类似方法的复用。 
增强了使用的安全性,充分利用系统管理员可以对执行的某一个存储过程进行权限限制,从而能够实现对某些数据访问的限制,避免非授权用户对数据的访问,保证数据的安全。程序员直接调用存储过程,根本不知道表结构是什么,有什么字段,没有直接暴露表名以及字段名给程序员。

④安全性高

可设定只有某些用户才具有对指定存储过程的使用权。

3)缺点

调试麻烦(至少没有像开发程序那样容易),可移植性不灵活(因为存储过程是依赖于具体的数据库)。

4)场景

当一个事务涉及到多个SQL语句时或者涉及到对多个表的操作时就要考虑用存储过程; 
当在一个事务的完成需要很复杂的商业逻辑时(比如,对多个数据的操作,对多个状态的判断更改等)要考虑;还有就是比较复杂的统计和汇总也要考虑,但是过多的使用存储过程会降低系统的移植性。

sql尽量放在存储过程中。 
面对大量数据,用orcle比sql server稳定。

5)代码

①创建

use test1
set ansi_nulls on
go
set quoted_identifier on
go
create procedure procedure_student
    -- add the parameters for the stored procedure here
    @gradeid int,
    @gradename varchar(10) --传入的参数
as
begin
    --计算内容
end
go
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

②执行

exec dbo.procedure_student 1,'g'
  • 1

9,数据库恢复技术

1)事务

①概念

是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。 
在关系数据库中,一个事务可以是一条SQL语句、一组SQL语句、整个程序。

事务是恢复和并发控制的基本单元。

②与程序区别

一个程序中包含多个事务。

③特性(ACID)

i>原子性(Atomic)

事务是数据库的逻辑工作单位。要么都做,要么都不做。

ii>一致性(Consistency)

事务完成时,数据必须处于一致状态,数据的完整性约束没有被破坏,事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

iii>隔离性(Isolation)

事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。

iv>持续性(永久性,Durability)

一个事务一旦提交,它对数据库的改变就是永久的,即处理结果得到固化。

④事务隔离级别

事务隔离级别由数据库系统实现。 
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们 
不会相互影响, 避免各种并发问题。 
在标准SQL规范中,定义了4个事务隔离级别(由低到高)。

i>未授权读取(读未提交read uncommitted)

允许事务读取未被其他事务提交的变更,可能有脏读,不可重复读和幻读的问题。 
比如:某时刻会话a 修改了一个数据,但还未提交,此时会话b 读取了该数据,这时会话a 回滚了事务,这就导致数据出现了不一致状态,这就是脏读。

ii>授权读取(读提交read committed)

允许事务读取已经被其他事务提交的变更,可以避免脏读,可能有不可重复读和幻读的问题。 
例如:某时刻会话a 的一个事务里查询一个数据,得到的数据是1,这时会话b 修改了该数据的值为2,并提交了,此时会话a 的事务又要读取该数据,这时的数据是2,就样就出现了同一个事务内,读的结果不一样,这就是不可重复读。

iii>可重复读取(repeatable read)(Mysql 的默认隔离级别)

确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读,可能会有幻读。

iv>序列化(serializable)

所有事务都一个接一个地串行执行。可以避免脏读,不可重复读,幻读。

10,并发控制

为了保证事务的隔离性和一致性,DBMS需要对并发操作进行正确调度。

1)并发操作带来的数据不一致性

①更新丢失

②读“脏”数据

事务T1修改数据,T2读取数据,T1由于某种原因被撤销,则数据修改回原值,但T2读取的数据是之前修改的数据,即脏数据、不正确的数据。

③不可重复读

事务T1读数据后,T2**修改**了数据,T1无法再现上一次读取的结果。

④幻读

事务T1读数据后,T2**新增或者删除**了数据,T1无法再现上一次读取的结果。

2)并发控制技术

悲观锁:封锁 
乐观锁:版本号、时间戳

3)封锁分类(悲观锁)

①共享锁(S锁、读锁)

(读取)操作创建的锁。其他用户可以并发读取数据,但任何事物都不能获取数据上的排它锁,直到已释放所有共享锁。 
若事务T对数据对象A加上S锁,则事务T只能读A;其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

②排它锁(X锁、写锁,eXclusive lock)

若事物T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。

③更新锁(U锁)

用来预定要对此页施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;当被读取的页将要被更新时,则升级为X锁;U锁一直到事务结束时才能被释放。

4)封锁问题

①活锁

i>饥饿

考虑一台打印机分配的例子,当有多个进程需要打印文件时,系统按照短文件优先的策略排序,该策略具有平均等待时间短的优点,似乎非常合理,但当短文件打印任务源源不断时,长文件的打印任务将被无限期地推迟,导致饥饿以至饿死。

ii>活锁概念

与饥饿相关的另外一个概念称为活锁,在忙式等待条件下发生的饥饿,称为活锁。

a)忙式等待:不进入等待状态的等待。 
b)阻塞式等待:进程得不到共享资源时将进入阻塞状态,让出CPU 给其他进程使用。 
c)忙等待和阻塞式等待的相同之处: 
在于进程都不具备继续向前推进的条件,不同之处在于处于忙等待的进程不主动放弃CPU,尽管CPU 可能被剥夺,因而是低效的;而处于阻塞状态的进程主动放弃CPU ,因而是高效的。

iii>举例

事务T1请求封锁R,T2请求封锁R,T3请求封锁R…… 
T1释放R之后,系统批准了T3的请求,然后是T4……请求,T2可能永远等待下去。(在整个过程中,事务T2 在不断的重复尝试获取锁R)。

iv>与死锁区别

活锁的时候,进程是不会阻塞的,这会导致耗尽CPU 资源,这是与死锁最明显的区别。 
处于活锁的实体是在不断的改变状态,所谓的“活”, 而处于死锁的实体表现为等待;活锁有一定几率解开,而死锁是无法解开的。

v>避免方式

采用先来先服务策略。

②死锁

i>概念

是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态或系统产生了死锁。

ii>举例

T1请求封锁R1,T2请求封锁R2,然后T1又请求封锁R2,T1一直等待T2释放R2,此时,T2请求封锁R1,T2将一直等待T1释放R1。

iii>死锁原因

在数据库中,产生死锁的原因主要是: 
两个或多个事务都已封锁了一些数据对象,然后又都请求其他事务已封锁的数据对象,从而出现死等待。

产生死锁的四个必要条件: 
(1) 互斥条件:一个资源每次只能被一个进程使用。 
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 
(3) 不可剥夺条件: 进程已获得的资源,在末使用完之前,不能强行剥夺。 
(4) 环路等待条件: 若干进程之间形成一种头尾相接的循环等待资源关系。 
只要系统发生了死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死 
锁。

iv>死锁预防

预防死锁的发生只需破坏死锁产生的四个必要条件之一即可。 
1) 破坏互斥条件 
如果允许系统资源都能共享使用,则系统不会进入死锁状态。但有些资源根本不能同时访问,如打印机等临界资源只能互斥使用。所以,破坏互斥条件而预防死锁的方法不太可行,而且在有的场合应该保护这种互斥性。 
2) 破坏不剥夺条件 
当一个已保持了某些不可剥夺资源的进程,请求新的资源而得不到满足时,它必须释放已经保持的所有资源,待以后需要时再重新申请。这意味着,一个进程已占有的资源会被暂时释放,或者说是被剥夺了,或从而破坏了不可剥夺条件。 
该策略实现起来比较复杂,释放已获得的资源可能造成前一阶段工作的失效,反复地申请和释放资源会增加系统开销,降低系统吞吐量。这种方法常用于状态易于保存和恢复的资源,如CPU 的寄存器及内存资源,一般不能用于打印机之类的资源。 
3) 破坏请求和保持条件 
釆用预先静态分配方法,即进程在运行前一次申请完它所需要的全部资源,在它的资源未满足前,不把它投入运行。一旦投入运行后,这些资源就一直归它所有,也不再提出其他资源请求,这样就可以保证系统不会发生死锁。 
这种方式实现简单,但缺点也显而易见,系统资源被严重浪费,其中有些资源可能仅在运行初期或运行快结束时才使用,甚至根本不使用。而且还会导致“饥饿”现象,当由于个别资源长期被其他进程占用时,将致使等待该资源的进程迟迟不能开始运行。 
4) 破坏环路等待条件 
为了破坏循环等待条件,可釆用顺序资源分配法。首先给系统中的资源编号,规定每个进程,必须按编号递增的顺序请求资源,同类资源一次申请完。也就是说,只要进程提出申请分配资源Ri,则该进程在以后的资源申请中,只能申请编号大于Ri 的资源。 
这种方法存在的问题是,编号必须相对稳定,这就限制了新类型设备的增加;尽管在为资源编号时已考虑到大多数作业实际使用这些资源的顺序,但也经常会发生作业使甩资源的顺序与系统规定顺序不同的情况,造成资源的浪费;此外,这种按规定次序申请资源的方法,也必然会给用户的编程带来麻烦。

都不好用,一般采用死锁的诊断和解除。

v>死锁的诊断和解除

a)超时法 
如果一个事务等待时间超时,则认为发生死锁。(可能误判) 
b)事务等待图法 
事务等待图是一个有向图,反映了事务的等待情况。如果图中出现回路,就表示出现了死锁。

处理方案是:选择一个处理代价最小的事务,将其撤销并释放所有锁。 
a) 从死锁进程处剥夺资源 
b) 终止部分或全部进程

5) 两段锁协议(Two-Phase Locking――2PL)

两段锁协议规定所有的事务应遵守的规则: 
① 在对任何数据进行读、写操作之前,首先要申请并获得对该数据的封锁。 
② 在释放一个封锁之后,事务不再申请和获得其它任何封锁。 
即事务的执行分为两个阶段: 
第一阶段是获得封锁的阶段,称为扩展阶段。 
第二阶段是释放封锁的阶段,称为收缩阶段。

定理:若所有事务均遵守两段锁协议,则这些事务的所有交叉调度都是可串行化的。 
对于遵守两段协议的事务,其交叉并发操作的执行结果一定是正确的。值得注意的是,上述定理是充分条件,不是必要条件。一个可串行化的并发调度的所有事务并不一定都符合两段锁协议,存在不全是2PL的事务的可串行化的并发调度。 
同时我们必须指出,遵循两段锁协议的事务有可能发生死锁。

此时事务T1 、T2同时处于扩展阶段,两个事务都坚持请求加锁对方已经占有的数据,导致死锁。 
为此,又有了一次封锁法。一次封锁法要求事务必须一次性将所有要使用的数据全部加锁,否则就不能继续执行。因此,一次封锁法遵守两段锁协议,但两段锁并不要求事务必须一次性将所有要使用的数据全部加锁,这一点与一次性封锁不同,这就是遵守两段锁协议仍可能发生死锁的原因所在。

11,常见图

DFD 数据流图(Data Flow Diagram): 
这里写图片描述
IPO 输入加工输出图(input process output) 
这里写图片描述
ER图 实体-联系图(Entity-Relationship Diagram) 
这里写图片描述

12,数据库连接

1)概念

①java连接

java应用程序可以通过JDBC或Hibernate对数据库系统进行访问。JDBC或Hibernate提供了事务控制的接口,这些接口把事务控制相关的命令发送给数据库系统,由数据库系统来控制事务的隔离级别。 
一般来说,java 应用程序访问数据库的过程是: 
①加载数据库驱动程序; 
②通过jdbc 建立数据库连接; 
③访问数据库,执行sql 语句; 
④断开数据库连接。

Hibernate

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使java程序员可以随心所欲地使用对象编程思想来操纵数据库。

JDBC(Java Data Base Connectivity,java数据库连接)

是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。 
JDBC是由一系列连接(Connection)、SQL语句(Statement)和结果集(ResultSet)构成的,其主要作用概括起来有如下3个方面: 连接(建立与数据库的连接)、查询(向数据库发起查询请求)、反馈(处理数据库返回结果)。

2)Statement

①概念

是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。Statement对象,用于执行不带参数的简单SQL语句。 
Statement 每次执行sql语句,数据库都要执行sql语句的编译 ,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement.

在JDBC应用中,应该尽可能的以PreparedStatement代替Statement。

②PreparedStatement

PreparedStatement是预编译的,优点: 
a. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。 
b. 安全性高 
有效防止Sql注入等问题。 
c. 提高性能 
对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch; 
d. 代码的可读性和可维护性。

③CallableStatement

CallableStatement接口扩展了 PreparedStatement(父接口),用来调用存储过程,它提供了对输出和输入/输出参数的支持。CallableStatement 接口还具有对 PreparedStatement 接口提供的输入参数的支持

3)应用

①config.properties配置文件

mysql连接

jdbc.driverClassName=com.mysql.jdbc.Driver  
jdbc.url=jdbc:mysql://localhost:3306/hadoop?useUnicode=true&characterEncoding=utf8  
jdbc.username=root  
jdbc.password=root  
  • 1
  • 2
  • 3
  • 4

//hadoop为数据库名。

driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc\:sqlserver\://202.200.102.1\:6666;databaseName\=IMAGE_VIDEO_DEMO;
username=sa
password=123456
  • 1
  • 2
  • 3
  • 4

②JDBC: IDEA连接SQL Server

i>下载SQL Server 2008数据库驱动文件“msbase.jar、mssqlserver.jar、msutil.jar” 
ii>导入包:File->Project Structure->Libraries导入->Modules依赖 
iii>代码如下:

package com.hankcs.hanlp.database;

import java.sql.*;

public class DBUtil {
    //这里可以设置数据库名称
    private static String URL = "jdbc:sqlserver://localhost:1433;DatabaseName=Character;";
    private static final String USER="sa";
    private static final String PASSWORD="123456";

    private static Connection conn=null;
    //静态代码块(将加载驱动、连接数据库放入静态块中)
    static{
        try {
            //1.加载驱动程序
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            //2.获得数据库的连接
            conn=(Connection) DriverManager.getConnection(URL,USER,PASSWORD);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //对外提供一个方法来获取数据库连接
    public static Connection getConnection(){
        return conn;
    }


    //测试用例
    public static void main(String[] args) throws Exception{

        //3.通过数据库的连接操作数据库,实现增删改查
        Statement stmt = conn.createStatement();
        //ResultSet executeQuery(String sqlString):执行查询数据库的SQL语句   ,返回一个结果集(ResultSet)对象。
        ResultSet rs = stmt.executeQuery("select * from Question");
        while(rs.next()){//如果对象中有数据,就会循环打印出来
            System.out.println(rs.getString("question"));
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

13,数据库安全

1)SQL注入

①概念

在SQL 语句在拼接的情况下,用户输入为一部分sql语句。

②解决方法

i> 对特殊字符进行过滤、转义或者使用预编译的sql 语句绑定变量

SQL执行时,2种方式: 
①字符串处理(拼接),然后执行SQL 
用户输入的时候,可以通过输入sql语句来进行SQL注入。 
②传参,执行SQL –>交给SQL引擎(推荐) 
用prepareStatement,参数用set 方法进行填装。

String sql= "insert into userlogin values(?,?)";
PreparedStatement ps=conn.prepareStatement(sql);
for(int i=1;i<100;i++){
ps.setInt(1, i);
ps.setInt(2, 8888);
ps.executeUpdate();
ps.close();
conn.close();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

ii> 当sql 语句运行出错时,不要把数据库返回的错误信息全部显示给用户,以防止泄漏服务器和数据库相关信息

iii>检查变量的数据类型和格式

只要是有固定格式的变量,在SQL 语句执行前,应该严格按照固定格式去检查,确保变量是我们预想的格式,这样很大程度上可以避免SQL 注入攻击。 
例如:对于where id={$id}这种形式,数据库里所有的id 都是数字,那么就应该在SQL 被执行前,检查确保变量id 是int 类型。

iv>所有的SQL 语句都封装在存储过程中

所有的SQL 语句都封装在存储过程中,这样不但可以避免SQL 注入,还能提高一些性能。

14,分布式数据库

1)概念

分布式数据库是一个物理上分散的而逻辑上集中的数据集。 
它有三大特点: 数据分布性 逻辑关联性 站点自治性

2)五个基本原则

①资源的重复性 
指分布式系统中硬件,软件以及数据的冗余配置。 
②物理上的分布性 
从硬件,软件以及数据上看都是相互独立地分布。 
③高层操作系统(或者分布式操作系统) 
高层操作系统负责对分布性的资源进行统一的控制,它使一个简单的硬件堆积转变为一个统一协调的工作系统。 
④系统的透明性 
透明性是分布式系统的灵魂,实现不同层次的透明性是分布式系统必须解决的关键问题之一。 
⑤协作的自治性 
每一节点都是一个完整的处理系统,同时又是合作的。 简而言之:分布式系统是一个多节点的,处理或数据分布的,在统一下提高综合处理能力的协作体。

3)待解决问题

不完整系统状态信息 
时间延迟 
通信的代价 
负载均衡

4)分类(从控制方式角度)

①紧耦合式DDBMS

全局控制信息放在一个称为中心站点的站点上。所有的全局访问都必须通过中心站点来确定远程数据片的位置。 
优点:容易实现数据的一致性和完整性。 
缺点:易产生访问瓶颈,系统效率不高,可靠性较差。

②联邦式DDBMS

每个站点都包含全局控制信息的一个副本,都可以接受全局访问。任何对远程数据的请求,都可以通过广播方式传播到其他节点。 
优点:具有较好的可靠性和可用性,并行性好,更容易适应旧有的系统集成和异构分布式数据库系统的建立。 
缺点:保持数据的一致性很困难,实现难度大。

③组合式DDBMS

是上述方案的折衷,它把站点分为两类,一类具有全局控制信息,称为主节点,可以接受全局任务,另一类没有全局信息,只能为主节点提供数据服务。 
优点:灵活性较好,易于实现层次控制结构。 
缺点:设计复杂。

5)分布透明性

即在分布式数据库系统中用户不必关心数据的分布情况。分为三个层次:

①分片透明性

它是分布式数据库系统的最高透明性层次,它向用户完全屏蔽了DDB的分片信息。这样的透明性保持了高水平的数据独立性。

②位置透明性

用户的应用程序不需要关心数据分片的具体存储站点,当数据库的数据片的存储站点发生改变时,只需改变对应的GRS/NRS映射就可以保持全局表示模式不发生改变

③数据模型透明性

它向用户屏蔽的只是本站点的具体数据库存储及其管理情况。 在异构的情况下,这种透明性避免了用户对不同数据模型的转换的实现。 
本地透明性是3种透明方式中最低的。

6)数据分割方法

①水平分割

把全局关系的元组分割成一些子集,这些子集被称为数据分片或段(Fragment)。 
水平分割可以通过关系运算“选择”来定义。

水平分片是对全局关系执行“选择”操作,把具有相同性质的元组进行分组,构成若干个不相交的子集.水平分片的方法可归为初级分片和导出分片两类。

②垂直分割

把全局关系按照属性组(纵向)分隔成一些数据分片或段。 
垂直分割可以通过关系运算“投影”来定义。

③混合分割

可把水平分割和垂直分割这两种方法结合起来使用,产生混合式数据分片。

④数据分片应遵循的原则

若R={R1,R2,…,Rn}满足: 
1)完整性(completeness)条件: 
如果分片 a∈R,则必有a∈Ri,i=l,2,…,n 
2)可重构(reconstructed)条件: 
R=∪ Ri,(水平分片)或R=∞Ri,(垂直分片) 
3)不相交(disjoint)条件: 
Ri∩ Rj=φ,i≠j,I,j:=1,2,…,,n(水平 分片) 
Ri∩Rj=主键属性,I,j=1,2,…,n(垂直分片)

7)分布式数据库和集中式区别

分布式(distributed)是指在多台不同的服务器中部署不同的服务模块,通过远程调用协同工作,对外提供服务。 
集群(cluster)是指在多台不同的服务器中部署相同应用或服务模块,构成一个集群,通过负载均衡设备对外提供服务。

15,数据库优化

1)优化SQL 语句

① 通过explain(查询优化神器)用来查看SQL 语句的执行效果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句。通常我们可以对比较复杂的尤其是涉及到多表的SELECT 语句,把关键字EXPLAIN 加到前面,查看执行计划。例如:explain select * from news; 
② 任何地方都不要使用select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。 
③ 不在索引列做运算或者使用函数。 
④ 查询尽可能使用limit 减少返回的行数,减少数据传输时间和带宽浪费。

2)优化表的数据类型

① 使用procedure analyse()函数对表进行分析

该函数可以对表中列的数据类型提出优化建议。能小就用小。表数据类型第一个原则是:使用能正确的表示和存储数据的最短类型。这样可以减少对磁盘空间、内存、cpu 缓存的使用。 
使用方法:select * from 表名procedure analyse();

② 对表进行拆分

通过拆分表可以提高表的访问效率。有2 种拆分方法: 
1.垂直拆分 
把主键和一些列放在一个表中,然后把主键和另外的列放在另一个表中。如果一个表中某些列常用,而另外一些不常用,则可以采用垂直拆分。 
2.水平拆分 
根据一列或者多列数据的值把数据行放到二个独立的表中。

③ 使用中间表来提高查询速度

创建中间表,表结构和源表结构完全相同,转移要统计的数据到中间表,然后在中间表上进行统计,得出想要的结果。

3)硬件优化

①CPU 的优化

选择多核和主频高的CPU。

②内存的优化

使用更大的内存。将尽量多的内存分配给MYSQL 做缓存。

③磁盘I/O 的优化

i>使用磁盘阵列

RAID 0 没有数据冗余,没有数据校验的磁盘陈列。实现RAID 0至少需要两块以上的硬盘,它将两块以上的硬盘合并成一块,数据连续地分割在每块盘上。 
RAID1 是将一个两块硬盘所构成RAID 磁盘阵列,其容量仅等于一块硬盘的容量,因为另一块只是当作数据“镜像”。 
使用RAID-0+1 磁盘阵列。RAID 0+1 是RAID 0 和RAID 1 的组合形式。它在提供与RAID 1 一样的数据安全保障的同时,也提供了与RAID 0 近似的存储性能。

ii>调整磁盘调度算法

选择合适的磁盘调度算法,可以减少磁盘的寻道时间。

4)MySQL 自身的优化

对MySQL 自身的优化主要是对其配置文件my.cnf 中的各项参数进行优化调整。如指定MySQL 查询缓冲区的大小,指定MySQL 允许的最大连接进程数等。

5)应用优化

①使用数据库连接池

②使用查询缓存

它的作用是存储select 查询的文本及其相应结果。如果随后收到一个相同的查询,服务器会从查询缓存中直接得到查询结果。查询缓存适用的对象是更新不频繁的表,当表中数据更改后,查询缓存中的相关条目就会被清空。

6)大访问量的优化

①使用优化查询的方法

(见上面)

②主从复制,读写分离

i>主从复制(master,slave):

通过配置两台(或多台)数据库的主从关系,可以将一台数据库服务器的数据更新同步到另一台服务器上。网站可以利用数据库的这一功能,实现数据库的读写分离,从而改善数据库的负载压力。一个系统的读操作远远多于写操作,因此写操作发向master,读操作发向slaves 进行操作(简单的轮循算法来决定使用哪个slave)。 
利用数据库的读写分离,Web 服务器在写数据的时候,访问主数据库(Master),主数据库通过主从复制机制将数据更新同步到从数据库(Slave),这样当Web 服务器读数据的时候,就可以通过从数据库获得数据。这一方案使得在大量读操作的Web 应用可以轻松地读取数据,而主数据库也只会承受少量的写入操作,还可以实现数据热备份,可谓是一举两得的方案。 
这里写图片描述

③负载均衡(Load Balance,简称LB)

i>概念

是一种服务器或网络设备的集群技术。负载均衡将特定的业务(网络服务、网络流量等)分担给多个服务器或网络设备,从而提高了业务处理能力,保证了业务的高可用性。负载均衡基本概念有:实服务、实服务组、虚服务、调度算法、持续性等,其常用应用场景主要是服务器负载均衡,链路负载均衡。

ii>优点

1,性能的水平扩展以 
2,避免单点故障

iii>场景

Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。

iv>分类

DNS负载均衡

DNS负载均衡技术的实现原理是在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到不同的机器上去,使得不同的客户端访问不同的服务器,从而达到负载均衡的目的。

DNS负载均衡是一种简单而有效的方法,但是它不能区分服务器的差异,也不能反映服务器的当前运行状态。

代理服务器负载均衡

使用代理服务器,可以将请求转发给内部的服务器,使用这种加速模式显然可以提升静态网页的访问速度。然而,也可以考虑这样一种技术,使用代理服务器将请求均匀转发给多台服务器,从而达到负载均衡的目的。

地址转换网关负载均衡

支持负载均衡的地址转换网关,可以将一个外部IP地址映射为多个内部IP地址,对每次TCP连接请求动态使用其中一个内部地址,达到负载均衡的目的。

协议内部支持负载均衡

除了以上这三种负载均衡方式之外,有的协议内部支持与负载均衡相关的功能,例如HTTP协议中的重定向能力等,HTTP运行于TCP连接的最高层。

NAT负载均衡NAT(Network Address Translation网络地址转换)

简单地说就是将一个IP地址转换为另一个IP地址,一般用于未经注册的内部地址与合法的、已获注册的Internet IP地址间进行转换。适用于解决Internet IP地址紧张、不想让网络外部知道内部网络结构等的场合下。

反向代理负载均衡

普通代理方式是代理内部网络用户访问internet上服务器的连接请求,客户端必须指定代理服务器,并将本来要直接发送到internet上服务器的连接请求发送给代理服务器处理。反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。反向代理负载均衡技术是把将来自internet上的连接请求以反向代理的方式动态地转发给内部网络上的多台服务器进行处理,从而达到负载均衡的目的。

混合型负载均衡

在有些大型网络,由于多个服务器群内硬件设备、各自的规模、提供的服务等的差异,可以考虑给每个服务器群采用最合适的负载均衡方式,然后又在这多个服务器群间再一次负载均衡或群集起来以一个整体向外界提供服务(即把这多个服务器群当做一个新的服务器群),从而达到最佳的性能。将这种方式称之为混合型负载均衡。此种方式有时也用于单台均衡设备的性能不能满足大量连接请求的情况下。

7)数据库分表、分区、分库

分表见上面描述。 
分区就是把一张表的数据分成多个区块,这些区块可以在一个磁盘上,也可以在不同的磁盘上,分区后,表面上还是一张表,但数据散列在多个位置,这样一来,多块硬盘同时处理不同的请求,从而提高磁盘I/O 读写性能,实现比较简单。包括水平分区和垂直分区。 
分库是根据业务不同把相关的表切分到不同的数据库中,比如web、bbs、blog 等库。

17,应用

1)服务器与服务器之间传输文件夹下的文件,一个文件夹下有10 个文件,另一个文件夹下有100 个文件,两个文件夹大小相等,问,哪个传输更快?

10 个文件更快。 
1)建立连接数更少,建立连接的开销比传输文件的开销大。 
2)文件写入磁盘,要计算文件的起始位置,文件数目少的话,这个开销就小了

猜你喜欢

转载自blog.csdn.net/qq_36178899/article/details/81605112