数据库MySql

本文详细介绍了MySQL数据库的一些常用操作,包括SQLyog的注释快捷键,数据库的创建、描述、备份和恢复方法,数据类型的使用,以及增删改查操作。还涉及到了表结构的修改,如字段的添加、删除和修改,以及各种SQL函数的使用,如统计函数、字符串函数、日期函数等。此外,文章还涵盖了事务处理、存储引擎的选择、JDBC连接数据库的方法,以及数据库连接池的概念。
摘要由CSDN通过智能技术生成

相关概念 

SQLyog 注释快捷键:Ctrl+Shift+C  取消注释: Ctrl+Shift+R

数据库简单指令

DESC 表名   显示表结构

        创建表

CREATE TABLE `user`(
	`id` INT,
	`name` VARCHAR(255),
	`password` VARCHAR(255),
	`birthday` DATE
)CHARACTER SET utf8 COLLATE utf8_bin ENGINE INNODB

        如果在创建的字段类型后年加上 UNSIGNED ,则代表此数据类型为无符号类型。默认有符号

CREATE TABLE user_01(
    id INT UNSIGNED
);

        创建utf8字符集的dxgsql数据库

CREATE DATABASE dxgsql CHARACTER SET utf8

         创建utf8字符集的,并带规则的dxgsql数据库

CREATE DATABASE dxgsql CHARACTER SET utf8 COLLATE utf8_bin

数据库的备份和恢复 

备份数据库(表):     

格式:mysqldump -u root  -p -B 数据库名 > 路径名.sql
格式: mysqldump -u root  -p 数据库名 表1名 表2名 > 路径名.sq

将ecshop数据库备份到D盘下(管理员运行DOS窗口直接键入)
mysqldump -u root -p -B ecshop > d:\ecshop.sql
将ecshop数据库中的表备份到D盘下(管理员运行DOS窗口直接键入)
mysqldump -u root -p  ecshop ecs_id ecs_card > d:\ecshop.sql

恢复数据库:

数据库的恢复需要管理员进入mysql命令行键入
source d:\ecshop.sql

 数据类型

 创建

小数类型

        DECIMAL[M,D] M是指总位数,D是指小数点后面位数(期望小数精度高,推荐使用)

        D为0,则没有小数部分,此时为整数。M最大65,D最大30

        M省略,默认为10;D省略,默认为0

