对于复杂的查询,在多次使用后,维护是一件非常麻烦的事情
解决:定义视图
视图本质就是对查询的一个封装,虚拟的表,一旦封装的内容改变了,视图的内容也随着用
定义一个视图
create view zhengdaoa(视图名) as
select students.*,scores.score from scores
inner join students on scores.stuid=students.id;
下面这个查询就被定义为一个视图,在我们下次使用时直接调用视图就可以了,有点像面向对象里面的调用方法。
视图的用途就是查询
select * from stuscore;
就如图所示,直接调用视图,不用再写sql语句,这样避免多次使用相同sql语句,简化了代码。
drop view 视图名称;
1.提高了重用性,就像一个函数
2.对数据库重构,却不影响程序的运行
3.提高了安全性能,可以对不同的用户
4.让数据更加清晰
事务广泛的运用于订单系统、银行系统等多种场景,事务只对增删改有效
所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
例如,银行转帐工作:从一个帐号扣款并使另一个帐号增款,这两个操作要么都执行,要么都不执行。所以,应该把他们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性
1.原子性:一组事务,要么成功;要么撤回。
2.稳定性 :有非法数据(外键约束之类),事务撤回。
3.隔离性:事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。
4.可靠性:软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit 选项 决定什么时候吧事务保存到日志里。
开启begin; 或者 start transaction;
提交commit;
回滚rollback;
BEGIN或START TRANSACTION;显式地开启一个事务;
COMMIT;也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改称为永久性的;
ROLLBACK;有可以使用ROLLBACK WORK,不过二者是等价的。回滚会结束用户的务,并撤销正在进行的所有未提交的修改;
SAVEPOINT identifier;SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;
RELEASE SAVEPOINT identifier;删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
ROLLBACK TO identifier;把事务回滚到标记点;
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度
索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的,如果我想找到m开头的单词呢?或者ze开头的单词呢?是不是觉得如果没有索引,这个事情根本无法完成?
1)查看索引
show index from 表名;
2)创建索引
如果指定字段是字符串,需要指定长度,建议长度与定义字段时的长度一致
字段类型如果不是字符串,可以不填写长度部分
create index 索引名称 on 表名(字段名称(长度))
3)删除索引:
drop index 索引名称 on 表名;
要注意的是,建立太多的索引将会影响更新和插入的速度,因为它需要同样更新每个索引文件。对于一个经常需要更新和插入的表格,就没有必要为一个很少使用的where字句单独建立索引了,对于比较小的表,排序的开销不会很大,也没有必要建立另外的索引。
建立索引会占用磁盘空间
在生产环境下操作数据库时,绝对不可以使用root账户连接,而是创建特定的账户,授予这个账户特定的操作权限,然后连接进行操作,主要的操作就是数据的crud
MySQL账户体系:根据账户所具有的权限的不同,MySQL的账户可以分为以下几种
1)服务实例级账号:,启动了一个mysqld,即为一个数据库实例;如果某用户如root,拥有服务实例级分配的权限,那么该账号就可以删除所有的数据库、连同这些库中的表
2)数据库级别账号:对特定数据库执行增删改查的所有操作
3)数据表级别账号:对特定表执行增删改查等所有操作
4)字段级别的权限:对某些表的特定字段进行操作
5)存储程序级别的账号:对存储程序进行增删改查的操作
账户的操作主要包括创建账户、删除账户、修改密码、授权权限等
注意:
1)进行账户操作时,需要使用root账户登录,这个账户拥有最高的实例级权限
2)通常都使用数据库级操作权限
需要使用实例级账户登录后操作,以root为例
主要操作包括:
1.查看所有用户
2.修改密码
3.删除用户
所有用户及权限信息存储在mysql数据库的user表中
查看user表的结构
desc user;
主要字段说明:
Host表示允许访问的主机
User表示用户名
authentication_string表示密码,为加密后的值
查看所有用户
select host,user,authentication_string from user;
需要使用实例级账户登录后操作,以root为例
常用权限主要包括:create、alter、drop、insert、update、delete、select(创建,修改,删除,数据的增删改查)
如果分配所有权限,可以使用all privileges
创建账户&授权
grant 权限列表 on 数据库 to ‘用户名’@’访问主机’ identified by ‘密码’;
修改权限
grant 权限名称 on 数据库 to 账户@主机 with grant option;
修改密码
使用root登录,修改mysql数据库的user表
使用password()函数进行密码加密
update user set authentication_string=password(‘新密码’) where user=’用户名’;
例:
update user set authentication_string=password(‘123’) where user=’laowang’;
注意修改完成后需要刷新权限
刷新权限:flush privileges
* 删除账户*
语法1:使用root登录
drop user ‘用户名’@’主机’;
例:
drop user ‘laowang’@’%’;
语法2:使用root登录,删除mysql数据库的user表中数据
delete from user where user=’用户名’;
例:
delete from user where user=’laowang’;
– 操作结束之后需要刷新权限
flush privileges
推荐使用语法1删除用户, 如果使用语法1删除失败,采用语法2方式
悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念。之前有写过一篇文章关于并发的处理思路和解决方案,这里我单独将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍一次吧。
悲观锁(Pessimistic Lock)
在查询的时候,锁起来,事务结束后,释放。
悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select… for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
这里需要注意的一点是不同的数据库对select for update的实现和支持都是有所区别的,例如oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,mysql就没有no wait这个选项。另外mysql还有个问题是select for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在mysql中用悲观锁务必要确定走了索引,而不是全表扫描。
乐观锁(Optimistic Lock)
查询的时候,不需要操作,更改的时候再判断。
乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。
乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。一般的做法是在需要锁的数据上增加一个版本号,或者时间戳,然后按照如下方式实现:
1. SELECT data AS old_data, version AS old_version FROM …;
2. 根据获取的数据进行业务操作,得到new_data和new_version
3. UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
* // 乐观锁获取成功,操作完成*
} else {
* // 乐观锁获取失败,回滚并重试*
}
乐观锁是否在事务中其实都是无所谓的,其底层机制是这样:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据时再次对比版本号确认与之前获取的相同,并更新版本号,即可确认这之间没有发生并发的修改。如果更新失败即可认为老版本的数据已经被并发修改掉而不存在了,此时认为获取锁失败,需要回滚整个业务操作并可根据需要重试整个过程。