sql、DB、DBMS分别是什么,他们之间的关系?
DB:
DataBase (数据库,数据库实际上在硬盘上以文件的形式存在)
DBMS:
DataBase Management System(数据库管理系统,常见的有:MySQL Oracle DB2 Sybase SqlServer. . . )
SQL :
结构化查询语言,是一门标准通用的语言。标准的sql 适合于所有的数据库产品。
SQL 属于高级语言。只要能看懂英语单词的,写出来的sql 语句,可以读懂什么意思。
SQL 语句在执行的时候,实际上内部也会先进行编译,然后再执行sql 。(sql 语句的编译由DBMS完成。)
DBMS负责执行sql 语句,通过执行sql 语句来操作DB当中的数据。
DBMS - ( 执行) - > SQL - ( 操作) - > DB
什么是表?
表:table
表:table 是数据库的基本组成单元,所有的数据都以表格的形式组织,目的是可读性强。
一个表包括行和列:
行:被称为数据/ 记录( data )
列:被称为字段( column )
每一个字段应该包括哪些属性:
字段名、数据类型、相关的约束。
SQL语句怎么分类
DQL(数据查询语言): 查询语句,凡是select 语句都是DQL。
DML(数据操作语言):insert delete update ,对表当中的数据进行增删改。
DDL(数据定义语言):create drop alter ,对表结构的增删改。
TCL(事务控制语言):commit 提交事务,rollback 回滚事务。( TCL中的T是Transaction )
DCL(数据控制语言): grant 授权、revoke 撤销权限等。
MySQL的常用命令
mysql
mysql - h要访问的数据库地址 - u用户名 - p密码
show databases ; 查看有哪些数据库
create database * * * ; 创建数据库
create database * * * charactor set 字符编码集; 创建指定编码集的数据库
drop database * * * ; 删除数据库
use * * * ; 使用数据库
show tables ; 查看所有表
desc * * * ; 查看表结构
source 脚本路径,初始化/ 导入数据,注意结尾没有分号
select version( ) ; 查看数据库版本号
exit ;
/ c; 结束一条语句
建表语句:
create table 表名(
列名1 数据类型( 长度) ,
列名2 数据类型( 长度) ,
列名3 数据类型( 长度) ,
. . . . . .
)
show creat table * * ; 查看创建表语句
简单的查询语句DQL
任何一条sql 语句以“; ”结尾。sql 语句不区分大小写。
格式:
select 字段名1 , 字段名1 , 字段名3 , . . . . from 表名;
给查询结果的列重命名?
select 字段名1 , 字段名1 as 名字 from emp; (as 关键字可以省略)
注意:标准sql 语句中要求字符串使用单引号括起来。虽然mysql支持双引号,尽量别用。
查询所有字段?
select * from emp;
条件查询。
语法格式:select 字段, 字段. . . from 表名 where 条件;
等号操作符、<> 、between . . . and 、is null 、and 、or 、in ( ) 、not 、like ;
and 比or 优先级高。
in 表示为某个值
在模糊查询当中,% 代表任意多个字符,_代表任意1 个字符。
在数据库当中NULL 不是一个值,代表什么也没有,为空。
空不是一个值,不能用等号衡量。必须使用 is null 或者is not null
order by 排序:
默认值、asc - > 升序 desc - > 降序
越靠前的字段越能起到主导作用。只有当前面的字段无法完成排序的时候,才会启用后面的字段。
如果包含where 语句order by 必须放到where 后面;
分组函数( 多行处理函数) :
count; sum; avg; max; min;
注意:分组函数自动忽略空值,不需要手动的加where 条件排除空值。
记住:所有的分组函数都是对“某一组”数据进行操作的。输入多行,最终输出的结果是1 行。
而任何一个分组函数都是在group by 语句执行结束之后才会执行的。
当一条sql 语句没有group by 的话,整张表的数据会自成一组。
分组函数不可直接使用在where 子句当中,因为group by 是在where 执行之后才会执行的。
count ( * ) 和count ( 具体的某个字段) ,他们有什么区别?
count ( * ) :不是统计某个字段中数据的个数,而是统计总记录条数。(和某个字段无关)
count ( comm) : 表示统计comm字段中不为NULL 的数据总数量。
单行处理函数:
输入一行,输出一行。
重点:所有数据库都是这样规定的,只要有NULL 参与的运算结果一定是NULL 。
解决:使用ifnull( 可能为NULL 的数据, 被当做什么处理) ;属于单行处理函数。
分组查询:
group by * * ; 按照某个字段或者某些字段进行分组。
having * * ; having 是对分组之后的数据进行再次过滤。
在SQL 语句中若有group by 语句,那么在select 语句后面只能跟分组函数+ 参与分组的字段。
查询结果集的去重:
加distinct 关键字
注意:distinct 只能出现在所有字段的最前面。
完整的select 语句:
( 5 ) select 字段 ( 1 ) from 表名 ( 2 ) where . . . ( 3 ) group by . . . ( 4 ) having . . . ( 6 ) order by . . .
原则:能在where 中过滤的数据,尽量在where 中过滤,效率较高。having 的过滤是专门对分组之后的数据进行过滤的。
连接查询
连接查询的分类?
根据语法出现的年代来划分:
SQL92:一些老的DBA可能还在使用这种语法。DBA:DataBase Administrator,数据库管理员
SQL99(比较新的语法):
. . . A join B on 连接条件 where . . .
inner 和outer 可以省略。
SQL99语法结构更清晰一些:表的连接条件和后来的where 条件分离了。
根据表的连接方式来划分:
内连接:
等值连接、非等值连接、自连接
外连接:
左外连接(左连接)、右外连接(右连接)
左连接有右连接的写法,右连接也会有对应的左连接的写法。
全连接(很少用!)
什么是外连接,和内连接有什么区别?
内连接:
假设A和B表进行连接,使用内连接的话,凡是A表和B表能够匹配上的记录查询出来,这就是内连接。
AB两张表没有主副之分,两张表是平等的。
外连接:
假设A和B表进行连接,使用外连接的话,AB两张表中有一张表是主表,一张表是副表,主要查询主表中
的数据,捎带着查询副表,当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL 与之匹配。
在表的连接查询方面有一种现象被称为:笛卡尔积现象。
当两张表进行连接查询的时候,没有任何条件进行限制,最终的查询结果条数是两张表记录条数的乘积。
怎么避免笛卡尔积现象?当然是加条件进行过滤。
思考:避免了笛卡尔积现象,会减少记录的匹配次数吗?不会,次数不变。只不过显示的是有效记录。
内连接:
等值连接:最大特点是:条件是等量关系。
非等值连接:最大的特点是:连接条件中的关系是非等量关系。
自连接:最大的特点是:一张表看做两张表。自己连接自己。
外连接:
左外连接:left outer join . . 右外连接: right outer join . .
多表连接查询:
select . . . from A join B on . . . join C on 表示A先和B连接,然后A继续和C进行连接
子查询:
select 语句当中嵌套select 语句,被嵌套的select 语句是子查询。
子查询可以出现在哪里?
select . . ( select ) . . from . . ( select ) . . where . . ( select ) . .
union :可以将相同或者不同表的查询结果集相加。
limit ( 重点中的重点,以后分页查询全靠它了。) :
limit 是mysql特有的,其他数据库中没有,不通用。(Oracle中有一个相同的机制,叫做rownum)
limit 取结果集中的部分数据,这是它的作用。
语法机制:
limit startIndex, length; ( startIndex表示起始位置,从0 开始,0 表示第一条数据。length表示取几个)
limit 是sql 语句最后执行的一个环节
通用的标准分页sql :
每页显示pageSize条记录
第pageNo页:( pageNo - 1 ) * pageSize, pageSize
CRUD
创建表:
语法格式:
create table 表名( 字段名1 数据类型, 字段名2 数据类型, . . . . ) ;
表名在数据库当中一般建议以:t_或者tbl_开始。
删除表:
drop table 表名;
drop table if exists 表名;
关于MySQL当中字段的数据类型?以下只说常见的
int 整数型( java中的int )
bigint 长整型( java中的long)
float 浮点型( java中的float double )
char ( ) 定长字符串( String)
varchar ( ) 可变长字符串( StringBuffer/ StringBuilder)
date 年月日 (对应Java中的java. sql . Date 类型)
time 时分秒
datetime 年月日时分秒(最大:9999 - 12 - 31 23 :59 :59 默认为null )
timestamp 年月日时分秒(最大:2037 - 12 - 31 23 :59 :59 默认为系统当前时间)
BLOB 二进制大对象(存储图片、视频等流媒体信息) Binary Large OBject (对应java中的Object)
CLOB 字符大对象(存储较大文本) Character Large OBject(对应java中的Object)
. . . . . .
char 和varchar 怎么选择?
在实际的开发中,当某个字段中的数据长度不发生改变的时候,是定长的,例如:性别、生日等都是采用char 。
当一个字段的数据长度不确定,例如:简介、姓名等都是采用varchar 。
insert 语句插入数据
语法格式:
insert into 表名( 字段名1 , 字段名2 , 字段名3 , . . . . ) values ( 值1 , 值2 , 值3 , . . . . )
要求:字段的数量和值的数量相同,并且数据类型要对应相同。
字段可以省略不写,但是后面的value 对数量和顺序都有要求。
将查询结果插入到一张表中:insert into 表1 select * * from 表2
表的复制
语法格式:
create table 表名 as select 语句; 将查询结果当做表创建出来。
修改数据:
语法格式:
update 表名 set 字段名1 = 值1 , 字段名2 = 值2. . . where 条件;
注意:没有条件整张表数据全部更新。
删除数据?
语法格式:
delete from 表名 where 条件;
注意:没有条件全部删除。
怎么删除大表中的数据?(重点)
语法格式:
truncate table 表名;
增删改查有一个术语:CRUD操作
Create (增) Retrieve(检索) Update (修改) Delete (删除)
约束Constraint
什么是约束?
在创建表的时候,可以给表的字段添加相应的约束,目的是保证表中数据的合法性、有效性、完整性。
常见的约束有哪些呢?
非空约束( not null ) :约束的字段不能为NULL
唯一约束( unique ) :约束的字段不能重复
主键约束( primary key ) :约束的字段既不能为NULL ,也不能重复(简称PK)
外键约束( foreign key ) :. . . (简称FK)
检查约束( check ) :注意Oracle数据库有check 约束,但是mysql没有,目前mysql不支持该约束。
默认约束( default ) :给定默认值
非空约束( not null ) :
约束的字段不能为NULL
not null 约束只有列级约束。没有表级约束。
唯一性约束( unique ) :
唯一约束修饰的字段具有唯一性,不能重复。但可以为NULL 。
列级约束:一个字段添加一个约束
表级约束:多个字段联合起来添加1 个约束unique
主键约束( primary key ) :
主键的特点:不能为NULL ,也不能重复。
一张表的主键约束只能有1 个。(必须记住)
主键相关的术语?
主键约束 : primary key
主键字段 : id字段添加primary key 之后,id叫做主键字段
主键值 : id字段中的每一个值都是主键值。
主键有什么作用?
- 表的设计三范式中有要求,第一范式就要求任何一张表都应该有主键。
- 主键值是这行记录在这张表当中的唯一标识。
主键的分类?
根据主键字段的字段数量来划分:
单一主键(推荐的,常用的。)
复合主键( 多个字段联合起来添加一个主键约束) (复合主键不建议使用,因为复合主键违背三范式。)
根据主键性质来划分:
自然主键:主键值最好就是一个和业务没有任何关系的自然数。(这种方式是推荐的)
业务主键:主键值和系统的业务挂钩,例如:拿着身份证号码作为主键。(不推荐用)
最好不要拿着和业务挂钩的字段作为主键。因为以后的业务一旦发生改变的时候,主键值可能也需要
随着发生变化,但有的时候没有办法变化,因为变化可能会导致主键值重复。
mysql提供主键值自增:(非常重要。)
primary key auto_increment ;
提示:Oracle当中也提供了一个自增机制,叫做:序列(sequence)对象。
外键约束:
关于外键约束的相关术语:
外键约束: foreign key ( 本表的PK) reference 表1 ( 表1 的PK)
外键字段:添加有外键约束的字段
外键值:外键字段中的每一个值。
顺序要求:
添加数据的时候,先添加父表,在添加子表。删除数据的时候,先删除子表,再删除父表。
创建表的时候,先创建父表,再创建子表。删除表的时候,先删除子表,在删除父表。
外键值可以为NULL ?
外键可以为NULL 。
外键字段引用其他表的某个字段的时候,被引用的字段不一定是主键,但至少具有unique 约束。
存储引擎
(整个内容属于了解内容):
完整的建表语句
CREATE TABLE ` t_x` (
` id` int ( 11 ) DEFAULT NULL
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
注意:在MySQL当中,凡是标识符是可以使用飘号括起来的。最好别用,不通用。
建表的时候可以指定存储引擎,也可以指定字符集。
mysql默认使用的存储引擎是InnoDB 方式。默认采用的字符集是UTF8
什么是存储引擎呢?
存储引擎这个名字只有在mysql中存在。
Oracle中有对应的机制,但是不叫做存储引擎。Oracle中没有特殊的名字,就是“表的存储方式”
mysql支持很多存储引擎,每一个存储引擎都对应了一种不同的存储方式。
每一个存储引擎都有自己的优缺点,需要在合适的时机选择合适的存储引擎。
查看当前mysql支持的存储引擎:show engines \G
常见的存储引擎?
Engine : MyISAM
Support: YES
Comment : MyISAM storage engine
Transactions : NO
XA: NO
Savepoints: NO
MyISAM这种存储引擎不支持事务。
MyISAM是mysql最常用的存储引擎,但是这种引擎不是默认的。
MyISAM采用三个文件组织一张表:
xxx. frm(存储格式的文件)
xxx. MYD(存储表中数据的文件)
xxx. MYI(存储表中索引的文件)
优点:可被压缩,节省存储空间。并且可以转换为只读表,提高检索效率。
缺点:不支持事务。
Engine : InnoDB
Support: DEFAULT
Comment : Supports transactions , row - level locking, and foreign keys
Transactions : YES
XA: YES
Savepoints: YES
优点:支持事务、行级锁、外键等。这种存储引擎数据的安全得到保障。
表的结构存储在xxx. frm文件中
数据存储在tablespace 这样的表空间中(逻辑概念),无法被压缩,无法转换成只读。
这种InnoDB 存储引擎在MySQL数据库崩溃之后提供自动恢复机制。
InnoDB 支持级联删除和级联更新。
Engine : MEMORY
Support: YES
Comment : Hash based, stored in memory, useful for temporary tables
Transactions : NO
XA: NO
Savepoints: NO
缺点:不支持事务。数据容易丢失。因为所有数据和索引都是存储在内存当中的。
优点:查询速度最快。
以前叫做HEPA引擎。
事务(Transaction)
什么是事务?
一个事务是一个完整的业务逻辑单元,不可再分。
要想保证以上的两条DML语句同时成功或者同时失败,那么就需要使用数据库的“事务机制”。
和事务相关的语句只有:DML语句。(insert delete update )
为什么?因为它们这三个语句都是和数据库表当中的“数据”相关的。
事务的存在是为了保证数据的完整性,安全性。
事务的特性?
事务包括四大特性:ACID
A: 原子性:事务是最小的工作单元,不可再分。
C: 一致性:事务必须保证多条DML语句同时成功或者同时失败。
I:隔离性:事务A与事务B之间具有隔离。
D:持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。
关于事务之间的隔离性
事务隔离性存在隔离级别,理论上隔离级别包括4 个:
第一级别:读未提交(read uncommitted )
对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
读未提交存在脏读(Dirty Read )现象:表示读到了脏的数据。
第二级别:读已提交(read committed )
对方事务提交之后的数据我方可以读取到。
这种隔离级别解决了: 脏读现象没有了。
读已提交存在的问题是:不可重复读。
第三级别:可重复读(repeatable read )
这种隔离级别解决了:不可重复读问题。
这种隔离级别存在的问题是:读取到的数据是幻象。
第四级别:序列化读/ 串行化读(serializable )
解决了所有问题。
效率低。需要事务排队。
oracle数据库默认的隔离级别是:读已提交。
mysql数据库默认的隔离级别是:可重复读。
mysql事务默认情况下是自动提交的。 只要执行任意一条DML语句则提交一次
索引
什么是索引?有什么用?
索引就相当于一本书的目录,通过目录可以快速的找到对应的资源。
在数据库方面,查询一张表的时候有两种检索方式:
第一种方式:全表扫描
第二种方式:根据索引检索(效率很高)
索引为什么可以提高检索效率呢?其实最根本的原理是缩小了扫描的范围。
索引虽然可以提高检索效率,但是不能随意的添加索引.
因为索引也是数据库当中的对象,也需要数据库不断的维护, 是有维护成本的。
比如,表中的数据经常被修改这样就不适合添加索引,因为数据一旦修改,索引需要重新排序,进行维护。
添加索引是给某一个字段,或者说某些字段添加索引。
创建索引对象:
create index 索引名称 on 表名( 字段名) ;
删除索引对象:
drop index 索引名称 on 表名;
什么时候考虑给字段添加索引?(满足什么条件)
* 数据量庞大。(根据客户的需求,根据线上的环境)
* 该字段很少的DML操作。(因为字段进行修改操作,索引也需要维护)
* 该字段经常出现在where 子句中。(经常根据哪个字段查询)
注意:主键和具有unique 约束的字段自动会添加索引。根据主键查询效率较高。尽量根据主键检索。
查看sql 语句的执行计划:explain 关键字
索引底层采用的数据结构是:B + Tree
索引的实现原理?
通过B Tree缩小扫描范围,底层索引进行了排序,分区,索引会携带数据在表中的“物理地址”,
最终通过索引检索到数据之后,获取到关联的物理地址,通过物理地址定位表中的数据,效率是最高的。
select ename from emp where ename = 'SMITH' ;
通过索引转换为:
select ename from emp where 物理地址 = 0x3 ;
索引的分类?
单一索引:给单个字段添加索引
复合索引: 给多个字段联合起来添加1 个索引
主键索引:主键上会自动添加索引
唯一索引:有unique 约束的字段上会自动添加索引
. . . .
索引什么时候失效?
select ename from emp where ename like '%A%' ;
模糊查询的时候,第一个通配符使用的是% ,这个时候索引是失效的。
视图(view)
什么是视图?
站在不同的角度去看到数据。(同一张表的数据,通过不同的角度去看待)。
怎么创建视图?怎么删除视图?
create view myview as select empno, ename from emp;
注意:只有DQL语句才能以视图对象的方式创建出来。
drop view myview;
对视图进行CRUD,会影响到原表数据。(通过视图影响原表数据的,不是直接操作的原表)
视图的作用?
视图可以隐藏表的实现细节。保密级别较高的系统,数据库只对外提供相关的视图,
java程序员只对视图对象进行CRUD。
DBA命令
将数据库当中的数据导出:
在windows的dos命令窗口中执行:(导出整个库)
mysqldump bjpowernode> D:\bjpowernode. sql - uroot - p333
在windows的dos命令窗口中执行:(导出指定数据库当中的指定表)
mysqldump bjpowernode emp> D:\bjpowernode. sql - uroot –p123
导入数据:
create database bjpowernode;
use bjpowernode;
source D:\bjpowernode. sql
数据库设计三范式(重点内容,面试经常问)
什么是设计范式?
设计表的依据。按照这个三范式设计的表不会出现数据冗余。
三范式都是哪些?
第一范式:任何一张表都应该有主键,并且每一个字段原子性不可再分。
第二范式:建立在第一范式的基础之上,所有非主键字段完全依赖主键,不能产生部分依赖。
多对多?三张表,关系表两个外键。
第三范式:建立在第二范式的基础之上,所有非主键字段直接依赖主键,不能产生传递依赖。
一对多?两张表,多的表加外键。
提醒:在实际的开发中,以满足客户的需求为主,有的时候会拿冗余换执行速度。
一对一怎么设计?
一对一设计有两种方案:主键共享和外键唯一。
Statement和PreparedStatement的区别
Statement:
1 、存在SQL注入问题
2 、执行效率没有后者高; 这个是编译一次执行一次;
3 、Statement'不会' 在编译阶段做类型的安全检查。
PreparedStatement:
1 、解决了SQL注入问题
2 、执行效率比前者高;这个是编译一次执行N次;
3 、PreparedStatement'会' 在编译阶段做类型的安全检查。
综上所诉:
如果业务方面不需要用户SQL注入,那么就用PreparedStatement;
如果业务方面要求能够支持SQL注入,那么就必须使用Statement;
SQL注入:
用户提供的信息包含有SQL语句的关键字, 它们会参数SQL语句的编译过程导致SQL语句的原意被扭曲, 进而达到SQL注入;
解决:只要用户提供的信息不参与SQL语句的编译过程,问题就解决了!
JDBC编程六步-PreparedStatement
import java. sql. *;
import java. util. *;
public class JDBCTest {
public static void main ( String[ ] args) {
ResourceBundle bundle = ResourceBundle. getBundle ( "配置文件" ) ;
String driver = bundle. getString ( "driver" ) ;
String url = bundle. getString ( "url" ) ;
String user = bundle. getString ( "user" ) ;
String password = bundle. getString ( "password" ) ;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
Class. forName ( driver) ;
conn = DriverManager. getConnection ( url, user, password) ;
conn. setAutoCommit ( false ) ;
String sql = "select * from t_user where loginName = ? and password = ?"
ps = conn. prepareStatement ( sql) ;
ps. setString ( 1 , user) ;
ps. setString ( 2 , password) ;
rs = ps. excuteQurey ( ) ;
while ( rs. next ( ) ) {
}
conn. commit ( ) ;
} catch ( Exception e) {
if ( conn != null) {
try {
conn. rollback ( ) ;
} catch ( SQLException e1) {
e1. printStackTrace ( ) ;
}
}
e. printStackTrace ( ) ;
} finally {
6 、释放资源
if ( rs != null) {
try {
rs. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
if ( ps != null) {
try {
ps. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
if ( conn != null) {
try {
conn. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
JDBC编程六步-Statement
import java. sql. Driver;
import java. sql. DriverManager;
import java. sql. SQLException;
import java. sql. Connection;
import java. sql. Statement;
import java. util. *;
public class JDBCTest {
public static void main ( String[ ] args) {
ResourceBundle bundle = ResourceBundle. getBundle ( "配置文件" ) ;
String driver = bundle. getString ( "driver" ) ;
String url = bundle. getString ( "url" ) ;
String user = bundle. getString ( "user" ) ;
String password = bundle. getString ( "password" ) ;
Statement stmt = null;
Connection conn = null;
ResuleSet rs = null;
try {
Class. forName ( driver) ;
conn = DriverManager. getConnection ( url, user, password) ;
stmt = conn. createStatement ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( )
} catch ( ClassNotFoundException e) {
e. printStackTrace ( ) ;
} finally {
if ( rs != null) {
try {
rs. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
if ( ps != null) {
try {
ps. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
if ( conn != null) {
try {
conn. close ( ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
JDBC事务机制
1 、JDBC中的事务默认是自动提交的,什么是自动提交?
只要执行任意一条DML语句,则自动提交一次,这是JDBC默认的事务行为。
但是在实际业务中,通常都是N条DML语句共同联合才能完成的,所以必须要保证他们这些DML语句在同一个事务中同时成功或失败!
解决:
1 、调用Connection接口中的方法禁用自动提交机制
数据库操作对象. setAutoCommit ( false ) ;
2 、在事务结束的时候再手动提交数据:
数据库操作对象. commit ( ) ;
3 、如果遇到异常,需要手动回滚数据
if ( 数据库操作对象 != null) {
try {
数据库操作对象. rollback ( ) ;
} catch ( SQLException e1) {
e1. printStackTrace ( ) ;
}
}
行级锁(悲观锁)
什么是行级锁:
在select 语句后面加上 for update; 即为行级锁;
eg:
select ename, job, sal from emp where job= 'MANAGER' for update;
此语句表示:在当前事务还没结束之前,emp表中工作岗位等于MANAGER的那一行所有的数据锁定,其他事务不可以对这些数据进行修改操作。
乐观锁
多线程并发,都可以对某条记录进行悠修改,但是在那条纪录上有一个版本号,比如两条线程同时获取到了版本号为1.0 的数据,线程1 事务完成之后把版本号变成了2.0 ,线程2 操作完成发现版本号不再是1.0 ,那么它就只能回滚事务。
数据库连接池
概念:其实就是一个容器( 集合) ,存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
优点:
1. 节约资源
2. 用户访问高效
标准接口:DataSource javax. sql包下的
方法:
* 获取连接:getConnection ( )
* 归还连接:Connection. close ( ) 。
如果连接对象Connection是从连接池中获取的,那么调Connection. close ( ) 方法,则不会再关闭连接而是归还连接。
一般我们不去实现它,有数据库厂商来实现
C3P0:数据库连接池技术
Druid:数据库连接池实现技术,由阿里巴巴提供的
DBCP
1 、导入jar包:
commons- dbcp- 1.4 . jar、commons- pool- 1.5 .6 . jar同时还有数据库驱动jar包
2 、创建配置文件放到类路径下
代码:
public class DBCP {
private static DataSource ds = null;
static {
try {
Properties pro = new Properties ( ) ;
pro. load ( new FileInputStream ( "src/dbcp.properties" ) ) ;
ds = BasicDataSourceFactory. createDataSource ( pro) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
public static Connection getConnFromDBCPPool ( ) throws SQLException {
return ds. getConnection ( ) ;
}
public static void returnConnection ( ResultSet rs, Statement stmt, Connection conn) {
rs, stmt, conn分别ifn,
注意:conn如果是从连接池中获取的,那么close ( ) 方法是归还而非释放
}
}
C3P0
* 步骤:
1. 导入jar包 (两个): c3p0-0.9.5.2.jar 和 mchange-commons-java-0.2.12.jar
* 不要忘记导入数据库驱动jar包
2. 定义配置文件:
* 名称(不可变): c3p0.properties 或者 c3p0-config.xml
特别注意配置文件中的数据不要出错!!!!!!
容易出错的地方:
1、驱动包路径新旧版本cj的有无
2、url中的数据
3、密码
* 路径:直接将文件放在src目录下即可。
3. 创建核心对象 数据库连接池对象:
DataSource ds = new ComboPooledDataSource();
*如果创建对象时传入一个参数,就是指定名字的连接池
4. 获取连接: ds.getConnection();
C3P0连接池特点是:
无需再手动加载配置文件信息,底层会自动去寻找c3p0.properties 或者 c3p0-config.xml配置文件。
* 代码:
public class C3P0 {
//获取数据源
private static DataSource ds = new ComboPooledDataSource();
public static Connection getConnFromC3P0() throws SQLException {
return ds.getConnection();
}
public static void returnConnection(ResultSet rs, Statement stmt,Connection conn){
释放,归还资源
}
Druid
Druid是在DBCP的基础上实现的
步骤:
1. 导入jar包 druid- 1.0 .9 . jar
2. 定义配置文件:
* 是properties形式的
* 可以叫任意名称,可以放在任意目录下
3. 加载配置文件。Properties
4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
5. 获取连接:getConnection
* 代码:
Properties pro = new Properties ( ) ;
InputStream is = DruidDemo. class . getClassLoader ( ) . getResourceAsStream ( "druid.properties" ) ;
pro. load ( is) ;
DataSource ds = DruidDataSourceFactory. createDataSource ( pro) ;
Connection conn = ds. getConnection ( ) ;
DBUtils
Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。尤其结合连接池使用效果更为理想。
JavaBean实体类:
实体类就是把查询结果集变成对象,使之持久化,以便后续操作。
Commons DbUtils的核心是两个类一个接口:
1 、DBUtils类:
主要为关闭连接,装载JDBC驱动程序之类的常规工作提供方法,都是静态的方法。
2 、QueryRunner类:
为我们提供两个重要方法,调用方法之前需要先创建一个QueryRunner的对象。
QueryRunner qRunner= new QueryRunner ( new ComboPooledDataSource ( ) ) ;
创建对象时需要传入一个连接池的数据源,这里结合c3p0连接池来完成。
qRunner. update ( ) :支持DML操作 qRunner. query ( ) :支持DQL操作
两个方法都有多个重载,可以根据需求选择不同的重载方法。
3 、ResultSetHandler接口:
用于处理ResultSet结果集,将结果集的的数据转换成不同形式。该接口的实现类有很多:
重点掌握三个:
BeanHandler
将结果集中第一条记录封装到一个指定的javaBean中。
BeanListHandler
将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中。
ScalarHandler
它是用于单列数据查询。例如:select count ( * ) from users 操作。
ArrayHandler
将结果集中的第一条记录封装到一个Object[ ] 数组中,数组中的每一个元素就是这条记录中的每一个字段的值。
ArrayListHandler
将结果集中的每一条记录都封装到一个Object[ ] 数组中,将这些数组在封装到List集合中。
ColumnListHandler
将结果集中指定的列的字段值,封装到一个List集合中。
MapHandler
将结果集中第一条记录封装到Map集合中, Key代表列名, Value代表该列数据。
MapListHandler
将结果集中每一条记录封装到Map集合中, Key代表列名, Value代表该列数据, Map集合再存储到List集合
使用:
先导包:commons- dbutils- 1.4 . jar