字符串类型

        CHAR(size) 固定长度字符串,最大255字符。是指字符 ,根据编码格式的不同,相同的字符数可能有不同的字节数。如果输入的字符数达不到设置的字符数,则也会占用分配的字符数,固定大小。(身份证号,手机号等)

        VARCHAR(size) 0-65535 可变长度字符串 最大65532字节 1-3个字节用于记录大小

        在utf8编码格式下,一个字符3字节,对打存储21844个字符。gbk编码一个字符2个字节,故不同编码存储的字符数不同。是变长的,插入的字符数达不到设置的字符数,则会占用实际使用的字符数,但因为有记录大小的字符数,故其最终占用的字节数是:实际字节数+预留记录大小的字节数(1-3个字节数)  (长度不固定的留言,文章

日期类型

        DATE,  DATETIME,  TIMESTAMP (时间戳)

CREATE TABLE timetable(-- 创建表格
	birthday DATE, -- 年月日
	job_time DATETIME, -- 年月日 时分秒
	login_time TIMESTAMP -- 时间戳
			NOT NULL DEFAULT CURRENT_TIMESTAMP -- 不为空且更新当前时间
			ON UPDATE CURRENT_TIMESTAMP);

#若插入的数据没有login_time,系统自动添加
INSERT INTO timetable(birthday,job_time)VALUES('2022-11-11','2022-11-11 10:10;10');

输出结果

 修改删除

修改字段名 
修改字段名name为user_name

ALTER TABLE emplyee
        CHANGE `name` `user_name` VARCHAR(64) NOT NULL DEFAULT ''
 增加列
员工emp表增加一个列image列,varchar类型(要求在本表最后一个字段resume后面)

ALTER TABLE emp
        ADD image VARCHAR(32) NOT NULL DEFAULT ''
        AFTER RESUME
删除列 
删除sex列

ALTER TABLE emp
    DROP sex;
修改列 
修改job列,使其长度为60

ALTER TABLE emp
    MODIFY job VARCHAR(60) NOT NULL DEFAULT ''
 修改表名
RENAME TABLE emp TO employee
 修改表的字符集
ALTER TABLE employee CHARACTER SET utf8

 插入数据

 一条语句添加多个记录

如果给表中所有字段添加数据,VALUES前可以不写字段名称,会自动匹配。但得按顺序填写

goods表插入多条数据

INSERT INTO `goods`(id,goods_name,price)
    VALUES(50,'华为手机',3000),(31,'苹果手机',4000);

 更新数据

 

 

 删除数据

 DELETE FROM 表名 WHERE[条件] ;                   删除表中记录,无条件则是删除全部记录

DROP TABLE 表名;     删除表

SELECT

给列 取别名

SELECT 原列名 AS 列名 FROM 表名; 

 运算符

 统计函数

COUNT(*) | COUNT(列名) 统计个数

统计数学成绩>90的学生个数
SELECT COUNT(*) FROM stu
WHERE  math > 90;

SUM() 计算总和

统计语数英各科成绩的总和
SELECT SUM(chinese),SUM(math),SUM(english) FROM grade;

AVG()  平均  MAX() MIN() 最大值最小值

GROUP BY()  HAVING

显示平均工资低于2000的部门号和平均工资
SELECT AVG(sal),deptno
    FROM emp GROUP BY deptno
        HAVING AVG(sal) < 2000;

字符串相关函数(内容多)

CHARSET(str) 返回字串字符集

SELECT CHARSET(NAME),CHARSET(sex) FROM emp;

CONCAT(str) 将多个字段值拼接输出

SELECT CONCAT(NAME,' 性别是 ',sex,' 工作是 ',job) AS `信息` FROM emp;

 

INSTR (string,substring) 返回substring 在string 中出现的位置,没有返回0.从1开始计算 

SELECT INSTR('dxgisagoodman','good')FROM DUAL; -- DUAL 亚元表(系统表),可作为测试表使用

  UCASE(string)  LCASE(string) 转换大小写

SELECT UCASE('dxg')FROM DUAL; -- 返回 DXG
SELECT UCASE(NAME)FROM emp;
SELECT LCASE('DXG')FROM DUAL;--返回dxg
SELECT LCASE(NAME)FROM emp;

LEFT(string,length) 从string左边取length个字符

SELECT LEFT(NAME,2) FROM emp;
SELECT LEFT('nihaoabushi',5) AS 'gain' FROM DUAL; -- 返回nihao

LENGTH(string) 计算string的长度(按照字节)

SELECT LENGTH('education') FROM DUAL; -- 返回9
SELECT LENGTH('丁凯') FROM DUAL;-- 返回 6  utf8编码
SELECT LENGTH(NAME) FROM emp;

REPLACE (str,old_str,new_str) str中new_str替换old_str

SELECT REPLACE('dxgstudy','study','learn') AS '替换结果'FROM DUAL; -- 返回 dxglearn
SELECT REPLACE(job,'销售','地推')AS '替换结果'FROM emp;

 STRCMP(str1,str2)比较大小 在utf8_bin区分大小写的前提下。根据ASCLL码进行字符串比较

SELECT STRCMP('Dag','Dge') FROM DUAL; -- 返回-1

SUBSTRING(str,position,[length])  length=0,则默认取到最后

SELECT sex AS '性别' ,SUBSTRING(NAME,1,3) AS '名字简写' FROM emp;
SELECT SUBSTRING('dxgykx',1,3) FROM DUAL; -- 返回dxg
SELECT SUBSTRING('dxgykx',1) FROM DUAL;  -- 返回dxgykx

 LTRIM(string) RTRIM(string) TRIM(string) 去除 左、右、左右 空格

SELECT LTRIM('  dxg') FROM DUAL; 
SELECT RTRIM('dxg  ') FROM DUAL; 
SELECT TRIM('  dxg  ') FROM DUAL; 


-- 从emp表取名字,要求名字首字母小写

SELECT CONCAT(LCASE (SUBSTRING(NAME,1,1)),SUBSTRING(NAME,2)) FROM emp;  
SELECT CONCAT(LCASE (LEFT(NAME,1)),SUBSTRING(NAME,2)) FROM emp; 

数学函数

ABS(-10)-- 绝对值
BIN(1.1) -- 十进制转2进制
HEX(10) -- 十进制转十六进制
CEILING(-1.1) -- 向上取整
FLOOR(-1.1) -- 向下取整 
CONV(8,10,2) -- 把8当作10进制,转换成2进制。第一个参数化只能写数字
FORMAT(56.2345,2) -- 四舍五入保留2位小数
 LEAST(0,1,-1,20,-100) -- 求最小值
 MOD(10,3) -- 求余 10%3


 RAND() -- 产生随机数,范围在[0 , 1.0]
 RAND(3) -- 如果想要获取的随机数保持不变但范围依旧在[0 , 1.0],则参数随便键入一个数字(seed)即可,每更换一次seed,随机数就会发生改变

 日期函数

-- YEAR|MONTH|DAY|DATE(datetime)

SELECT YEAR(NOW()) FROM DUAL;

SELECT MONTH(NOW()) FROM DUAL;

SELECT DAY(NOW()) FROM DUAL;

SELECT YEAR('2022-11-11') FROM DUAL;

SELECT MONTH('2022-11-11') FROM DUAL; 

 -- 返回的是1970-1-1 到现在的秒数

SELECT UNIX_TIMESTAMP() FROM DUAL;

  

-- %Y-%m-%d 是规定好的,表示年月日  FROM_UNIXTIME()可以把UNIX_TIMESTAMP()

获取的秒数转换成指定格式的日期

SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(),'%Y-%m-%d') FROM DUAL;

