MySQL数据库(SQL语句、JDBC、连接池)

MySQL数据库

概念

用于存储和管理数据的仓库。 特点: 1、持久化存储数据的,就是一个文件系统。 2、方便存储和管理数据 3、方便了统一的方式操作数据库---SQL

cmd启动MySQl

使用管理员打开cmd net start mysql 启动MySQL服务器 net stop mysql 关闭MySQL服务器 MySQL登录; mysql -uroot -proot -p连接的密码 mysql -uIP地址 -p连接目标密码 mysql --host=ip --user=root --password=连接目标的密码 MySQL退出; exit quit

SQL

什么是SQL: Structured Query Language 结构化查询语言 其实就是定义了操作所有关系型数据库的规则。每一种数据库操作的方式存在不一样的地方,称为“方言”。

  • SQl分类

    • DDL(Data Definition Language)数据定义语言

      用来定义数据库对象:数据库,表,列表。关键字:create,drop,alter等

      • 操作数据库:CRUD

        • C(create)创建

          创建数据库格式: create database 数据库名称; 创建数据库,判断不存在,在创建: create database if not exists 数据库名称; 创建数据库,并指定字符集: create database 数据库名称 character set 字符集名;

        • R(retrieve)查询

          查询所有数据库的名称: show databases; 查询某个数据库的字符集:查询某个数据库的创建语句 show create database 数据库名称;

          扫描二维码关注公众号,回复: 7293059 查看本文章
        • U(update)修改

          修改数据库的字符集: alter database 数据库名称 character set 字符集名称;

        • D(delete)删除

          删除数据库: drop database 数据库名称; 判断数据库存在,存在再删除: drop database if exists 数据库名称;

        • 使用数据库

          查询当前正在使用的数据库名称: select database(); 使用数据库: use 数据库名称;

        • 代码示例

          -- 创建数据库 CREATE DATABASE db2;

          -- 查询所有数据库 SHOW DATABASES;

          -- 查询某个数据库的字符集 SHOW CREATE DATABASE db2;

          -- 修改数据库的字符集 ALTER DATABASE db2 CHARACTER SET gbk; SHOW CREATE DATABASE db2;

          -- 删除数据库 DROP DATABASE db2; SHOW DATABASES;

          -- 使用数据库 USE db1;

          -- 查询当前使用的数据库 SELECT DATABASE();

      • 操作表

        • C(create)创建

          格式 : create table 表名( 列表1 数据类型1, 列表2 数据类型2, ... 列表n 数据类型n ); 注意:最后一列,不需要加逗号,符号都是英文

          数据库数据类型: 1、int :整数类型 age int 2、double :小数类型 score double 3、date:日期,只包含年月日,yyy-MM-dd 4、datetime:日期,包含年月日时分秒,yyy-MM-dd HH:mm:ss 5、timestamp:时间错类型,包含年月日时分秒,yyy-MM-dd HH:mm:ss 如果将来不给这个字段赋值,或赋值为null,则默认使用当前的系统时间,来自动赋值 6、varchar:字符串 name varchar(20) 姓名最大20个字符 zhangsan 8个字符 张三 2个字符

          创建表代码示例: create table student( id int, name varchar(32), age int, score double(4,1), birthday date, insert_time timestamp ); 复制表: create table 表名 like 被复制的表名;

        • R(retrieve)查询

          查询某个数据库中所有表的名称: show tables; 查询表的结构: desc 表名;

        • U(update)修改

          修改表名: alter table 表名 rename to 新的表名; 修改表的字符集: alter table 表名 character set 字符集名称; 添加一列: alter table 表名 add 列名 数据类型; 修改列名称: alter table 表名 change 列名 新列名 新数据类型; alter table 表名 modify 列名 数据类型;

        • D(delete)删除

          删除列: alter table 表名 drop 列名; 删除表: drop table 表名; drop table if exists 表名;

        • 代码示例

          -- 新建表 CREATE TABLE teacher( NAME VARCHAR(32), age INT, birthday DATE );

          -- 复制表 CREATE TABLE teachers LIKE teacher;

          -- 查询数据库中所有表的名称 SHOW TABLES;

          -- 查询表格结构 DESC teacher;

          -- 修改表名 ALTER TABLE teacher RENAME TO student;

          -- 修改表的字符集 ALTER TABLE student CHARACTER SET gbk; ALTER TABLE student CHARACTER SET utf8;

          -- 添加一列 DESC student; ALTER TABLE student ADD ids INT; ALTER TABLE student ADD score DOUBLE;

          -- 修改列的名称 类型 ALTER TABLE student CHANGE ids id INT; ALTER TABLE student MODIFY id VARCHAR(18);

          -- 删除列 ALTER TABLE student DROP id;

          -- 删除表 DROP TABLE teachers;

      • 约束

        • 概述

          对表中的数据进行限定,保证数据的正确性、有效性和完整性。

        • 非空约束 not null

          • 代码示例

            -- 创建表时,添加非空约束 CREATE TABLE stu( id INT, NAME VARCHAR(32) NOT NULL );

            -- 删除name的非空约束 ALTER TABLE stu MODIFY NAME VARCHAR(20);

            -- 创建表完成后,添加非空约束 ALTER TABLE stu MODIFY NAME VARCHAR(20) NOT NULL;

        • 唯一约束 unique

          • 代码示例

            -- 创建表时,添加唯一约束 CREATE TABLE stu( id INT, phone_number VARCHAR(20) UNIQUE );

            -- 删除唯一约束 ALTER TABLE stu DROP INDEX phone_number;

            -- 创建表完成后,添加唯一约束

            ALTER TABLE stu MODIFY id INT UNIQUE;

        • 主键约束 primary key

          注意: 含义,非空唯一 一张表只能有一个字段为主键 主键就是表中记录的唯一标识 主键自动增长: 如果某一列是数值类型的,使用auto_increment

          • 代码示例

            -- 创建表的时候,添加主键 CREATE TABLE stu( id INT PRIMARY KEY, NAME VARCHAR(20) );

            -- 删除主键 ALTER TABLE stu DROP PRIMARY KEY;

            -- 创建完表后,添加主键 ALTER TABLE stu MODIFY id INT PRIMARY KEY;

            -- 创建表的时候,添加主键自动增长 CREATE TABLE stu( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) );

            -- 删除主键自动增长 ALTER TABLE stu MODIFY id INT;

            -- 创建表完成后,添加主键自动增长 ALTER TABLE stu MODIFY id INT AUTO_INCREMENT;

        • 外键约束 foreign key

          • 代码示例

            -- 创建表的时候,添加外键约束 -- 创建部门表(id,dep_name,dep_location) -- 一方,主表 CREATE TABLE department( id INT PRIMARY KEY AUTO_INCREMENT, dep_name VARCHAR(20), dep_location VARCHAR(20) );

            -- 创建员工表(id,name,age,dep_id) -- 多方,从表 CREATE TABLE employee( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT, dep_id INT, -- 外键对应主表的主键 CONSTRAINT emp_depid_fk FOREIGN KEY (dep_id) REFERENCES department(id) ) ;

            -- 删除外键 ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;

            -- 创建完成表后,添加外键 格式: ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称); ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id);

          • 级联操作

            概述: 在修改和删除主表的主键时,同时更新或删除副表的外键值,称为级联操作 格式: alter table 表名 add constraint 外键名称 foreign key (外键字段名称) references 主表名称(主表列名称) on update cascade on delete cascade; 1、级联更新 : on update cascade 2、级联删除 : on delete cascade

    • DML(Data Manipulation Language)数据操作语言

      用来对数据库中表的数据进行增删改。关键字:insert,delete,update等

      • 增删该表中数据

        • 添加数据

          格式: insert into 表名(列名1,列名2,...列名n) values(值1,值2,...,值n); 注意: 1、列名和值要意义对应。 2、如果表名后,不定义列名,则默认给所有列添加值 insert into 表名 values(值1,值2,...,值n);

        • 删除数据

          格式: delete from 表名 where 条件; 注意: 1、如果不添加条件,则删除表中所有记录 2、如果删除所有记录 1、delete from 表名;不推荐使用,因为该方式为由多少条记录就执行多少次删除操作 2、truncate table 表名;推荐使用,效率高,先删除表,再创建一张表。

        • 修改数据

          格式: update 表名 set 列名1 = 值1,列名2 = 值2,...where 条件; 注意:如果不加任何条件,则会将列表中所有记录全部修改。

        • 代码示例

          • 添加数据 INSERT INTO student(NAME,age)VALUES('张三',18); INSERT INTO student(NAME,age)VALUES('张三',18); INSERT INTO student(NAME,age)VALUES('张三',18); INSERT INTO student VALUES('李四',20,'1994-10-10',99.0); INSERT INTO student VALUES('李四',20,'1994-10-10',99.0);

          -- 查询表中所有数据 SELECT * FROM student;

          -- 删除数据 DELETE FROM student WHERE NAME='张三';

          -- 修改数据 UPDATE student SET birthday = '1986-12-20',score = 98 WHERE NAME='张三';

          -- 删除所有数据 DELETE FROM student; TRUNCATE TABLE student;

    • DQL(Data Query Language) 数据查询语言

      用来查询数据库中表的记录(数据)。关键字:select,where等

      • 查询表中的记录(数据)

        • 标准格式

          select 字段列表 from 表名列表 where 条件列表 group by 分组字段 having 分组之后的条件 order by 排序 limit 分页限定

        • 基础查询

          • 多个字段的查询

            格式: select 字段名1,字段名2,... from 表名; 注意:如果查询所有字段,则可以用*来替代字段列表。

          • 取别名

            as 可以省略

          • 计算列

            一般可以使用四则运算计算一些列的值。(一般只会进行数值型的计算) ifnull(表达式1,表达式2) null参与的运算,一般结果都为null,表达式1:那个字段需要判断是否为null;表达式2:如果字段1为null则用表达式2替换掉。

          • 去除重复

            格式: select distinct 字段名1,字段名2,... from 表名;

          • 代码示例

            -- 查询表中所有数据 SELECT * FROM student;

            -- 去重查询 SELECT DISTINCT address FROM student;

            -- 查询年龄大于18小于25 SELECT * FROM student WHERE age BETWEEN 18 AND 25;

            -- 查询英语成绩为null SELECT * FROM student WHERE english IS NULL;

            -- 查询英语成绩不为null SELECT * FROM student WHERE english IS NOT NULL;

            -- 查询姓马的 SELECT * FROM student WHERE NAME LIKE '马%';

            -- 查询名字中有德的 SELECT * FROM student WHERE NAME LIKE '%德%';

            -- 查询第二个字是化的 SELECT * FROM student WHERE NAME LIKE '_化%';

        • 条件查询

          • where子句后面跟条件

            • 运算符

              <<=>=\=<>(!=) between...and in(集合) like模糊查询 占位符: “_”单个任意字符 “%”多个任意字符 is null and 或 && or 或 || not 或 !

          • group by分组查询

            • 注意事项

              分组语句中,select后面必须跟共性(分组字段,聚合函数)

            • 代码示例

              代码示例:

              -- 按照性别分组,分别查询男、女同学的数学平均分 SELECT sex,AVG(math) FROM student GROUP BY sex;

              -- 按照性别分组,分别查询男、女同学的数学平均分,人数 SELECT sex,AVG(math),COUNT(id) FROM student GROUP BY sex;

              -- 按照性别分组,分别查询男、女同学的数学平均分,人数.要求分数低于70不参与 SELECT sex ,AVG(math),COUNT(id) FROM student WHERE math>70 GROUP BY sex;

              -- 按照性别分组,分别查询男、女同学的数学平均分,人数.要求分数低于70不参与,分组后,显示人数大于2的组 SELECT sex,AVG(math),COUNT(id) FROM student WHERE math>70 GROUP BY sex HAVING COUNT(id)>2;

          • having后面跟条件语句

            对分组后数据进行筛选

          • order by后面跟排序条件字段

            代码示例: -- 数学成绩升序(默认) SELECT * FROM student ORDER BY math ASC;

            -- 数学成绩升序,然后英语成绩降序 SELECT * FROM student ORDER BY math ASC , english DESC;

            -- 总分降序 SELECT * ,math+IFNULL(english,0) AS 总分 FROM student ORDER BY 总分 DESC;

          • limit分页

            limit 索引,每页显示的条数; limit (currentPage - 1) * pageSize;

          • 聚合函数

            注意:聚合函数的计算,排除null值。 解决方案: 1. 选择不包含非空的列进行计算 2. IFNULL函数

            • count 计算个数

            • max 计算最大值

            • min 计算最小值

            • sum 计算和

            • avg 计算平均值

            • 代码示例

              SELECT COUNT(id) FROM student;

        • 多表查询

          • 显示内连接查询

            仅能查询有关联的数据(交集)

            • 示例代码

              格式: select 字段列表 from 表名1[inner] join 表名2 on 条件

              /查询员工信息和所在的部门/ SELECT * FROM emp INNER JOIN dept ON emp.dept_id = dept.id;

              SELECT * FROM emp JOIN dept ON emp.dept_id = dept.id;

          • 外连接查询

            • 示例代码

              格式: select 字段列表 from 表1 [left/right] outer join 表2 on 条件

              /-- 查询所有员工信息,如果员工由部门,则查询部门名称,没有部门,则不显示部门名称/

              左外连接(显示左表所有数据、左表和右表有关联的数据): SELECT * FROM emp t1 LEFT OUTER JOIN dept t2 ON t1.dept_id = t2.id;

              右外连接(显示右表所有数据、右表和左表有关联的数据): SELECT * FROM emp t1 RIGHT OUTER JOIN dept t2 ON t1.dept_id = t2.id;

          • 子查询

            查询中嵌套查询,称嵌套查询为子查询。

            • 单行单列

              代码示例:   -- 查询员工工资小于平均工资的人  SELECT * FROM emp WHERE emp.salary < (SELECT AVG(salary) FROM emp);

            • 多行单列

              代码示例:

              -- 查询'财务部'和'市场部'所有的员工信息 SELECT id FROM dept WHERE NAME = '财务部' OR NAME = '市场部'; SELECT * FROM emp WHERE dept_id = 3 OR dept_id = 2;

              -- 子查询 SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE NAME = '财务部' OR NAME = '市场部');

            • 多行多列

              代码示例: -- 查询员工入职日期是2011-11-11日之后的员工信息和部门信息 -- 子查询 SELECT * FROM dept t1 ,(SELECT * FROM emp WHERE emp.join_date > '2011-11-11') t2 WHERE t1.id = t2.dept_id;

              -- 普通内连接 SELECT * FROM emp t1,dept t2 WHERE t1.dept_id = t2.id AND t1.join_date > '2011-11-11'

          • 笛卡尔积

            有两个集合A,B .取这两个集合的所有组成情况。 要完成多表查询,需要消除无用的数据

    • DCL(Data Control Language)数据控制语言

      用来定义数据库的访问权限和安全级别,及创建用户。关键字:GRANT,REVOKE等

      • 分配不同用户对数据库操作的不同权限

        • 创建用户

          格式: create user '用户名'@'主机名' identified by '密码';

          格式解析: 用户名:将创建的用户名 主机名:指定该用户再那个主机上可以登陆,如果是本地用户可以用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符% 密码:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器

          代码示例: 创建user1用户,只能localhost这个服务器登陆mysql服务器,密码为123 create user 'user1'@'localhost' identified by '123'; 创建user2用户可以在任何电脑上登陆mysql服务器,密码为123 create user 'user2'@'%' identified by '123';

          注: 创建的用户名都在mysql数据库中的user表中可以查看到,密码经过了加密。

        • 给用户授权

          格式: grant 权限1,权限2...on 数据库名.表名 to '用户名'@'主机名'; 格式解析: grant...on...to授权关键字 权限:授予用户的权限,如:GREATE\ALTER\SELECT\INSERT\UPDATE等,如果要授予所有的权限则使用ALL 数据库名.表名:该用户可以操作那个数控的那些表,如果要授予该用户对所有数据库和表的相应操作权限则可以用*表示 '用户名'@'主机名':给那个用户授权

          代码示例: 给user1用户分配对test这个数据库操作的权限:创建表,修改表,插入记录,更新记录,查询 grant create,alter,insert,update,select on test.* to 'user1'@'localhost'; 给user2用户分配所有权限,对数据库的作用表 grant all on . to 'user2'@'%';

        • 撤销权限

          格式: revoke 权限1,权限2,... on 数据库.表名 revoke all on test.*from '用户名'@'主机名';

          格式解析: revoke...on...from:撤销授权的关键字 权限:用户的权限,如:create\alter\select\insert\update等,所有的权限则用ALL 数据库.表名:对那些数据库的哪些表,如果要取消该用户对所有数据库和表的操作授权则可用*表示 '用户名'@'主机名':给那个用户撤销

          代码示例: 撤销user1用户对test数据库所有表的操作的权限 revoke all on test.* from 'user1'@'localhost';

        • 查看权限

          格式: show grants for '用户名'@'主机名'; 注:usage是指连接(登陆)权限,建立一个用户,就会自动授予其usage权限(默认授予)。

        • 删除用户

          格式: drop user '用户名'@'主机名';

        • 修改管理员密码

          格式: mysqladmin -uroot -p password 新密码 注:需要在未登陆MySQL的情况下操作,新密码不需要加上引号

          操作步骤: 1、将 root 管理员的新密码改成 123456 mysqladmin -uroot -p password 123456 2、 要求输入旧密码 Enter password: 3、 使用新密码登录 mysql -uroot -p123456

        • 修改普通用户密码

          格式: set password for '用户名'@'主机名' = password('新密码'); 注意:需要在登陆MySQL的情况下操作,新密码要加单引号。

          操作步骤: 1、 将'user1'@'localhost'的密码改成'666666' set password for 'user1'@'localhost'=passworld('666666'); 2、使用新密码登录,老密码登录不了

        • 忘记了root密码

          mysql中忘记了root用户的密码? 1. cmd -- > net stop mysql 停止mysql服务 【 需要管理员运行该cmd 2. 使用无验证方式启动mysql服务: mysqld --skip-grant-tables 3. 打开新的cmd窗口,直接输入mysql命令,敲回车。就可以登录成功 4. use mysql; 5. update user set password = password('你的新密码') where user = 'root'; 6. 关闭两个窗口 7. 打开任务管理器,手动结束mysqld.exe 的进程 8. 启动mysql服务 9. 使用新密码登录。

  • SQL通用语法

    1、SQl语句可以单行或多行书写,以分号结尾。 2、可以使用空格和缩进来增强语句的可读性。 3、MySQL数据库的SQL语句不区分大小写,关键字建议使用大写。 4、3种注释 单行注释:-- 注释内容 或 # 注释内容(MySQL特有)。 多行注释: /* 注释 */

数据库的设计

  • 多表之间的的关系

    • 一对一

      如:人和身份证 一个人只能由一个身份证,一个身份证只能对应一个人 实现方式: 一对一关系实现,可以在任意一方添加唯一外键指向另一方的主键。

    • 一对多

      如: 部门和员工 一个部门由多个员工,一个员工只能对应一个部门 实现方式: 在多的一方建立外键,指向一的一方的主键

    • 多对多

      如:学生与课程 一个学生可以由多门课程,一门课程对应多名学生 实现方式: 多对多关系实现需要借助第三张中间表。中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键

  • 数据库设计的范式

    • 概念

      设计数据库时,需要遵循的一些规范,要遵循后边的范式要求,必须先遵循前边的所有范式要求 设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。 目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。

    • 第一范式

      每一列都是不可分割的原子数据项

    • 第二范式

      在1NF的基础上,非码属性必须完全依赖于码(在1NF基础上消除非主属性对主码的部分函数依赖)

          * 几个概念:
      1. 函数依赖:A-->B,如果通过A属性(属性组)的值,可以确定唯一B属性的值。则称B依赖于A
      例如:学号-->姓名。 (学号,课程名称) --> 分数
      2. 完全函数依赖:A-->B, 如果A是一个属性组,则B属性值得确定需要依赖于A属性组中所有的属性值。
      例如:(学号,课程名称) --> 分数
      3. 部分函数依赖:A-->B, 如果A是一个属性组,则B属性值得确定只需要依赖于A属性组中某一些值即可。
      例如:(学号,课程名称) -- > 姓名
      4. 传递函数依赖:A-->B, B -- >C . 如果通过A属性(属性组)的值,可以确定唯一B属性的值,在通过B属性(属性组)的值可以确定唯一C属性的值,则称 C 传递函数依赖于A
      例如:学号-->系名,系名-->系主任
      5. 码:如果在一张表中,一个属性或属性组,被其他所有属性所完全依赖,则称这个属性(属性组)为该表的码
      例如:该表中码为:(学号,课程名称)
      * 主属性:码属性组中的所有属性
      * 非主属性:除过码属性组的属性
    • 第三范式

      在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)

数据库的备份和还原

  • 命令行

    备份: MySQLdump -u用户名 -p密码 数据库名称>保存路径 还原: 1、登录数据库 2、创建数据库 3、使用数据库 4、执行:source 文件路径

  • 图形化工具

事务

如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。

  • 事务原理

    事务开启之后,所有的操作都会临时保存到事务日志中,事务日志只有在得到commit命令才会去同步到数据表中,其他情况都会清空事务日志(rollback,断开连接)

    • 原理图

    • 事务步骤

      1、客服端连接数据库服务器,创建连接时创建此用户临时日志文件。 2、开启事务以后,所有操作都会先写入到临时日志文件中。 3、所有的查询操作从表中查询,但会经过日志文件加工后才返回。 4、如果事务提交则将日志文件中的数据写到表中,否则清空日志文件。

    • 回滚点

      在某些成功的操作完成之后,后续的操作有可能成功有可能失败,但是不管成功还是失败,前面操作都已经成功,可以在当前成功的位置设置一个回滚点。可以供后续失败操作返回到该位置,而不是返回所有操作,这个点称之为回滚点。

      • 设置回滚点

        设置回滚点:savepoint 名字 回到回滚点:rollback to 名字

  • 自动提交

    mysql就是自动提交的 一条DML(增删改)语句会自动提交一次事务。

    • 开启事务 start transaction

    • 如果出错就,回滚 rollback

    • 提交事务 commit

  • 手动提交

    Oracle 数据库默认是手动提交事务 需要先开启事务,再提交 执行过程: 成功:开启事务->执行多条SQL语句->成功提交事务 失败:开启事务->执行多条SQL语句->事务回滚

  • 修改事务的默认提交方法

    查看事务的默认提交方式: SELECT @@autocommit; -- 1 代表自动提交 0 代表手动提交 修改默认提交方式: set @@autocommit = 0;

  • 事务的四大特征(ACID)

    • 原子性

      是不可分割的最小操作单位,要么同时成功,要么同时失败。

    • 持久性

      当事务提交或回滚后,数据库会持久化的保存数据。

    • 隔离性

      多个事务之间。相互独立。

    • 一致性

      事务操作前后,数据总量不变

  • 事务的隔离级别

    多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。

    • 问题

      • 脏读

        一个事务,读取到另一个事务中没有提交的数据

      • 虚读(不可重复读)

        在同一个事务中,两次读到的数据不一样

      • 幻读

        一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。

    • read uncommitted:读未提交

      • 存在问题:脏读、虚读、幻读

    • read committed:读已提交(Oracle)

      • 存在问题:虚读、幻读

    • repeatable read : 可重复读(MySQL)

      • 存在问题:幻读

    • serializable : 串行化

      • 解决所有问题

    • 设置隔离级别

      查询数据库隔离级别: select @@tx_isolation 数据库设置隔离级别: set global transcation isolation level 级别字符串;

          设置事务隔离级别,需要退出MySQL再重新登录才能看到隔离级别的变化

      隔离级别越高,性能越差,安全性越高

JDBC(Java Datebase Connectivity )Java数据库连接,Java语言操作数据库

  • 概念

    JDBC 是 Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个 数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用 JDBC 接口中的方法即 可,数据库驱动由数据库厂商提供。

  • JDBC常用包

    • java.sql

      所有与 JDBC 访问数据库相关的接口和类

    • javax.sql

      数据库扩展包,提供数据库额外的功能。如:连接池

    • 数据库的驱动

      由各大数据库厂商提供,需要额外去下载,是对 JDBC 接口实现的类

  • JDBC访问数据库的步骤

    1、注册和加载驱动() 2、获取连接 3、Connection获取Statement对象 4、使用Statement对象执行SQL语句 5、返回结果集 6、释放资源

  • JDBC的核心API

    • Class.forName(数据库驱动实现类)

      加载和注册数据库驱动,数据库驱动由 mysql 厂商 "com.mysql.jdbc.Driver" 注: 从 JDBC3 开始,目前已经普遍使用的版本。可以不用注册驱动而直接使用。Class.forName 这句话可以省略

    • DriverManager 类

      作用: 1、 管理和注册数据库驱动 2、得到数据库连接对象

      • 常用方法

        Connection getConnection (String url,String user,String password) 通过连接字符串,用户名,密码来得到数据库的连接对象 Connection getConnection (String url,Properties info) 通过连接字符串,属性对象来得到连接对象

      • 代码示例

        代码示例: //获取数据库的连接对象 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root");

        url格式解析: 协议名:子协议://服务器名或 IP 地址:端口号/数据库名?参数=参数值

    • Connection 接口

      具体的实现类由数据库厂家提供,代表一个连接对象,可用于创建 Statement 和 PreparedStatement 对象

      • 常用方法

        Statement createSteatment() 创建一条SQL语句 PrepareStatement prepareStatement(String sql) 指定预编译的SQL语句,SQL语句中使用占位符? 创建一个语句对象

    • Statement 接口

      代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象

      • 常用方法

        int executeUpdate(String sql) 用于发送DML语句,增删改的操作:insert、update、delete 参数:SQL语句 返回值:返回对数据库影响的行数 ResultSet executeQuery(String sql) 用于发送DQL语句,执行查询的操作,select 参数:SQL语句 返回值:查询的结果集

    • PreparedStatemen 接口

      PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句

          Statement对象每执行一条SQL语句都会先将SQL语句发送给数据库,数据库先编译SQL,再执行。如果有一万条类似的SQL语句,数据库要编译一万次,执行一万次,效率低。

      PrepareStatement会先将SQL语句发送给数据库预编译。PrepareStatement会引用预编译后的结果可以多次传入不同的参数给’PrepareStatement‘对象并执行。如果有一万条类似的插入数据的语句。数据库只需要预编译一次,传入一万次不同的参数并执行。减少了SQL语句的编译次数,提高了执行效率。

      1、因为有预先编译的功能,提高 SQL 的执行效率。
      2、 可以有效的防止 SQL 注入的问题,安全性更高。
      3、提高了程序的可读性
      • 使用步骤

        1、编写 SQL 语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND password=?"; 2、 获得 PreparedStatement 对象 3、 设置实际参数:setXxx(占位符的位置, 真实的值) 4、 执行参数化 SQL 语句 5、 关闭资源

      • 常用方法

        int executeUpdate() 执行DML,增删改的操作,返回影响的行数 ResultSet executeQuery() 执行DQL,查询的操作,返回结果集

      • 设置参数的方法

        void setDouble(int parameterIndex, double x) 将指定参数设置为给定 Java double 值。 void setFloat(int parameterIndex, float x) 将指定参数设置为给定 Java REAL 值。 void setInt(int parameterIndex, int x) 将指定参数设置为给定 Java int 值。 void setLong(int parameterIndex, long x) 将指定参数设置为给定 Java long 值。 void setObject(int parameterIndex, Object x) 使用给定对象设置指定参数的值。 void setString(int parameterIndex, String x) 将指定参数设置为给定 Java String 值。

    • ResultSet 接口

      用于封装数据库查询的结果集,返回给客户端 Java 程序

      • 常用方法

        Boolean next() 1、游标向下移动1行 2、返回boolean 类型,如果还有下一条记录,返回true,否则返回false 数据类型 getXxx() 1、通过字段名,参数是String类型。返回不同的类型 2、通过列号,参数是整数,从1开始,返回不同的类型

        • getXxx() 方法对应的常用数据类型转换

          SQL类型 Jdbc对应方法 返回类型 BIT(1) bit(n) getBoolean() boolean TINYINT getByte() byte SMALLINT getShort() short INT getInt() int BIGINT getLong() long CHAR,VARCHAR getString() string Text(Clob) Blob getClob getBlob() Clod Blob DATE getDate() java.sql.Date 只代表日期 TIME getTime() java.sql.Time 只代表时间 TIMESTAMP getTimestamp() java.sql.Timestamp 同时有日期和时间 注意: java.sql.Date、Time、Timestamp(时间戳),三个共同父类是;java.util.Date

      • 常见报错

        1、如果光标在第一行之前,使用 rs.getXX()获取列值,报错:Before start of result set 2、 如果光标在最后一行之后,使用 rs.getXX()获取列值,报错:After end of result set 3、 使用完毕以后要关闭结果集 ResultSet,再关闭 Statement,再关闭 Connection

  • JDBC事务处理

    1、获取连接 2、开启事务 3、获取到PrepardStatement 4、使用PreparedStatement执行SQL语句 5、正常,就提交事务 6、出现异常回滚事务 7、最后关闭资源

    • API

      void setAutoCommit(boolean autoCommit) 参数是true或false 如果设置为false,表示关闭自动提交,相当于开启事务(放在执行SQL语句之前) void commit() 提交事务(放在SQL语句执行完成之后) void rollback() 回滚事务(一般放在catch里面)

    • 工具类

      public class JDBCUtils { private static String url; private static String user; private static String password; private static String driver;

      static {
        try {
            //创建Properties 集合,是Map的子类,key-value都是字符串
            Properties pro = new Properties();
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            URL resource = classLoader.getResource("jdbc.properties");
            String path = resource.getPath();
            pro.load(new FileReader(path));
            /*
            //通过类加载器 加载src/目录下的 datasource.properties文件,返回流
            InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("datasource.properties");
            //把流里的键值对加载到props对象中
            pro.load(inputStream);
            */
            //获取配置文件在的value内容
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");

            //注册驱动
            Class.forName(driver);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

      }

      public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, user, password);
      }

      public static void close(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
      }

      public static void close(Statement stmt, ResultSet rs, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
      }

      }

连接池

  • 概念

    其实就是一个容器(集合),存放数据库连接的容器。 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

    好处: 节约资源 提高效率(用户访问高效)

  • c3p0

    实现javax.sql包下的DateSource 接口

    使用: 1、导入jar包( c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar )和数据库驱动包 2、定义配置文件(文件名: c3p0.properties 或者 c3p0-config.xml) 3、创建对象(数据库连接对象 ComboPooledDataSource) 4、获取连接 getConnection

    • 代码示例

      //1、创建数据连接对象 DateSource ds = new ComboPooledDataSource(); //2、获取连接对象 Connection conn = ds.getConnection();

  • druid

    使用步骤: 1、导入jar包(druid-1.0.9.jar) 2、定义配置文件(文件名后缀为:Properties) 3、加载配置文件 (Properties) 4、获取数据库连接池对象:通过工厂类来获取 (DruidDataSourceFactory) 5、获取连接(getConnection)

    • 代码示例

      //加载配置文件 Properties pro = new Properties(); InputStream is = DruidDemo.class.getClassLodaer().getRespurceAsStream("druid.properties"); pro.load(is); //获取连接池对象 DataSource ds = DruidDataSourceFactory.createDateSource(pro); //获取连接 Connection conn = ds.getConnection();

  • 工具类

    1、定义一个类 JDBCUtils 2、提供静态代码块加载配置文件,初始化连接对象 3、提供方法: 1、快速连接方法:通过数据库连接池获取连接 2、释放资源 3、获取连接池的方法

    • 代码示例

      public class JDBCUtils { private static DataSource ds;

      static {
        Properties pro = new Properties();
        try {
            pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
      }

      //获取连接
      public static Connection getConnection() throws SQLException {
        return ds.getConnection();
      }

      //关闭资源
      public static void close(Statement stmt, Connection conn) {
        /* if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(conn != null){
            try {
                conn.close();//归还连接
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }*/

        close(null, stmt, conn);
      }

      public static void close(ResultSet rs, Statement stmt, Connection conn) {

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                conn.close();//归还连接
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
      }

      //获取连接池
      public static DataSource getDataSource() {
        return ds;
      }

      }

  • Spring JDBC

    Spring框架对JDBC的简单封装,提供了一个JDBCTemplate对象简化JDBC的开发

    • 使用步骤

      1、导入jar包 2、创建JDBCTemplate对象。依赖于数据源DataSource(JdbcTemplate trmplate = new JdbcTemplate(ds)); 3、调用JdbcTemplate的方法来完成CRUD的操作

    • 常用方法

      update(String sql, Object... args) 执行DML语句,增、删、改 queryForMap() 将查询的结果封装为map集合,将列作为key,将值作为value,将这条记录封装为一个map集合(查询的结果集长度只能是1) queryForList() 查询结果将结果封装为list集合(将每一条记录封装为一个map集合,再将map集合封装到List集合中) query(String sql, new BeanPropertyRowMapper<T>(T.class), Object... args) 返回的对象的集合,适合返回多行多列的情况 queryForObject(String sql, new BeanPropertyRowMapper<T>(T.class), Object... args) 返回的单个对象, 适合查询一条记录的情况 queryForObject(String sql, 包装类型.class, Object... args) 返回的单行单列的包装类型,适合聚合函数情况

    • 代码示例

      public class JdbcTemplateDemo02 {

      //获取JdbcTemplate对象
      JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

      //修改id1001的salary数据
      @Test
      public void test1() {
        String sql = "update emp set salary = 8000 where id = 1001";
        int count = template.update(sql);
        System.out.println(count);
      }

      //添加id1015记录
      @Test
      public void test2(){
        String sql = "insert into emp(id,name,dept_id) values(?,?,?)";
        int count = template.update(sql, 1015, "郭靖", 10);
        System.out.println(count);
      }

      //删除id为1015的记录
      @Test
      public void test3(){
        String sql = "delete from emp where id =?";
        int update = template.update(sql, 1015);
        System.out.println(update);
      }

      //queryForMap()查询的结果只能为1条
      @Test
      public void test4(){
        String sql = "select * from emp where id = ?";
        Map<String, Object> map = template.queryForMap(sql, 1001);
        System.out.println(map);
      }

      //查询所有记录,将其封装为LIst
      @Test
      public void test5(){
        String sql = "select * from emp";
        List<Map<String, Object>> list = template.queryForList(sql);
        for (Map<String, Object> map : list) {
            System.out.println(map);
        }
      }

      //查询所有记录,将其封装为Emp对象的list集合
      @Test
      public void test6(){
        String sql = "select * from emp";
        List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
        for (Emp emp : list) {
            System.out.println(emp);
        }
      }

      //查询总记录数
      @Test
      public void test7(){
        String sql = "select count(id) from emp";
        Long aLong = template.queryForObject(sql, long.class);
        System.out.println(aLong);
      }

      //查询id1001的信息。使用queryForObject(sql, new BeanPropertyRowMapper<Emp>(Emp.class), 1001)方法
      @Test
      public void test8(){
        String sql = "select * from emp where id = ?";
        Emp emp = template.queryForObject(sql, new BeanPropertyRowMapper<Emp>(Emp.class), 1001);
        System.out.println(emp);
      }

      //查询id1002的信息。使用query(sql, new BeanPropertyRowMapper<>(Emp.class), 1002)方法
      @Test
      public void test9(){
        String sql = "select * from emp where id = ?";
        List<Emp> list = template.query(sql, new BeanPropertyRowMapper<>(Emp.class), 1002);
        System.out.println(list.size());
        System.out.println(list);
      }

      }

猜你喜欢

转载自www.cnblogs.com/zyxyz/p/11527927.html