MySQL_JDBC_数据库连接池

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 --version()/ -V;查看数据库版本
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...andis nullandorin()notlike;
    	andor优先级高。
    	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 ...
			innerouter可以省略。
			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表示取几个)
	
	limitsql语句最后执行的一个环节
	
	通用的标准分页sql:
		每页显示pageSize条记录
		第pageNo页:(pageNo - 1) * pageSize, pageSize


CRUD

创建表:	
	语法格式:
		create table 表名(字段名1 数据类型,字段名2 数据类型,....);
	表名在数据库当中一般建议以:t_或者tbl_开始。
	
删除表:
	drop table 表名; // 这个通用。
	drop table if exists 表名; // oracle不支持这种写法。        
	
关于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)
		......

charvarchar怎么选择?
	在实际的开发中,当某个字段中的数据长度不发生改变的时候,是定长的,例如:性别、生日等都是采用char。
	当一个字段的数据长度不确定,例如:简介、姓名等都是采用varcharinsert语句插入数据
	语法格式:
        insert into 表名(字段名1,字段名2,字段名3,....) values(1,2,3,....)
        要求:字段的数量和值的数量相同,并且数据类型要对应相同。
        字段可以省略不写,但是后面的value对数量和顺序都有要求。
        
        将查询结果插入到一张表中:insert into1 select ** from2
        
表的复制
	语法格式:
		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;// 字段自动维护一个自增的数字,从1开始,以1递增。
			提示: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;//注意这里prepared是形容词
        ResultSet rs = null;
        
        try{
    
    
            //1、注册驱动
            Class.forName(driver);
            
            //2、获取连接
            conn = DriverManager.getConnection(url,user,password);
            conn.setAutoCommit(false);//开启事务
            
            //3、获取预编译数据库操作对象
            //先写SQL语句框子,其中一个?表示一个占位符用,作将来接收值,注意占位符不能用单引号括起来。
            String sql = "select * from t_user where loginName = ? and password = ?"
            //程序执行到此处会发送SQL语句框子给DBMS,然后DBMS进行sql语句的预编译
            ps = conn.prepareStatement(sql);//注意这里prepare是动词
            //给点位符?传值(第一个?下标是1,第二个是2...;JDBC中所有的下标都是从1开始)
            //点位符占“值”
            ps.setString(1,user);
            ps.setString(2,password);//如果参数是数值,那么可以用setInt();
            
            //4、执行SQL
            rs = ps.excuteQurey();
            
            //5、处理结果集
            while(rs.next()){
    
    //如果是只一条语句例如登陆可以用if(){}
                //对取出的数据进操作
            }
            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{
    
    
            //第一步:注册驱动
            //Driver driver = new oracle.jdbc.driver.OracleDriver();这是Oracle的驱动
            //写法一:Driver driver = new com.mysql.jdbc.Driver();//多态,父类型引用指向子类型对象
            		//DriverManager.registerDriver(driver);
            //写法二:
            Class.forName(driver);//不需要接收返回值,因为只需要它的类加载动作!
            
            //第二步:获取联接
            /*
            	url:统一资源定位符(网络中某个资源的绝对路径)
            	url包括:协议、IP、PORT、资源名
            		eg:jdbc:mysql://127.0.0.1:3306/bjpowernode
            			jdbc:mysql://-->通信协议
            			127.0.0.1------>服务器IP地址(127.0.0.1和localhost都是本机IP地址)
            			3306----------->服务器上软件的端口
            			bjpowernode---->服务器上某个资源名
            */
            conn = DriverManager.getConnection(url,user,password);
            
            
            //第三步:获取数据库操作对象
            stmt = conn.createStatement();
            
            
            //第四步:执行SQL语句
            //此处的SQL语句不需要提供分号结尾
            /*
            增删改-->String sql = "insert into dept(deptno,deptname,loc) values(50,'人事部','北京')";
            以下是专门执行DML语句的(insert,delete,update),返回值是“影响数据库中的记录条数Int count”
            int count = stmt.executeUpdate(sql);
            */
            /*
            查  询-->String sql = "select empno,ename sal from emp";
            以下是专门执行DQL语句的(select),返回的是“ResuleSet rs”
            rs = stmt.executeQuery(sql);
            
            //第五步:处理查询结果集
            while(rs.next()){
            	//getString()方法的参数可以是列的下标、列名
            	//注意:getString()的参数如果是名称那么指的就是查询结果集的列名称!
            	//除了以String类型取出数据外,还可以以特定的类型取出:eg:getInt("enpno");原数据类型必须匹配!
                String empno = rs.getString("enpno");
                String ename = rs.getString("ename");
                String sal = rs.getString("sal");
            }
            */
        }catch(SQLException e){
    
    
            e.printStackTrace()
        }catch(ClassNotFoundException e){
    
    
            e.printStackTrace();
        }finally{
    
    
            
            //第六步:释放资源
            //遵循从小到大依次关闭,且分别try...catch
            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();
        }
    }
    /**
     * 从连接池获取连接对象
     * @return 获取到的连接对象
     * @throws SQLException 连接异常
     */
    public static Connection getConnFromDBCPPool() throws SQLException {
    
    
        return ds.getConnection();
    }

    /**
     * 释放资源,归还连接对象
     * @param rs 结果集
     * @param stmt 数据库操作对象
     * @param conn 连接对象
     */
    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
    * 代码:
    //3.加载配置文件
    Properties pro = new Properties();
	InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
	pro.load(is);

    //4.获取连接池对象
    DataSource ds = DruidDataSourceFactory.createDataSource(pro);

    //5.获取连接
    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                     

猜你喜欢

转载自blog.csdn.net/Wgijja/article/details/112059832