-- 输出 2023-07-25(当前的时间) 

SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(),'%Y-%m-%d %H:%i:%s') FROM DUAL;

-- 输出当前时间 加上时分秒

 加密函数

SELECT USER() FROM DUAL; -- 查询数据库当前的 用户@IP地址
SELECT DATABASE(); -- 查询当前使用的数据库

-- MD5(str) 为字符串加密  信息摘要算法(无论输入要加密的字符串有多长,加密后一定是32位的)
SELECT MD5('dxg') FROM DUAL;

SELECT PASSWORD('dxg') FROM DUAL; -- mysql8 取消了 PASSWORD()

 流程控制函数

-- IF(expr1,expr2,expr3)  如果expr1 为真,则返回expr2,否则expr3
SELECT    IF(TRUE,'北京','上海') FROM DUAL; -- 返回北京


-- IF(expr1,expe2)  如果expr1不为空则返回,为空则返回expr2
SELECT    IFNULL('上海','北京') FROM DUAL; -- 返回上海
SELECT    IFNULL(NULL,'北京') FROM DUAL; -- 返回北京
SELECT    IFNULL(' ','北京') FROM DUAL; -- 返回‘ ’

 分页查询

基本语法: SELECT...LIMIT START ,ROWS

表示从START +1 行开始取,取出ROWS行,START从0开始计算

推导公式

SELECT * FROM 表名

        ORDER BY 字段

         LIMIT 每页显示记录数*(第几页-1) , 每页显示记录数

例子:按照雇员的ID号降序取出,每一页显示5条记录。请分别显示第3页,第5页对应的sql语句。
SELECT * FROM emp -- 第三页
	ORDER BY id DESC
	LIMIT	10,5;
SELECT * FROM emp -- 第五页
	ORDER BY id DESC
	LIMIT	20,5;

多子句查询(分组排序分页)

例子:统计各个部门的平均工资,并且是大于1000的,并且按照平均工资从高到低排序,取出前两行记录
SELECT depno,AVG(sal) AS avg_sal
    FROM emp
    GROUP BY deptno
    HAVING avg_sal > 1000
    ORDER BY avg_sal DESC
    LIMIT 0,2;

 多表查询

ALL

显示工资比部门30的所有员工的工资高的员工姓名、工资和部门号
SELECT ename,sal,deptno
    FROM emp 
    WHERE sal > ALL (
        SELECT sal 
        FROM emp
        WHERE deptno = 30
);

SELECT ename,sal,deptno
    FROM emp 
    WHERE sal >(
        SELECT MAX(sal) 
        FROM emp
        WHERE deptno = 30
);

ANY

显示工资比部门30的其中一个员工的工资高的员工姓名、工资和部门号
SELECT ename,sal,deptno
    FROM emp 
    WHERE sal > ANY (
        SELECT sal 
        FROM emp
        WHERE deptno = 30
);

SELECT ename,sal,deptno
    FROM emp 
    WHERE sal >(
        SELECT MIN(sal) 
        FROM emp
        WHERE deptno = 30
);

多列子查询

SELECT *
    FROM emp
    WHERE (deptno,job) = (
        SELECT deptno,job
        FROM emp
        WHERE ename = 'SMITH'
);

查询 和宋江数学、英语、语文成绩完全相同的学生
SELECT *
    FROM student
    WHERE (math,english,chinese) = (
        SELECT math、english、chinese
        FROM student
        WHERE `name` = '宋江'
)

子查询

问题:查找每个部门工资高于所属部门平均工资的人的资料
SELECT ename,sal,temp.avg_sal,emp.deptno
    FROM emp,(
        SELECT deptno,AVG(sal) AS avg_sal
        FROM emp
        GROUP BY deptno
) temp
WHERE emp.deptno = temp.deptno AND emp.sal > temp.avg_sal

表的复制

把emp表的记录复制到my_table表
 INSERT INTO my_table(
    id,`name`,sal,job,deptno)
    SELECT empno,ename,sal,job,deptno FROM emp;
表的自我复制

INSERT INTO my_table
    SELECT * FROM my_table;

删除表中重复记录

CREATE TABLE my_tab LIKE emp; -- 把emp表的结构复制到my_tab
INSERT INTO my_tab  SELECT * FROM emp; -- 设置重复记录
   

思路:
(1)先创建临时表my_tmp ,该表结构和my_tab一样
(2)把my_tmp的记录通过distinct关键字处理后,把记录复制到my_tmp
(3)清除掉my_tab记录
(4)把my_tmp表的记录复制到my_tab
(5)drop 临时表 my_tmp

CREATE TABLE my_tmp LIKE my_tab

INSERT INTO my_tmp SELECT DISTINCT * FROM my_tab;

DELETE FROM my_tab;

INSERT INTO my_tab SELECT * FROM my_tmp;

DROP TABLE my_tmp;

合并查询(UNION,UNION ALL)

UNION ALL  简单的对两条查询语句进行合并,不会消除重复行

 UNION(同UNION ALL 相同功能,但可以去掉重复行)

外连接

左外连接

如果左侧的表完全显示我们就说是左外连接

SELECT ... FROM 表1(左表) LEFT JOIN 表2(右表) ON 条件

右外连接

如果右侧的表完全显示我们就说是右外连接

SELECT ... FROM 表1(左表) RIGHT JOIN 表2(右表) ON 条件

MYSQL约束

not null 

不可插入空值,不过多介绍

unique

该字段值不可重复。但若没有指定NOT NULL(非空),则可以有多个空值

primary key

主键不再多说,下面演示复合主键

CREATE TABLE t18(
    id INT,
    `name` VARCHAR(32),
    email VARCHAR(32),
    PRIMARY KEY(id,`name`) -- 复合主键
)

foreign key

check

  

CREATE DATABASE shop_db;

CREATE TABLE goods(
	goods_id INT PRIMARY KEY,
	goods_name VARCHAR(32),
	unitprice DOUBLE CHECK (unitprice>1.0 AND unitprice<9999.99),
	category VARCHAR(32),
	provider VARCHAR(32)
)

DESC goods -- 查看表结构
 
