大家可以加群一起学习:688160561
按存储模型分为:关系次数据库、网络次数据库、层次数据库。不同的数据库的是按不同的数据结构组织和联系的
数据结构:数据的组织形式与数据之间的联系 用ds=(D, R)其中D表示数据,R表示数据间的联系。
数据结构类型:数据结构类型分为数据的逻辑结构和数据的物理结构
逻辑结构:以数据的组织形式和联系方式,来观察数据与分析数据,不考虑存储位置
物理结构:数据在计算机存储结构
管理技术发展历程:
顺序存取 随机存取 数据共享和集中 群集、共享 数据独立 满足复杂的数据类型 管理技术发生变化:不再仅是存储和管理 需要明确存储结构,指出存取路径 不需要 数 据,而是转变为用户所需要的数据管理方式
穿孔卡片--》磁带----------》磁盘----------------》网状数据库-------------》层次数据库--->关系数据库--------》面向对象数据库--------------》数据仓库
常用的数据库分类和数据仓库
关系型数据库:oracle sqlserver mysql access
非关系型数据库分类如下:
键值存储数据库:Redis Memcached
以键值形式存储,类似哈希表,以key为切入点带入哈希函数key=func(key)(直接定址法 数据分析法 平方取中法 除留余数法 随机数法),用那种方式的哈希函数根据以下条件:1 计算哈希函数所需的时间 2 关键字的长度 3 哈希表的大小 4 关键字的分布情况5记录的查找范围,得到新的key,如果相同的key(数组地址),即冲突,处理的方法有:1 开放定址法 2再哈希法 3链地址法4建立一个公共溢出区。不同就直接访问数据。
特点:简单、易部署、高并发
文档存储数据库:mongodb couchDB
面向文档数据库会将数据以文档形式存储。每个文档都是自包含的数据单元,是一系列数据项的集合。每个数据项都有一个名词与对应值,值既可以是简单的数据类型,如字符串、数字和日期等;也可以是复杂的类型,如有序列表和关联对象。数据存储的最小单位是文档,同一个表中存储的文档属性可以是不同的,数据可以使用XML、JSON等多种形式存储。也就是逻辑结构为:文档-------》数据项-----键-----》值。数据项之间允许嵌套。
特点:比键值数据库查询效率高
列存储数据库:Hbase
把相关数据项(属性)存储在同一个列族中,不相关就放在不同的列族。
特点:用于分布式存储海量数据(分布式就是计算机网络中的不同节点间可以相互访问,同时它在自己节点上又是独立的)
图数据库:Neo4J,inforGrid
数据以图的方式存储,每个实体被视作为顶点,它们之间的关系视为边。
关系数据库中的基本概念:
简介:
安装
架构与组件
目录结构
连接组成服务器对象与对象资源管理器
启动
数据库管理:
数据库对象
数据库文件及文件组
创建数据库
获取数据库信息
删除、修改数据库
事务日志
备份与还原
数据字典
数据库设计过程基本概念:
数据库设计规范:第一范式 (属性值是不可分割的最小单元)、第二范式 (非主属性完全依赖主键,不存在部分依赖)、第三范式(非主属性仅函数依赖主键,即不存在传递依赖)
关系:二维表
元组:每一行
属性:每一列,也叫字段
属性值:行与列交会处
超键:能唯一标识元组的属性集,一个超键可由一个属性或者多个属性组合,属性中可由多余的(有它或者没有都可以构成一个超键)
候选键:与超键一样,但它不包含多余属性
主键:一个关系(表)中可以有多个候选键(可有多个属性集{{属性,属性},{属性} ),选择其中一个候选键做为主键。
外键:某一个属性集在在另一张表中是主键,但在本表中不是主键 就称为外键
主属性:在任何候选键中的属性为主属性,否则为非主属性
数据库设计流程:
E-R:实体、属性、关系 表结构 数据存储在计算机上了 当数据量达到亿万级就要优化
需求分析-----》概念结构设计-------------》逻辑设计--------》物理设计---------------------》数据库性能优化,改进读、写性能
E-R:实体-关系模型
表与表间关系:无、一对一(表A有一条记录、一对多、多对多
一对一:表A中的一条记录在表B中有一条记录与之对应。反过来,表B中的一条记录在表A中仅有一条记录与之对应。
一对多:表A中的一条记录在表B中有多条记录与之对应。反过来,表B中的一条记录在表A中仅有一条记录与之对应。
多对多:表A中的一条记录在表B中有多条记录与之对应。反过来,表B中的一条记录在表A中也有多条记录与之对应。
如果两个表之间没关系,则可以利用中间表发生关系。即中间表都有两表的外键。表A想取表B的数据可以通过中间表去取。大数据中两表之间不设外键,不发生直接关系。
数据类型
char 与nchar定长字符串。不足补空格,读写速度比varchar与nvarchar快
varchar与nvarchar 自动增长 n代表支持unicode 数据存储在表中
text与ntext保存大量文本(大于8KB),数据保存在另外空间
int smallint
double float
decimal[(p[,s])] numeric[(p[,s])]
datetime smalldatetime 'yyyy-mm-dd hh24:mi:ss'
image 位存储
binary[(n)] varbinary 二进制 大小是n+4字节
表结构
CREATE TABLE Seller IF NOT EXISTS ‘Seller'
(SaleID char(3) NOT NULL,
SaleName char(8) NOT NULL,
Sex char(2),
Birthday datetime,
HireDate datetime,
Address char(60),
Telephone char(13),
Note char(200)
)
约束: primary key foreign key default check unique auto_increment
JOIN: 如果表中有至少一个匹配,则返回行 只显示匹配的
LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行 先显示匹配 再显示左表没匹配的 右表为null
RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
FULL JOIN: 只要其中一个表中存在匹配,就返回行 不管匹配不匹配都显示
并集UNION :SELECT column1, column2 FROM table1 UNION SELECT column1, column2 FROM table2
交集JOIN :SELECT * FROM table1 AS a JOIN table2 b ON a.name=b.name
差集NOT IN :SELECT * FROM table1 WHERE name NOT IN(SELECT name FROM table2)
笛卡尔积CROSS JOIN :SELECT * FROM table1 CROSS JOIN table2 ( 与 SELECT * FROM table1,table2相同)
注意:表空间分配,表分区
表结构修改
修改的操作包括:增加或删除列、修改列的名称、数据类型、数据长度、改变表的名称等。
ALTER TABLE table_name
{ ADD column_name date_type
[DEFAULT contant_expression][IDENTITY(SEED,INCREMENT)][NULL | NOT NULL]
| DROP COLUMN column_name
| ALTER COLUMN column_name new_datetype [NULL | NOT NULL ]
}
增删改查
insert
INSERT [ INTO ] table_name [ ( column_name [,…n] ) ]
VALUES ( expression | NULL | DEFAULT [,…n] )
delete、tracate、drop
DELETE [ ( column_name [,…n] ) ] [ FROM ] table_name
[ WHERE search_conditions] 注意:没有列表示删除表中的所有数据
TRACATE table_name 删除表中所有数据,是整个表直接操作,不写入日志,速度比delete快
DROP table_name IF EXISTS TABLE_NAME把表结构和数据都删了
update
UPDATE table_name
SET column_name=expression [,…n]
[ WHERE search_conditions ]
select
SELECT [ALL| DISTINCT] [TOP n [PERCENT] select_list [计算表达式]
[ INTO new_table ] FROM [table_nameA join_type|apply_type|pivot|unpivot]| ]table_nameB
[ON |AS]
[ WHERE search_condition ]
[ GROUP BY group_by_expression ]
[ HAVING search_condition ]
[ ORDER BY order_expression [ ASC | DESC ] ]
常用的查询条件:like '张%'、 in not in 、 IS NULL IS NOT NULL、NOT 、AND 、OR、 >=、EXISTS、BETWEEN a AND b、ALL、SOME、ANY. limit 1 ,1(表示从第二条记录开始取,总共一条)
外连接与内连接和笛卡尔乘积之间关系?
注意:查询顺序是from A---->JOIN B ----> on(筛选删除是暂时的,用于添加outer外部行)-------where(帅选删除是永久的)----->group by(分组)------>having(分组条件,不满足条件就删除) ------>select计算表达式-------->distinct----->top(还没排序,只是列出多少行,数据行已经确定)---->order by(排序)---->set-----游标 每一状态结果生成一个虚拟表原来操作。
函数:
内置函数:
聚合函数:
count(*) 计算元组个数
count(列名)计算某一列中的数据的个数
COUNT DISTINCT(列名)计算某一列不同值的个数
SUM(列名)计算某一列中值个总和
AVG(列名)计算某一列值的平均数
MIN(列名)求(字符、日期、属性列)的最小值
MAX(列名)
字符串函数
数学函数
日期函数
系统函数:
转换函数:
包:包一般是是函数和存储过程的封装,包含包头和包体
包头:定义函数和存储过程
包体:函数和存储过程的实现
自定义函数:(mysql)
DELIMITER // (修改默认结束符;)
CREATE FUNCTION addTwoNumber(x SMALLINT UNSIGNED, Y SMALLINT UNSIGNED)
RETURNS SMALLINT
BEGIN
DECLARE a, b SMALLINT UNSIGNED DEFAULT 10;
SET a = x, b = y;
RETURN a+b;
END//
自定义存储过程:(mysql)
CREATE PROCEDURE procedure_name (in p_id int unsigned, out userNums int unsigned ,inout int unsigned)
BEGIN
执行体
//in表示函数被调用执行时,参数值先确定
//out表示参数值可以在存储过程体重改变,并返回
//inout表示函数被调用时先指定,可以改变和返回
//特点:预编译速度快,灵活,减少网络流量(调用传几个参数 而不是大量的sql语句),安全(设置特定用户才能使用存储过程以及传参数形式防止sql注入攻击)
//不好是,大量存储过程占用空间和维护难,重新编译高耦合
END//
游标:游标分为静态游标(结果集是对数据库数据的一个备份,对结果集进行增删改查不改变数据库中数据)和动态游标ref
静态游标分为:显示游标与隐性游标
游标操作:
BEGIN
DECLARE no_more_record INT DEFAULT 0;
DECLARE pID BIGINT(20);
DECLARE pValue DECIMAL(15,5);
DECLARE cur_record CURSOR FOR SELECT colA, colB from tableABC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_record = 1;
OPEN cur_record;
FETCH cur_record INTO pID, pValue;
WHILE no_more_record != 1 DO
INSERT INTO testTable(ID, Value)
VALUES (pID, pValue);
FETCH cur_record INTO pID, pValue;
END WHILE;
END
定义游标
DECLARE CURSOR cursor_name IS SELECT 结果集
打开游标
OPEN cursor_name
赋值变量
FETCH cursor_name INFO 行变量//fetch取当前游标指向的记录并赋值给行变量.
输出:行变量.属性(列名),即可把该记录下指定的列值输出
关闭游标
CLOSE cursor_name//关闭游标,关闭后就不能对其进行结果集操作
视图:数据库中虚拟的表 显示的数据是最新的 每次由数据库引擎(识别sql语法是否正确)通过sql语句重建
CREATE VIEW view_name AS SELECT column_names FROM table_name WHERE conditions;
事务和锁:保证数据安全
事务特点
1、事务的原子性可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit选项 决定什么时候吧事务保存到日志里。
事务具有4个属性:原子性、一致性、隔离性、持续性。这四个属性通常称为ACID特性。
原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability)。持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
事务的过期时间
事务如果在规定的时间内如果没提交完,单位秒,就强制事务回滚。
事务的读写特性
某一些对数据库操作只是读取数据库中的数据,则可以设置为只读属性,可以提高速度,
事务传播行为
谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring 支持 7 种事务传播行为:
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。
注意:mysql不支持检查约束
事务并发产生的问题
丢失更新:提交一个事务时,会把其它事务已提交的更新的数据覆盖了。
脏读:一个事务读到另一个事务未提交的更新数据。
幻读:一个事务执行两次查询,但第二次查询比第一次查询多或者少了一些数据行。
虚读:一个事务两次读同一行数据,可是这两次读到的数据不一样。
不可重复读:幻读、虚读
事务并发问题的解决:
在应用程序上解决
乐观锁
乐观锁假定当前事务操纵数据资源时,不会有其他事务同时访问该数据资源,因此不作数据库层次上的锁定。为了维护正确的数据,乐观锁使用应用程序上的版本控制(由程序逻辑来实现的)来避免可能出现的并发问题。
唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、 或者时间戳来检测更新冲突(并且防止更新丢失)。
使用版本检查(
Hibernate中通过版本号检查来实现后更新为主,这也是Hibernate推荐的方式。在数据库表中加入一个version(版本)字段,读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。就抛出异常。
使用时间戳(
跟版本检查的用法相似。
在数据库中解决
事务隔离级别
为了解决多个事务并发会引发的问题。数据库系统提供了四种事务隔离级别供用户选择。
Serializable:8串行化。隔离级别最高。
Repeatable Read:4可重复读。
Read Committed: 2读已提交数据。
Read Uncommitted:1读未提交数据。隔离级别最差。
数据库系统采用不同的锁类型来实现以上四种隔离级别,具体的实现过程对用户是透明的。用户应该关心的是如何选择合适的隔离级别。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读,而且具有较好的并发性能。
每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中可以显示地设置隔离级别。每一种隔离级别对应着一个正整数。
在hibernate.cfg.xml中设置隔离级别如下:
设置之后,在开始一个事务之前,Hibernate将为从连接池中获得的JDBC连接设置级别。需要注意的是,在受管理环境中,如果Hibernate使用的数据库连接来自于应用服务器提供的数据源,Hibernate不会改变这些连接的事务隔离级别。在这种情况下,应该通过修改应用服务器的数据源配置来修改隔离级别。
悲观锁(Pessimistic Locking)
悲观锁假定当前事务操纵数据资源时,肯定还会有其他事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源。尽管悲观锁能够防止丢失更新和不可重复读这类并发问题,但是它影响并发性能,因此应该很谨慎地使用悲观锁。
Hibernate 的加锁模式有:
LockMode.NONE :无锁机制。
LockMode.WRITE :Hibernate 在 Insert 和 Update 记录的时候会自动获取。
LockMode.READ :Hibernate 在读取记录的时候会自动获取。
以上这三种锁机制一般由 Hibernate 内部使用,如Hibernate 为了保证 Update过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE 锁。
LockMode.UPGRADE :利用数据库的 for update 子句加锁。
LockMode. UPGRADE_NOWAIT : Oracle 的特定实现,利用 Oracle 的 for update nowait 子句实现加锁。
上面这两种锁机制是我们在应用层较为常用的,加锁一般通过以下方法实现:
Criteria.setLockMode
Query.setLockMode
Session.lock
下面我们来看一下hibernateAPI中提供的两个get方法:
Get(Classclazz,Serializable id,LockMode lockMode)
Get(Classclazz,Serializable id,LockOptions lockOptions )
可以看到get方法第三个参数"lockMode"或"lockOptions",注意在Hibernate3.6以上的版本中"LockMode"已经不建议使用。方法的第三个参数就是用来设置悲观锁的,使用第三个参数之后,我们每次发送的SQL语句都会加上"for update"用于告诉数据库锁定相关数据。LockMode参数选择UPGRADE选项,就会开启悲观锁。
注意,只有在查询开始之前(也就是 Hiberate 生成 SQL 之前)设定加锁,才会真正通过数据库的锁机制进行加锁处理,否则,数据已经通过不包含 for update 子句的 Select SQL 加载进来,所谓数据库加锁也就无从谈起。
事务操作流程
开启事务事务的终止
事务模式:
设置“自动提交”模式每条SQL都是同一个事务的不同命令,之间由 COMMIT 或 ROLLBACK隔开
修改mysql隔离模式:
1.对所有的用户都有效,修改mysql.ini配置文件,在最后加上
transaction-isolation=REPEATABLE-READ(这是它的默认隔离模式,其他大多数数据库采用读已提交的)
默认情况下select是不加锁的,但update 、delete、insert加
所以查询语句想要加锁需带上for update或者select lock in lockmode share
当不加锁时,其他事务不管数据库设置什么隔离模式,都可以对该数据库表进行增删改查
当加锁时,其他事务需根据锁的性质来对表的操作,否则其他事务讲将被挂起。
比如
A事务start transaction (数据库默认单条查询语句是一个事务,autocommit,自动开始、自动提交,提交后锁就释放了),所以事务开始需要start开始,防止autocommit影响,就等于是没有加锁了。因为加完,提交释放了。
select * from user;(前面三种隔离模式默认不加锁 ,但可串行化是加共享锁的)
B事务也开始
select * from user;
update user set username="ee" where id=2;(如果A事务查询加for update(排他锁)、lock in share mode(共享锁) 事务B只能挂起了)
接着A事务执行查询时,所得到的数据就根据数据库的隔离模式有关了
如果是未提交读、得到的数据与B事务修改的一样(就算B事务不提交,也能查到B事务修改但没提交的数据)
如果是已提交读的、得到的数据与B事务更新后的数据一样(条件是B事务提交了)
如果是可重复读、得到数据是A之前的查询的,就算B修改和提交了A也查不到(第一个事务的修改对另一个事务没有影响)
接着A事务执行update user set username="cc" where id=2;(等于是给这个事务添加了共享锁,如果其他事务执行update就挂起,直到超时。但其他事务可以执行select语句,因为加了共享锁的数据,其他对象也可以获得该共享锁)
注意:由于InnoDB 预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)。
所以总的来说隔离模式就是对锁的封装。
共享锁(s):又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。(对于加x锁的事务只能读不能写,其他事务只能对该数据加s锁)
排他锁(独占锁 X):又称写锁,若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。(对于加x锁的事务能写、读,其他事务不能对该数据加任何锁)
死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象----死锁
死锁必须具备以下条件:
互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0 占用的资源。
死锁解决方法:
有序资源分配法
这种算法资源按某种规则系统中的所有资源统一编号(例如打印机为1、磁带机为2、磁盘为3、等等),申请时必须以上升的次序。系统要求申请进程:
1、对它所必须使用的而且属于同一类的所有资源,必须一次申请完;
2、在申请不同类资源时,必须按各类设备的编号依次申请。例如:进程PA,使用资源的顺序是R1,R2; 进程PB,使用资源的顺序是R2,R1;若采用动态分配有可能形成环路条件,造成死锁。
采用有序资源分配法:R1的编号为1,R2的编号为2;
PA:申请次序应是:R1,R2
PB:申请次序应是:R1,R2
这样就破坏了环路条件,避免了死锁的发生
银行算法
避免死锁算法中最有代表性的算法是Dijkstra E.W 于1968年提出的银行家算法:
该算法需要检查申请者对资源的最大需求量,如果系统现存的各类资源可以满足申请者的请求,就满足申请者的请求。这样申请者就可很快完成其计算,然后释放它占用的资源,从而保证了系统中的所有进程都能完成,所以可避免死锁的发生。
活锁:指事物1可以使用资源,但它让其他事物先使用资源;事物2可以使用资源,但它也让其他事物先使用资源,于是两者一直谦让,都无法使用资源。
活锁解决方法:
先来先服务
饥饿:是指如果事务T1封锁了数据R,事务T2又请求封锁R,于是T2等待。T3也请求封锁R,当T1释放了R上的封锁后,系统首先批准了T3的请求,T2仍然等待。然后T4又请求封锁R,当T3释放了R上的封锁之后,系统又批准了T4的请求......T2可能永远等待,这就是饥饿。
注意:活锁一般能解(高优先级),死锁不能解
共享锁 和 排它锁 的区别:在于是否阻断其他客户发出的 SELECT …… LOCK IN SHARE MODE命令索引:排序占用存储空间
触发器:保证数据正确性
在Java中使用数据库进行JDBC编程时,Java程序中通常应包含下述几部分内容:
(1) 在程序的首部用import语句将java.sql包引入程序:
import java.sql.*;
(2) 使用Class.forName( )方法加载相应数据库的JDBC驱动程序。若以加载jdbc-odbc桥为例,则相应的语句格式为:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
(3) 定义JDBC的URL对象。例如: String conURL="jdbc:odbc:TestDB";
其中TestDB是我们设置的要创建的数据源。
(4) 连接数据库。
Connection s=DriverManager.getConnection(conURL);
(5) 使用SQL语句对数据库进行操作。
(6) 使用close( )方法解除Java与数据库的连接并关闭数据库。
例如: s.close( );
数据库连接
步骤—1
创建一个以JDBC连接数据库的程序,包含7个步骤:
1、加载JDBC驱动程序:
在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),这通过java.lang.Class类的静态方法forName(String className)实现。例如:
try{
//加载MySql的驱动类
Class.forName("com.mysql.jdbc.Driver") ;
//加载oracle驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//加载sqlserver驱动
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
}catch(ClassNotFoundException e){
System.out.println("找不到驱动程序类 ,加载驱动失败!");
e.printStackTrace() ;
}
成功加载后,会将Driver类的实例注册到DriverManager类中。
步骤—2
提供JDBC连接的URL
•连接URL定义了连接数据库时的协议、子协议、数据源标识。
•书写形式:协议:子协议:数据源标识
协议:在JDBC中总是以jdbc开始
子协议:是桥连接的驱动程序或是数据库管理系统名称。
数据源标识:标记找到数据库来源的地址与连接端口。
例如:(MySql的连接URL)
jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=gbk ; //
useUnicode=true:表示使用Unicode字符集。如果characterEncoding设置为
gb2312或GBK,本参数必须设置为true.characterEncoding=gbk:字符编码方式。
也可表示为:
String url= "jdbc:mysql://localhost:3306/test"; //mysql
String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"; //连接sqlserver的url
步骤—3
创建数据库的连接
. •要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象,该对象就代表一个数据库的连接
•使用DriverManager的getConnectin(String url , String username,String password)方法传入指定的欲连接的数据库的路径、数据库的用户名和密码来获得。
例如:
//连接MySql数据库,用户名和密码都是root
String url = "jdbc:mysql://localhost:3306/test" ;
String username = "root" ;
String password = "root" ;
try{
Connection con=DriverManager.getConnection(url,username,password);
}catch(SQLException se){
System.out.println("数据库连接失败!");
se.printStackTrace() ;
}
步骤—4
创建一个Statement
•要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下3种类型:
1、执行静态SQL语句。通常通过Statement实例实现。
2、执行动态SQL语句。通常通过PreparedStatement实例实现。
3、执行数据库存储过程。通常通过CallableStatement实例实现。
具体的实现方式:
Statement stmt = con.createStatement() ;
PreparedStatement pstmt = con.prepareStatement(sql) ;
CallableStatement cstmt = con.prepareCall("{CALL demoSp(? , ?)}") ;
步骤—5
执行SQL语句
Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate
和execute
1、ResultSet executeQuery(String sqlString):执行查询数据库的SQL语句,返回一个结果集(ResultSet)对象。
2、int executeUpdate(String sqlString):用于执行INSERT、UPDATE或DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等 (返回影响到的数据记录数)
3、execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合语句。
具体实现的代码:
ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ;
int rows = stmt.executeUpdate("INSERT INTO ...") ;
boolean flag = stmt.execute(String sql) ;
步骤—6
处理结果
两种情况:
1、执行更新返回的是本次操作影响到的记录数。
2、执行查询返回的结果是一个ResultSet对象。
• ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问。
• 使用结果集(ResultSet)对象的访问方法获取数据:
while(rs.next()){
String name = rs.getString("name") ;
String pass = rs.getString(1) ; // 此方法比较高效(列是从左到右编号的,并且从列1开始)
}
步骤—7
关闭JDBC对象
操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声 明顺序相反:
1、关闭记录集
2、关闭声明
3、关闭连接对象
优化考虑的问题:存储大数据、减少I/0、cpu、内存、存取速度快、安全、共享、独立、扩展、减少冗余、接口,并发、管理与控制、数据结构
维护:
安全:
事务:
日志:
连接: