一、脚本处理sql语句
-------------------------------------------------
-- 创建脚本文件: 将需要执行的sql语句,写入一个文件即可
-- 脚本文件后缀: .sql
-- 执行脚本指令: source d:\\tsSql.sql;
-- 删除子表orders
drop table if exists orders;
-- 删除customers(主表)
drop table if exists customers;
-- 创建 customers 表
create table customers(id int primary key auto_increment , name varchar(20));
-- 创建 orders 表
create table orders(id int primary key auto_increment , ordernum varchar(20)
price float,
cid int);
-- 给orders 的 cid 添加外检约束(cid必须是customers的id存在)
alter table orders add constraint foreign key (cid) references customers(id);
-- 添加数据
insert into customers (name) values ('tom');
insert into customers (name) values ('tomsen');
insert into customers (name) values ('tomsenlee');
insert into orders(ordernum, price, cid) values ('no001',100.01,1);
insert into orders(ordernum, price, cid) values ('no002',100.02,1);
insert into orders(ordernum, price, cid) values ('no003',100.03,2);
insert into orders(ordernum, price, cid) values ('no004',100.04,3);
二、关联查询(内连接,左外,右外连接)
-------------------------------------------------------------------------------
-- 内连接:无条件(笛卡尔积)
select a.* , b.* from customers a, orders b order by a.id,b.id;
select a.id as aid , a.name as aName , b.id as bid , b.ordernum as bNum from customers a , orders b order by a.id,b.id;
-- 内连接:有条件(自定义条件)
select a.* , b.* from customers a, orders b where a.id = b.cid order by a.id;
-- 外连接(左外连接 left outer join 向左看齐, 右外连接 right outer join ,向右看齐)
-- 空值自动补全,补NULL
select a.* , b.* from customers a left outer join orders b on a.id = b.cid order by a.id;
/**
* 测试内连接
*/
public static void tsInnerJoin()
{
try {
Connection conn = Ts01.getConn();
String sql = "select a.* , b.* from customers a , orders b " + "where a.id = b.cid and a.id = 1";
PreparedStatement pt = conn.prepareStatement(sql);
ResultSet set = pt.executeQuery();
while(set.next())
{
int aid = set.getInt(1);
String aName = set.getString(2);
int bid = set.getInt(3);
String bName = set.getString(4);
float bPrice = set.getFloat(5);
System.out.println(aid + "," + aName + "," + bid + "," + bName +"," + bPrice);
}
set.close();
pt.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
---------------------------------------------------------------------------------------------------------
/**
* 测试右外连接
*/
public static void tsRightOutJoin()
{
try {
Connection conn = Ts01.getConn();
String sql = "select a.* , b.* from customers a right outer join orders b " + "on a.id = b.cid and a.id = 1";
PreparedStatement pt = conn.prepareStatement(sql);
ResultSet set = pt.executeQuery();
while(set.next())
{
int aid = set.getInt(1);
String aName = set.getString(2);
int bid = set.getInt(3);
String bName = set.getString(4);
float bPrice = set.getFloat(5);
System.out.println(aid + "," + aName + "," + bid + "," + bName +"," + bPrice);
}
set.close();
pt.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
--------------------------------------------------------------------------------------------------------
/**
* 测试左外连接
*/
public static void tsLeftOutJoin()
{
try {
Connection conn = Ts01.getConn();
String sql = "select a.* , b.* from customers a left outer join orders b " + "on a.id = b.cid and a.id = 1";
PreparedStatement pt = conn.prepareStatement(sql);
ResultSet set = pt.executeQuery();
while(set.next())
{
int aid = set.getInt(1);
String aName = set.getString(2);
int bid = set.getInt(3);
String bName = set.getString(4);
float bPrice = set.getFloat(5);
System.out.println(aid + "," + aName + "," + bid + "," + bName +"," + bPrice);
}
set.close();
pt.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
三、聚集函数查询
--------------------------------------------------------------------------------
-- 1.Max/Min 最大最小值查询
select max(price) form orders; -- 查询orders表 price 列中的最大值
select min(price) form orders; -- 查询orders表 price 列中的最小值
-- 2.avg 平均值查询
select avg(price) from orders; -- 查询orders表 price 列的平均值
-- 3.count 统计数值
select count(price) from orders; -- 查询orders表 price 列的总个数
-- 4.sum 统计数值
select sum(price) from orders; -- 查询orders表 price 列的总和
-- 5.group by 分组查询最大值
select cid max(price) from orders group by cid; -- 以cid分组,并查询每组价格的最大值
-- 6.having 对分组之后的值进行过滤,where是对分组之前进行过滤
select cid max(price) from orders group by cid having max(price) > 100.07; -- 以cid分组,并查询最大值大于100.07的数据
四、OLTP / LOAP
----------------------------------------------------------
OLTP: online transaction process, 在线事务处理
OLAP: online analyze process, 在线分析处理
五、数据库的并发执行容易导致三个现象
-------------------------------------------------------------
1.脏读:读未提交 -- A事务读取了B事务改写但是未提交的数据,B事务紧接着进行回滚
2.不可重复读:同一个事务,进行多次连续相同条件的查询,由于查询期间其他事务对数据进行了update操作,导致每次结果都不同。
3.幻读:不同时刻,进行相同条件的查询,由于查询期间其他事务对数据进行了insert/delete操作,导致数据数量增加或者减少
六、事务操作的特点
------------------------------------------------------------
1.独占写锁:写操作一个时刻只能一个事务去写
2.共享读锁:同一时刻,可以多个事务去读
七、ANSI(美国国家标准机构) SQL
------------------------------------------------------------
1.
2.
3.
4.
八、隔离级别 isolation level
------------------------------------------------------------------
1. --level 1 读未提交 read uncommitted,可能导致脏读
2. --level 2 读已提交 read committed, 避免了脏读,但是依然存在不可重复读和幻读(oracle默认隔离级别)
3. --level 4 可以重复读 repeatable read, 避免了脏读和不可重复读,但是依然存在幻读(mysql默认隔离级别)
4. --level 8 串行 serializable。事务之间完整隔离。避免了脏读,不可重复读和幻读
九、设置事务隔离级别
------------------------------------------------------------------
set session transaction isolation level read uncommitted; -- session 表示设置当前会话的隔离级别为uncommitted 可读不提交,当前会话生效
set global transaction isolation level read committed; -- global 表示设置全局服务器的隔离级别为committed 可读提交,全局生效
set transaction isolation level repeatable read; -- 不写修饰默认为为下一个事务设定隔离级别为repeatable 可重复读,并且仅下一个事务期间生效
set transaction isolation level serializable; -- 不写修饰默认为为下一个事务设定隔离级别为serializable 串行化,并且仅下一个事务期间生效
十、通过mysql客户端验证事务隔离级别(开启两个服务器客户端,进行两个事务A和B)
-------------------------------------------------------------------
【脏读】
-- 事务B读取事务A修改但未提交的数据。造成事务B脏读
-- 1.设置事务B的隔离级别,可以读取未提交的数据
set transaction isolation level read uncommitted(读非提交的);
-- 2.关闭事务A的自动提交
set autocommit = 0;
-- 3.事务A进行更新操作,但不提交
update customers set name = 'jerry' where id = 1;
-- 4.事务B进行查询操作
select * from customers where id = 1; -- 此时就出现了脏读,B读取了A未提交的数据
【不可重复读】
-- 事务B在事务A对数值进行了update操作之前和之后,分别读取数值,发现数值改变
-- 1.设置事务B的隔离级别,read committed(读提交的).
set transaction isolation level read committed;
-- 2.读取数据
select * from customers where id = 1;
-- 3.开启事务A的自动提交
set autocommit = 1;
-- 4.事务A进行update操作
update customers set name = 'jerry' where id = 1;
-- 5.事务B再次执行查询
select * from customers where id = 1;
【幻读】
-- 事务B在事务A对数值进行了insert操作之前和之后,分别读表,发现表结构改变
-- 1.设置事务B的隔离级别,repeatable read(可重复读)
--- mysql中的repeatable read(可重复读)隔离级别,同时避免了不可重复读和幻读
set transaction isolation level repeatable read;
-- 2.读取数据
select * from customers where id = 1;
-- 3.开启事务A的自动提交
set autocommit = 1;
-- 4.事务A进行insert操作
insert into customers (name) values ('join');
-- 5.事务B再次执行查询
select * from customers where id = 1;
【串行化】
-- 1.事务A设置隔离级别,serializable(串行化)
set transaction isolation level serializable;
-- 2.事务A关闭自动提交
set autocommit = 0;
-- 3.事务A开启事务
start transaction;
-- 4.事务A查询
select * from customers;
-- 5.事务B进行insert操作
insert into customers (name) values ('join'); --- 发现事务B会阻塞,直到事务A进行了commit(当然如果两个事务之前没有数据交叉,共用,是不会阻塞的)
-- 6.事务A进行提交
commit;
-- 7.事务A查询
select * from customers;
/**
* 测试隔离级别--脏读--事务A
*/
@Test
public void tsDirtyRead_A()
{
try {
//建立连接
Connection conn = Ts01.getConn();
//设置隔离级别
conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
String sql = "select * from customers where id = 1";
PreparedStatement pt = conn.prepareStatement(sql);
ResultSet set = pt.executeQuery();
while(set.next())
{
String aName = set.getString(2);
System.out.println("name" + aName);
}
set.close();
pt.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
------------------------------------------------------------------------------------------------------------
/**
* 测试隔离级别--脏读--事务B
*/
@Test
public void tsDirtyRead_B()
{
try {
//建立连接
Connection conn = Ts01.getConn();
//关闭自动提交
conn.setAutoCommit(false);
//更新数据
String sql = "update customers set name = 'xxx' where id = 1";
PreparedStatement pt = conn.prepareStatement(sql);
//更新但不提交
pt.executeUpdate();
System.out.println("--------------------------");
pt.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
十二、查询列转行显示
---------------------------------------------------------------
select * from customers \G;
十三、悲观锁、乐观锁
---------------------------------------------------------------
【悲观锁】
-- 不支持并发 :serializable 就是悲观锁
-- 业务层面实现:增加一个字段 lock 0/1;
【乐观锁】
-- 支持并发,但是要判断版本之后再进行数据库操作
-- 业务层面实现: 增加一个字段,version,存放整数值。
-- 事务开启的时候查询版本号,更新数据和版本号之前先判断版本号和之前查询的是否一致,一致说明没有其事务操作数组。可以更新。否则不可以更新
十四、读操作时上写锁(我读时别人不能写)
-----------------------------------------------------------------
1.使用serializable隔离级别
2.单语句添加写锁for update -- select * from customers where id = 1 for update;
十五、查询事务的隔离级别
-----------------------------------------------------------------
select @@global.tx_isolation; //查询全局的
select @@session.tx_isolation; //查询当前会话的
select @@tx_isolation; //查询下一次事务的
十六、行级锁、表级锁
-----------------------------------------------------------------
【表级锁】
-- lock tables ..... unlock tables;
-- lock tables customers read local; //加锁,其他事务无法使用该表
-- unlock tables; //解锁