CREATE TABLE customer(
	customer_id INT PRIMARY KEY,
	`name` VARCHAR(32) NOT NULL,
	address VARCHAR(32),
	email VARCHAR(32) UNIQUE,
	sex CHAR(1) CHECK(sex IN ('男','女')),-- sex ENUM('男','女')
	card_id CHAR(18)
)

DESC customer

CREATE TABLE purchase(
	order_id INT PRIMARY KEY,
	customer_id INT,
	goods_id INT,
	nums INT,
	FOREIGN KEY (customer_id) REFERENCES customer(customer_id),
	FOREIGN KEY (goods_id) REFERENCES goods(goods_id)
)

DESC purchase

自增长(AUTO_INCREMENT)

 

索引

 创建索引后查询速度大大减少,但只对创建索引的字段有效

索引的类型

​​​

如何选择索引(唯一和普通) 

某列的值是唯一不重复 选择 唯一索引 ,否则普通索引

创建唯一索引

CREATE UNIQUE INDEX 新的索引字段名 ON 表名(被创建索引字段)

CREATE UNIQUE INDEX id_index ON table_index(id)


ALTER TABLE t25 ADD UNIQUE id_index (id)

ALTER TABLE 表名 ADD UNIQUE 新的索引字段名 (被创建索引字段)

 创建普通索引

CREATE INDEX 新的索引名称 ON 表名 (被创建索引字段名)

CREATE INDEX id_index ON t25 (id)

ALTER TABLE 表名 ADD INDEX 新的索引名称(被创建索引字段名)

ALTER TABLE T25 ADD INDEX id_index(id)

创建主键索引 

可以直接在创建表时在字段后面键入 PRIMARY KEY  即代表主键索引

                                                                        或

ALTER TABLE 表名 ADD PRIMARY KEY (被创建索引字段名)

ALTER TABLE t26 ADD PRIMARY KEY (id)

查询索引

SHOW INDEX FROM 表名
SHOW INDEXES FROM 表名
SHOW KEYS FROM 表名

 删除索引

DROP INDEX 索引名称 ON 表名
        删除主键索引
ALTER TABLE 表名 DROP PRIMARY KEY

修改索引

先删除再添加

事务

 START TRANSACTION    或 SET AUTOCOMMIT=OFF       开启事务

 SAVEPOINT 标记名                 设置保存点

 ROLLBACK TO 标记名             回滚到标记点 倘若有多个标记点,回到早的标记点,晚的就会被删除,无法返回

 ROLLBACK                                 直接回退到事务开始的状态

 COMMIT                                 提交事务,删除保存点,无法返回保存点

(类似快照的概念)

提交事务 COMMIT

当执行了之后,会确认事务的变化、结束事务、删除保存点、释放锁,数据生效。当使用COMMIT语句结束事务后,其他会话[其他连接]将可以查看到事务变化后的新数据[所有数据就正式生效]

如果没开启事务,所有的操作都不能操作。开启了事务,但没设保存点,执行ROLLBACK默认返回事务最开始

事务的隔离

隔离级别 (和事务相关)

√代表可能出现   ×代表不会出现

 读未提交:事务A的DML操作事务B可以看到

 查看隔离级别
SELECT @@tx_isolation
查看系统隔离级别 
SELECT @@global.tx_isolation
设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL 隔离级别
设置系统隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL 隔离级别
重点 

ACID 

 存储引擎

 MEMORY是内存级别,插入速度非常快

 如何选择存储引擎

指令修改存储引擎

ALTER TABLE 表名 ENGINE = 存储引擎

视图

视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含列,其数据来自对应的真实表

总结:

1.视图是根据基表(或者多个基表)来创建的 视图是虚拟的表

2.视图也有列,数据来自基表

3.通过视图可以修改表的数据

4.基表的改变,也会影响到视图的数据

 视图的创建修改

CREATE VIEW 视图名 AS SELECT 语句

ALTER VIEW 视图名 AS SELECT 语句 

SHOW CREATE VIEW 视图名

DROP VIEW 视图名1,视图名2

视图的最佳实践

MySQL管理 

创建用户

CREATE USER '用户名' @ '允许登录的位置' IDENTIFIED BY '密码'
创建用户,同时指定密码

删除用户

DROP USER '用户名' @ '允许登录位置'

 修改密码

修改自己的密码

SET PASSWORD = PASSWORD('密码')

修改其他用户 的密码(需要有修改其他用户密码的权限)

SET PASSWORD FOR '用户名' @ '登录位置' = PASSWORD('密码')

细节说明

 

JDBC

代码实现  

MySQL 5 之后的驱动包,可以省略注册驱动的步骤,即省略了:

Class.forName("com.mysql.jdbc.Driver") .转而代之的是自动加载jar包中

META-INF/services/java.sql.Driver文件中的驱动类

 如果链接的是自己的主机(前提是端口号为3306),可写:

String url="jdbc:mysql:///dxgsql_01?useSSL=false"; 标黄的是去除SSl警告

public class JDBC_demo {
    public static void main(String[]args) throws Exception{
        //获取链接
        String url="jdbc:mysql://127.0.0.1:3306/dxgsql_01";
        String username="root";
        String password="123456";
        Connection conn = DriverManager.getConnection(url, username, password);
        //定义sql
        String sql = "UPDATE tb_user SET PASSWORD = 3000 WHERE id =1";
        //获取执行sql的对象 Statement
        Statement statement = conn.createStatement();
        //执行sql
        int count = statement.executeUpdate(sql);//受影响行数
        //处理结果
        System.out.println(count);
        //释放资源
        statement.close();
        conn.close();

    }
}

 DriverManager

参数: 

  • url 连接路径
    • jdbc:mysql://IP地址(域名):端口号/数据库名称[?参数键值对1&参数键值对2]
    • 细节:useSSL=false参数,禁用安全连接方式,解决警告提示
  • user:用户名
  • password:密码
String url="jdbc:mysql://127.0.0.1:3306/dxgsql_01?useSSL=false";
String username="root";
String password="123456";
Connection conn = DriverManager.getConnection(url, username, password);

 Connection

获取执行SQL的对象

  • 普通执行SQL对象
    • createStatement()
  • 预编译SQL的执行SQL对象:防止SQL注入
    • preparedStatement(sql)
  • 执行存储过程的对象
    • prepareCall(sql)

与事务结合使用

  • 开启事务
    • setAutoCommit( true | false )  true为自动提交事务,false为手动提交事务即开启事务
  • 提交事务
    • commit()
  • 回滚事务
    • rollback()

事务代码

异常处理机制(try..catch)中开启事务之后。如果一条出错误就会执行rollback(),数据库不会进行更改。如果没有开启事务,则第一条数据库指令会正常执行,第二条就会报错

public class JDBC_demo_Connection {
    public static void main(String[]args) throws Exception{

        //获取链接
        String url="jdbc:mysql://127.0.0.1:3306/dxgsql_01?useSSL=false";
        String username="root";
        String password="123456";
        Connection conn = DriverManager.getConnection(url, username, password);
        //定义sql
        String sql1 = "UPDATE tb_user SET PASSWORD = 5000 WHERE id =1";
        String sql2 = "UPDATE tb_user SET PASSWORD = 5000 WHERE id =2";
        //获取执行sql的对象 Statement
        Statement statement = conn.createStatement();

        try {
            //开启事务
            conn.setAutoCommit(false);
            //执行sql
            int count1 = statement.executeUpdate(sql1);
            //处理结果
            System.out.println(count1);
            int i=3/0;//出错
            //执行sql
            int count2 = statement.executeUpdate(sql2);
            //处理结果
            System.out.println(count2);
            //提交事务
            conn.commit();
        } catch (Exception e) {
            //回滚事务
            conn.rollback();
            throw new RuntimeException(e);
        }

        //释放资源
        statement.close();
        conn.close();
    }
}

Statemenet

PreparedStatement

作用: 预编译SQL语句和预防SQL注入的问题

SQL注入问题解释

 // 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
       String url = "jdbc:mysql:///db1?useSSL=false";
       String username = "root";
       String password = "1234";
       Connection conn = DriverManager.getConnection(url, username, password);

       // 接收用户输入 用户名和密码
        String name = "zhangsan";
        String pwd = "' or '1' = '1";

        String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";

        // 获取stmt对象
        Statement stmt = conn.createStatement();

        // 执行sql
        ResultSet rs = stmt.executeQuery(sql);

        // 判断登录是否成功
        if(rs.next()){
            System.out.println("登录成功~");
        }else{
            System.out.println("登录失败~");
        }

        //7. 释放资源
        rs.close();
        stmt.close();
        conn.close();

当参数值传入sql语句时,会利用字符串拼接使得查询条件变成true

 String name = "zhangsan";
 String pwd = "' or '1' = '1";
 String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";

sql会显示如下所示,where查询就会变为真,去查询数据库信息直到找出正确的信息

select * from tb_user where username = 'hfkjsfhskj' and password = '' or '1' = '1'

解决SQL注入问题依靠PreparedStatement

把接收参数传递的参数改成 ?,再在下面给每个?赋值,这样就避免了拼接字符串

 //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
       String url = "jdbc:mysql:///db1?useSSL=false";
       String username = "root";
       String password = "1234";
       Connection conn = DriverManager.getConnection(url, username, password);

       // 接收用户输入 用户名和密码
        String name = "zhangsan";
        String pwd = "' or '1' = '1";

        // 定义sql
        String sql = "select * from tb_user where username = ? and password = ?";

        // 获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

        // 设置?的值
        pstmt.setString(1,name);
        pstmt.setString(2,pwd);

        // 执行sql
        ResultSet rs = pstmt.executeQuery();

        // 判断登录是否成功
        if(rs.next()){
            System.out.println("登录成功~");
        }else{
            System.out.println("登录失败~");
        }

        //7. 释放资源
        rs.close();
        pstmt.close();
        conn.close();

介绍其预编译功能

useServerPrepStmts=true 参数开启预编译功能

 

开启预编译步骤

//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        // useServerPrepStmts=true 参数开启预编译功能
        String url = "jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);

        // 接收用户输入 用户名和密码
        String name = "zhangsan";
        String pwd = "' or '1' = '1";

        // 定义sql
        String sql = "select * from tb_user where username = ? and password = ?";

        // 获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

        // 设置?的值
        pstmt.setString(1,name);
        pstmt.setString(2,pwd);
        ResultSet rs = null;
        // 执行sql
        rs = pstmt.executeQuery();


        // 设置?的值
        pstmt.setString(1,"aaa");
        pstmt.setString(2,"bbb");

        // 执行sql
        rs = pstmt.executeQuery();


        // 判断登录是否成功
        if(rs.next()){
            System.out.println("登录成功~");
        }else{
            System.out.println("登录失败~");
        }

        //7. 释放资源
        rs.close();
        pstmt.close();
        conn.close();

 

 ResultSet

 pojo包下的Account类

pojo包在实际的开发中往往存放一些实体类

package com.itheima.pojo;
public class Account {

    private int id;
    private String name;
    private double money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

实现代码

public void testResultSet2() throws  Exception {
       
        //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        String url = "jdbc:mysql:///db1?useSSL=false";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);

        //3. 定义sql
        String sql = "select * from account";

        //4. 获取statement对象
        Statement stmt = conn.createStatement();

        //5. 执行sql
        ResultSet rs = stmt.executeQuery(sql);

        // 创建集合
        List<Account> list = new ArrayList<>();

        // 6.1 光标向下移动一行,并且判断当前行是否有数据
        while (rs.next()){
            Account account = new Account();

            //6.2 获取数据  getXxx()
            int id = rs.getInt("id");
            String name = rs.getString("name");
            double money = rs.getDouble("money");

            //赋值
            account.setId(id);
            account.setName(name);
            account.setMoney(money);

            // 存入集合
            list.add(account);
        }

        System.out.println(list);

        //7. 释放资源
        rs.close();
        stmt.close();
        conn.close();
    }

 数据库连接池

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值