失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Java_16_JDBC连接池:JDBC(连接数据库技术)

Java_16_JDBC连接池:JDBC(连接数据库技术)

时间:2018-07-11 09:06:03

相关推荐

Java_16_JDBC连接池:JDBC(连接数据库技术)

摘要

一、JDBC介绍

客户端操作MySQL数据库的方式

1、使用第三方客户端来访问MySQL: SQLyog, Navicat, SQLWave,MyDB Studio, EMS SQLManager for MySQL

2、使用MySQL自带的命令行方式

3、通过Java程序来访问MySQL数据库(即JDBC),今天要学习的内容

1、什么是JDBC

JDBC概念: 英文全称Java DataBase Connectivity,中文全称Java连接数据库的技术

作用:通过Java程序来对数据库进行各种操作。

2、JDBC的由来

直接写Java代码操作数据库存在的问题:

1、不知道MySQL数据库的操作方式,解析方式

2、代码繁琐,写起来麻烦

3、MySQL和Oracle等其他数据库的操作方式和解析方式不同,每个数据库都要写一套代码

4、MySQL和Oracle等其他数据库相互切换麻烦

JDBC规范定义接口,具体的实现由各大数据库厂商来实现

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

3、JDBC的好处

1、我们只需要会调用JDBC接口中的方法即可,使用简单

2、使用同一套Java代码,进行少量的修改就可以访问其他JDBC支持的数据库

4、JDBC用到的包

5、JDBC核心API

JDBC操作数据库流程

小结

二、利用JDBC获取Java程序与数据库的连接

Connection接口表示Java程序与数据库之间的连接,只有拿到Connection对象才能操作数据库。

JDBC获取连接步骤

1、导入驱动Jar包

2、注册驱动

3、获取连接

1、导入驱动Jar包

在IDEA工程下,创建一个名称为lib(Libraries)的文件夹,专门用来放jar包。并把数据库驱动包放到这个文件夹

右键点击lib文件夹->“add as library”->确定

2、注册驱动(Driver类和DriverManager类)

我们Java程序需要通过数据库驱动才能连接到数据库,因此需要注册驱动。MySQL的驱动的入口是:com.mysql.jdbc.Driver类

com.mysql.jdbc.Driver类是数据库驱动对象,

java.sql.DriverManager类用来注册和管理数据库驱动,和数据库建立连接获得连接对象

注册驱动的作用:告诉JVM接下来操作的是哪个厂商的数据库

注册驱动的方法

java.sql.DriverManager类用于注册驱动。提供如下方法注册驱动

//向DriverManager注册给定驱动程序。static void registerDriver(Driver driver)

registerDriver注册驱动示例

DriverManager.registerDriver(驱动对象);传入对应参数即可

public class Demo01 {public static void main(String[] args) throws Exception {//注册驱动DriverManager.registerDriver(new com.mysql.jdbc.Driver());}

registerDriver注册驱动存在的问题(重复注册)

通过查询com.mysql.jdbc.Driver源码,我们发现Driver类又"主动"将自己进行注册

public class Driver extends NonRegisteringDriver implements java.sql.Driver {static {try {// 自己自动注册java.sql.DriverManager.registerDriver(new Driver());} catch (SQLException E) {throw new RuntimeException("Can't register driver!");}}public Driver() throws SQLException {}}

区分 Driver类和Driver接口

1、com.mysql.jdbc.Driver是类,java.sql.Driver是接口

2、com.mysql.jdbc.Driver类 继承 NoRegisteringDriver类,NoRegisteringDriver类实现java.sql.Driver接口

注意:

使用DriverManager.registerDriver (new com.mysql.jdbc.Driver())方式注册驱动,存在两方面不足

1、硬编码,后期不易于程序扩展和维护

2、驱动被注册两次

DriverManager.registerDriver(driver)会触发两次注册,不推荐使用

forName注册驱动示例(解决重复注册)

使用Class. forName (“com.mysql.jdbc.Driver”);加载驱动,这样驱动只会注册一次

public class Demo01 {public static void main(String[] args) throws Exception {Class.forName("com.mysql.jdbc.Driver"); // 后期可将"com.mysql.jdbc.Driver"字符串写在文件中.}}

3、获取连接(DriverManager类)

java. sql.DriverManager类中有如下方法获取数据库连接

static ConnectiongetConnection(String url, Properties info)* 与数据库建立连接并获得连接对象(等价于Socket对象)* url:数据库连接字符串* info:属性集合:用来存储用户名和密码,可以将用户名和密码存储到配置文件static ConnectiongetConnection(String url, String user, String password)* 与数据库建立连接并获得连接对象(等价于Socket对象)* url:数据库连接字符串* user:用户名 root* password: 密码 root

参数说明

1、string url:连接数据库的URL,用于说明连接数据库的位置

2、string user:数据库的账号

3、string password:数据库的密码

连接数据库的URL地址格式:

协议名:子协议://服务器名或IP地址:端口号/数据库名?参数二参数值

MySQL数据库的URL写法:

jdbc:mysql://localhost:3306/day24

如果是本地服务器localhost,端口号是默认的3306,则可以省略简写为

jdbc:mysql:///day24

注意事项

如果查询出来的数据出现乱码,需要加上参数:?characterEncoding=utf8

表示让数据库以UTF-8编码来处理数据。如: jdbc:mysql://localhost:3306/day24?characterEncoding=utf8

获取连接示例

DriverManager.getConnection(url, user, password);传入对应参数即可

public class Demo01 {public static void main(String[] args) throws Exception {Class.forName("com.mysql.jdbc.Driver");// 连接到MySQL// url: 连接数据库的URL// user: 数据库的账号// password: 数据库的密码Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day24", "root", "root");System.out.println(conn);}}

连接成功

连接失败

三、使用JDBC实现对单表数据增删改查

我们要对数据库进行增、删、改、查,需要使用statement对象来执行SQL语句。

1、获取Statement对象(通过Connection接口获取)

获取到statement对象,要先获取连接connection对象(通过驱动管理DriverManager类获取)

在java.sql.Connection接口中有如下方法获取到statement对象(connection对象获取statement对象)

Statement createStatement()//创建一个 Statement 对象来将 SQL 语句发送到数据库

Statement 对象方法

boolean execute(String sql)

execute方法说明:此方法可以执行任意sql语句。返回boolean值,表示是否返回Resultset结果集。仅当执行select语句,且有返回结果时返回true,其它语句都返回false;

int executeUpdate(String sql)

executeUpdate方法说明:根据执行的DML (INSERT、UPDATE、DELETE)语句,返回受影响的行数

ResultSet executeQuery(String sql)

executeQuery方法说明:根据查询语句返回结果集,只能执行SELECT语句

注意:

在MySQL中,只要不是查询就是修改。

executeUpdate:用于执行增删改

executeQuery:用于执行查询

2、使用JDBC实现增删改查步骤

1、注册驱动

2、获取连接

3、获取Statement对象

4、使用Statement对象执行SQL语句

5、释放资源

3、JDBC增删改案例

使用JDBC增删改示例1

JDBC执行DDL语句_创建表

使用JDBC在MySQL的数据库中创建一张学生表

1) id 是主键,整数类型,自增长

2) name 是varchar(20),非空

3) 性别 是char类型

4) 生日 是date类型

package com.itheima._03执行DDL语句;import org.junit.Test;import java.sql.Connection;import java.sql.DriverManager;import java.sql.Statement;/**目标:使用JDBC在MySQL的数据库中创建一张学生表实现步骤:1. 注册驱动2. 获得连接对象:Connection对象3. 获得SQL语句发送对象:Statement对象4. 准备SQL语句:String sql = ...5. 执行SQL语句6. 关闭连接释放资源:Connection和Statement*/public class JDBCDemo01 {@Testpublic void testCreateTable()throws Exception{// 1. 注册驱动Class.forName("com.mysql.jdbc.Driver");// 2. 获得连接对象:Connection对象Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day16", "root", "root");// 3. 获得SQL语句发送对象:Statement对象Statement stmt = conn.createStatement();// 4. 准备SQL语句:String sql = ...String sql = "create table student(" +"id int primary key auto_increment," +"name varchar(20) not null," +"gender char(1)," +"birthday date);";// 5. 执行SQL语句stmt.execute(sql);// 6. 关闭连接释放资源:Connection和Statementstmt.close();conn.close();}}

JDBC执行DML语句_增删改

package com.itheima._04执行DML语句;import org.junit.Test;import java.sql.Connection;import java.sql.DriverManager;import java.sql.Statement;/**目标:使用JDBC实现增删改功能实现步骤1. 注册驱动2. 获得连接对象3. 获得SQL语句发送对象4. 准备SQL语句5. 执行SQL语句并获得结果6. 关闭连接释放资源*/public class JDBCDemo01 {// 插入数据@Testpublic void testInsert() throws Exception{// 1. 注册驱动Class.forName("com.mysql.jdbc.Driver");// 2. 获得连接对象Connection conn = DriverManager.getConnection("jdbc:mysql:///day16", "root", "root");// 3. 获得SQL语句发送对象Statement stmt = conn.createStatement();// 4. 准备SQL语句String sql = "insert into student values(null,'小苍','女','2000-11-10'),(null,'小武','男','1999-12-20')";// 5. 执行SQL语句并获得结果int row = stmt.executeUpdate(sql);System.out.println("row = " + row);// 6. 关闭连接释放资源stmt.close();conn.close();}// 修改数据@Testpublic void testUpdate()throws Exception{// 1. 注册驱动Class.forName("com.mysql.jdbc.Driver");// 2. 获得连接对象Connection conn = DriverManager.getConnection("jdbc:mysql:///day16", "root", "root");// 3. 获得SQL语句发送对象Statement stmt = conn.createStatement();// 4. 准备SQL语句String sql = "update student set name = '武大郎', gender = '男' where id = 4;";// 5. 执行SQL语句并获得结果int row = stmt.executeUpdate(sql);System.out.println("row = " + row);// 6. 关闭连接释放资源stmt.close();conn.close();}// 删除数据:删除id为2的学生@Testpublic void testDelete() throws Exception{// 1. 注册驱动Class.forName("com.mysql.jdbc.Driver");// 2. 获得连接对象Connection conn = DriverManager.getConnection("jdbc:mysql:///day16", "root", "root");// 3. 获得SQL语句发送对象Statement stmt = conn.createStatement();// 4. 准备SQL语句String sql = "delete from student where id = 2;";// 5. 执行SQL语句并获得结果int row = stmt.executeUpdate(sql);System.out.println("row = " + row);// 6. 关闭连接释放资源stmt.close();conn.close();}}

使用JDBC增删改示例2

准备数据

-- 创建分类表CREATE TABLE category (cid INT PRIMARY KEY AUTO_INCREMENT,cname VARCHAR(100));-- 初始化数据INSERT INTO category (cname) VALUES('家电');INSERT INTO category (cname) VALUES('服饰');INSERT INTO category (cname) VALUES('化妆品');

代码实现

public class Demo03 {public static void main(String[] args) throws Exception {Class.forName("com.mysql.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");System.out.println(conn);// String sql = "SELECT * FROM category;";// 从连接中拿到一个Statement对象Statement stmt = conn.createStatement();// 1.插入记录String sql = "INSERT INTO category (cname) VALUES ('手机');";int i = stmt.executeUpdate(sql);System.out.println("影响的行数:" + i);// 2.修改记录sql = "UPDATE category SET cname='汽车' WHERE cid=4;";i = stmt.executeUpdate(sql);System.out.println("影响的行数:" + i);// 3.删除记录sql = "DELETE FROM category WHERE cid=1;";i = stmt.executeUpdate(sql);System.out.println("影响的行数:" + i);// 释放资源stmt.close();conn.close();}}

效果

4、使用JDBC查询单表

JDBC进行查询操作时,使用statement对象的executeQuery方法,返回值是ResultSet。

ResultSet对象的作用:用来封装满足查询条件的记录信息

ResultSet executeQuery(String sql)

Resultset用于保存执行查询SQL语句的结果。我们不能一次性取出所有的数据,需要一行一行的取出。

ResultSet的原理

1、ResultSet内部有一个指针,刚开始记录开始位置

2、调用next方法, ResultSet内部指针会移动到下一行数据

3、我们可以通过ResultSet得到一行数据getxxx得到某列数据

ResultSet原理图(和迭代器Iterator相似)

ResultSet的API

ResultSet获取数据的API其实ResultSet获取数据的API是有规律的get后面加数据类型。我们统称getxxx()

使用JDBC查询数据库中的数据的步骤

1、注册驱动

2、获取连接

3、获取到Statement

4、使用Statemen对象executeQuery方法t执行SQL

5、ResultSet处理结果

6、关闭资源

JDBC查询数据库单表示例1

public class Demo04 {public static void main(String[] args) throws Exception {Class.forName("com.mysql.jdbc.Driver");Connection conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");Statement stmt = conn.createStatement();String sql = "SELECT * FROM category;";ResultSet rs = stmt.executeQuery(sql);// 内部有一个指针,只能取指针指向的那条记录while (rs.next()) {// 指针移动一行,有数据才返回true// 取出数据int cid = rs.getInt("cid");String cname = rs.getString("cname");System.out.println(cid + " == " + cname);}// 关闭资源rs.close();stmt.close();conn.close();}}

案例效果

注意:

1、如果光标在第一行之前,使用rs.getXxX()取列值,报错: Before start of result set

2、如果光标在最后一行之后,使用rs.getXXX()获取列值,报错: After end of result set

JDBC查询数据库单表示例2

package com.itheima._05执行DQL语句;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.Statement;/**目标:使用JDBC实现查询功能需求:查询所有学生信息并输出实现步骤:1. 注册驱动2. 获得连接对象3. 获得SQL语句发送对象4. 准备要执行的SQL语句5. 执行SQL语句并获得结果集对象6. 通过结果集对象获得每行每列的值7. 关闭连接释放资源注意事项1. 指针指向第一行记录之前还调用getXxx方法就会出现如下异常java.sql.SQLException: Before start of result set2. 指针指向最后一行记录之后还调用getXxx方法就会出现如下异常java.sql.SQLException: After end of result set*/public class JDBCDemo01 {public static void main(String[] args) throws Exception{// 1. 注册驱动Class.forName("com.mysql.jdbc.Driver");// 2. 获得连接对象Connection conn = DriverManager.getConnection("jdbc:mysql:///day16", "root", "root");// 3. 获得SQL语句发送对象Statement stmt = conn.createStatement();// 4. 准备要执行的SQL语句String sql = "select * from student;";// 5. 执行SQL语句并获得结果集对象ResultSet rs = stmt.executeQuery(sql);// 6. 通过结果集对象获得每行每列的值while (rs.next()) {// 根据列号获得每列的值/* // 获得id值int id = rs.getInt(1);// 获得姓名String name = rs.getString(2);// 获得性别String gender = rs.getString(3);// 获得生日String birthday = rs.getString(4);System.out.println(id+":" + name + ":" + gender + ":" + birthday);*/// 根据列名获得每列的值// 获得id值int id = rs.getInt("id");// 获得姓名String name = rs.getString("name");// 获得性别String gender = rs.getString("gender");// 获得生日String birthday = rs.getString("birthday");System.out.println(id+":" + name + ":" + gender + ":" + birthday);}// 7. 关闭连接释放资源rs.close();stmt.close();conn.close();}}

总结:

我们使用JDBC操作数据库的步骤都是固定的。不同的地方是在编写SQL语句

四、JDBC事务

之前我们是使用MySQL的命令来操作事务。接下来我们使用DBC来操作银行转账的事务。

Connection接口中与事务有关的方法

void setAutoCommit(boolean autoCommit) throws SQLException;false:开启事务, ture:关闭事务void commit() throws SQLException;提交事务void rollback() throws SQLException;回滚事务

JDBC事务使用步骤

1、注册驱动

2、获取连接

3、获取到Statement

4、开启事务

5、使用Statement执行SQL

6、提交或回滚事务

7、关闭资源

JDBC事务示例1

public class Demo05 {public static void main(String[] args) {Connection conn = null;try {// 拿到连接Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");// 开启事务conn.setAutoCommit(false);Statement pstmt = conn.createStatement();// 张三减500String sql = "UPDATE account SET balance = balance - 500 WHERE id=1;";pstmt.executeUpdate(sql);// 模拟异常// int i = 10 / 0;// 李四加500sql = "UPDATE account SET balance = balance + 500 WHERE id=2;";pstmt.executeUpdate(sql);pstmt.close();// 成功,提交事务System.out.println("成功,提交事务");mit();} catch (Exception e) {// 失败,回滚事务try {System.out.println("出现了异常,回滚事务");conn.rollback();} catch (SQLException e1) {e1.printStackTrace();}} finally {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}

案例效果

JDBC事务示例2

package com.itheima._06JDBC事务;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;/**目标:使用JDBC实现事务的管理需求:Jack给rose转500块实现步骤1. 注册驱动2. 获得连接对象3. 获得SQL语句发送对象4. 准备SQL语句:扣钱SQL5. 执行扣钱SQL语句6. 准备SQL语句:加钱SQL7. 执行加钱SQL语句8. 关闭资源Collection接口中与事务管理相关的方法void setAutoCommit(boolean b);设置是否自动提交事务true:自动提交事务false:禁止自动提交事务,等价于 start transaction;void commit(); 提交事务void rollback(); 回滚事务*/public class JDBCDemo01 {public static void main(String[] args) {// 声明连接对象Connection conn = null;// 声明SQL发送对象Statement stmt = null;try{// 1. 注册驱动Class.forName("com.mysql.jdbc.Driver");// 2. 获得连接对象conn = DriverManager.getConnection("jdbc:mysql:///day16", "root", "root");// 开启事务:禁止自动提交事务conn.setAutoCommit(false);// 3. 获得SQL语句发送对象stmt = conn.createStatement();// 4. 准备SQL语句:扣钱SQLString sql01 = "update account set balance = balance - 500 where id = 1";// 5. 执行扣钱SQL语句int row = stmt.executeUpdate(sql01);System.out.println("扣钱:" + row);// 模拟异常// System.out.println(100/0);// 6. 准备SQL语句:加钱SQLString sql02 = "update account set balance = balance + 500 where id = 2";// 7. 执行加钱SQL语句row = stmt.executeUpdate(sql02);System.out.println("加钱:" + row);// 提交事务mit();} catch(Exception e){// e.printStackTrace();try {System.out.println("回滚了事务...");// 回滚事务conn.rollback();} catch (SQLException ex) {ex.printStackTrace();}}finally {// 8. 关闭资源if (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}}

五、JDBC工具类

通过上面案例需求我们会发现每次去执行SQL语句都需要注册驱动,获取连接,得到Statement,以及释放资源。发现很多重复的劳动,我们可以将重复的代码定义到某个类的方法中。直接调用方法,可以简化代码。那么我们接下来定义一个JDBCutil类。把注册驱动,获取连接,得到Statement,以及释放资源的代码放到这个类的方法中。以后直接调用方法即可。

创建工具类的目的:将重复的代码定义到某个类的方法中,直接调用方法,可以简化代码。

编写JDBC工具类步骤

1、将固定字符串定义为常量

2、在静态代码块中注册驱动(只注册一次)

3、提供一个获取连接的方法static Connection getConneciton();

4、定义关闭资源的方法close(Connection conn, Statement stmt, Resultset rs)

5、重载关闭方法close(Connection conn, statement stmt)

工具类代码

package com.itheima._07JDBC工具类;import java.sql.*;/**创建工具类的目的:将重复的代码定义到某个类的方法中,直接调用方法,可以简化代码。实现工具类的步骤1. 将固定字符串定义为常量2. 在静态代码块中注册驱动(只注册一次)3. 提供一个获取连接的方法:static Connection getConneciton();4. 定义关闭资源的方法:close(Connection conn, Statement stmt, ResultSet rs)5. 重载关闭方法:close(Connection conn, Statement stmt)*/public class JDBCUtils {// 1. 将固定字符串定义为常量private static final String URL = "jdbc:mysql:///day16";private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";private static final String USER = "root";private static final String PASSWORD = "root";// 2. 在静态代码块中注册驱动(只注册一次)static {try{Class.forName(DRIVER_CLASS);} catch(Exception e){e.printStackTrace();}}// 3. 提供一个获取连接的方法:static Connection getConnection();public static Connection getConnection(){try {return DriverManager.getConnection(URL, USER, PASSWORD);} catch (SQLException e) {throw new RuntimeException(e);}}// 4. 定义关闭资源的方法:close(Connection conn, Statement stmt, ResultSet rs)//关闭资源方法(先关闭ResultSet,再关闭statement,最后关闭Connection)public static void close(Connection conn, Statement stmt, ResultSet rs){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();}}}// 5. 重载关闭方法:close(Connection conn, Statement stmt)//关闭只有2个对象的方法,非查询的JDBC没有ResultSet不用关闭public static void close(Connection conn, Statement stmt){close(conn, stmt, null);}}

使用JDBC工具类案例

public class Demo06 {public static void main(String[] args) throws Exception {createTable();// addEmployee();// updateEmployee(); // deleteEmployee();}// 删除员工public static void deleteEmployee() throws Exception {Connection conn = JDBCUtils.getConnection();Statement stmt = conn.createStatement();// 删除id为3的员工String sql = "DELETE FROM employee WHERE id=3;";int i = stmt.executeUpdate(sql);System.out.println("影响的行数: " + i);// stmt.close();// conn.close();// JDBCUtils.close(conn, stmt, null);JDBCUtils.close(conn, stmt);}// 修改员工public static void updateEmployee() throws Exception {Connection conn = JDBCUtils.getConnection();Statement stmt = conn.createStatement();// 将id为3的员工姓名改成田七,地址改成天津String sql = "UPDATE employee SET address='天津', name='田七' WHERE id=3;";int i = stmt.executeUpdate(sql);System.out.println("影响的行数: " + i);// stmt.close();// conn.close();// JDBCUtils.close(conn, stmt, null);JDBCUtils.close(conn, stmt);}// 定义添加员工public static void addEmployee() throws Exception {Connection conn = JDBCUtils.getConnection();Statement stmt = conn.createStatement();// 添加4个员工String sql = "INSERT INTO employee VALUES (NULL, '张三4', 20, '北北京'),"+ " (NULL, '李李四4', 21, '南京'),"+ " (NULL, '王五4', 18, '东京'),"+ " (NULL, '赵六4', 17, '西安');";int i = stmt.executeUpdate(sql);System.out.println("影响的行数: " + i);// stmt.close();// conn.close();// JDBCUtils.close(conn, stmt, null);JDBCUtils.close(conn, stmt);}// 创建表public static void createTable() throws Exception {Connection conn = JDBCUtils.getConnection();Statement stmt = conn.createStatement();String sql = "CREATE TABLE IF NOT EXISTS employee ("+ " id INT PRIMARY KEY AUTO_INCREMENT,"+ " name VARCHAR(20) UNIQUE NOT NULL,"+ " age INT,"+ " address VARCHAR(50)"+ ");";int i = stmt.executeUpdate(sql);System.out.println("ok");// stmt.close();// conn.close();// JDBCUtils.close(conn, stmt, null);JDBCUtils.close(conn, stmt);}}

六、JDBC实现登录案例

案例需求

模拟用户输入账号和密码登录网站

案例效果

1、输入正确的账号,密码,显示登录成功

2、输入错误的账号,密码,显示登录失败

步骤分析

1. 准备数据表和测试数据2. 创建键盘录入对象3. 接收用户名和密码4. 获得连接对象5. 获得SQL语句发送对象6. 准备要执行的SQL语句7. 执行SQL语句并获得结果集对象8. 根据结果集对象判断是否登录成功9. 关闭资源

JDBC实现登录 示例1

1、创建一个用户表保存用户的账号和密码,并添加一些数据,SQL语句如下:

CREATE TABLE USER (id INT AUTO_INCREMENT PRIMARY KEY,NAME VARCHAR(50),PASSWORD VARCHAR(50));INSERT INTO USER (NAME, PASSWORD) VALUES('admin', '123'), ('test', '123'), ('gm', '123');

2、编写代码让用户输入账号和密码

public class Demo07 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入账号: ");String name = sc.nextLine();System.out.println("请输入密码: ");String password = sc.nextLine(); }

3、使用SQL根据用户的账号和密码去数据库查询数据

public class Demo07 {public static void main(String[] args) throws Exception {// 让用户输入账号和密码Scanner sc = new Scanner(System.in);System.out.println("请输入账号: ");String name = sc.nextLine();System.out.println("请输入密码: ");String password = sc.nextLine();// 使用SQL根据用户的账号和密码去数据库查询数据Connection conn = JDBCUtils.getConnection();Statement stmt = conn.createStatement();String sql = "SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';";}}

4、如果查询到数据,说明登录成功,如果查询不到数据,说明登录失败

public class Demo07 {public static void main(String[] args) throws Exception {// 让用户输入账号和密码Scanner sc = new Scanner(System.in);System.out.println("请输入账号: ");String name = sc.nextLine();System.out.println("请输入密码: ");String password = sc.nextLine();// 使用SQL根据用户的账号和密码去数据库查询数据Connection conn = JDBCUtils.getConnection();Statement stmt = conn.createStatement();String sql = "SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';";// 如果查询到数据,说明登录成功,如果查询不不到数据,说明登录失败ResultSet rs = stmt.executeQuery(sql);if (rs.next()) {//能进来查询到了了数据.String name2 = rs.getString("name");System.out.println("欢迎您," + name2);} else {//查询不不到数据,说明登录失败System.out.println("账号或密码错误...");}JDBCUtils.close(conn, stmt, rs);}}

JDBC实现登录 示例2

1、准备数据表和用户数据

-- 准备数据表create table user(id int primary key auto_increment,username varchar(20) not null unique,password varchar(20) not null );-- 测试数据insert into user(username,password) values('jack','rose'),('rose','laowang');select * from user;

2、实现代码

package com.itheima._08JDBC登录案例;import com.itheima._07JDBC工具类.JDBCUtils;import java.sql.Connection;import java.sql.ResultSet;import java.sql.Statement;import java.util.Scanner;/**目标:使用JDBC实现登录功能实现步骤2. 创建键盘录入对象3. 接收用户名和密码4. 获得连接对象5. 获得SQL语句发送对象6. 准备要执行的SQL语句7. 执行SQL语句并获得结果集对象8. 根据结果集对象判断是否登录成功9. 关闭资源*/public class LoginDemo01 {public static void main(String[] args) throws Exception{// 2. 创建键盘录入对象Scanner sc = new Scanner(System.in);// 3. 接收用户名和密码System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();// 4. 获得连接对象Connection conn = JDBCUtils.getConnection();// 5. 获得SQL语句发送对象Statement stmt = conn.createStatement();// 6. 准备要执行的SQL语句String sql = "select * from user where username = '"+username+"' and password = '"+password+"';";System.out.println("sql = " + sql);// 7. 执行SQL语句并获得结果集对象ResultSet rs = stmt.executeQuery(sql);// 8. 根据结果集对象判断是否登录成功if (rs.next()){System.out.println("欢迎你," + username);} else {System.out.println("用户名或密码错误...");}// 9. 关闭资源JDBCUtils.close(conn,stmt,rs);}}

登录案例的SQL注入问题

SQL注入的概念:用户输入的内容作为了SQL语法的一部分,改变了原有SQL语句的含义。

SQL注入示例

在登录案例中当我们输入以下密码,我们发现我们账号和密码都不对竟然登录成功了了

请输入用户名:hehe请输入密码:a' or '1'='1

问题分析:

// 代码中的SQL语句"SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';";// 将用户输入的账号密码拼接后"SELECT * FROM user WHERE name='hehe' AND password='a' or '1'='1';"

我们让用户输入的密码和SQL语句进行字符串拼接。用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义,以上问题称为SQL注入。要解决SQL注入就不能让用户输入的密码和我们的SQL语句进行简单的字符串拼接。需要使用PreparedSatement接口(预编译对象)解决SQL注入。

小结

1、SQL注入的概念:用户输入的内容作为了SQL语法的一部分,改变了原有SQL语句的含义。

2、如何解决SQL注入问题:不能将用户输入的内容和SQL语句进行拼接了,此时发送SQL语句不能使用Statement要使用PreparedStatement来发送SQL语句到数据库执行了。

七、PreparedStatement预编译对象(解决SQL注入问题)

我们写的SQL语句让数据库执行,数据库不是直接执行SQL语句字符串。和Java一样,数据库需要执行编译后的SQL语句(类似ava编译后的字节码文件)。

1、Statement执行原理

Satement对象每执行一条SQL语句都会先将这条SQL语句发送给数据库编译,数据库再执行。

Statement stmt = conn.createStatement();stmt.executeUpdate("INSERT INTO users VALUES (1, '张三', '123456');");stmt.executeUpdate("INSERT INTO users VALUES (2, '李四', '666666');");

上面2条SQL语句我们可以看到大部分内容是相同的,只是数据略有不一样。数据库每次执行都编译一次。如果有1万条类似的SQL语句,数据库需要编译1万次,执行1万次,显然效率就低了。

2、PreparedStatement执行原理

preparestatement()会先将SQL语句发送给数据库预编译。之后Preparedstatement会引用着预编译后的结果。可以多次传入不同的参数给Preparedstatement对象并执行。相当于调用方法多次传入不同的参数。

String sql = "INSERT INTO users VALUES (?, ?, ?);";//会先将SQL语句发送给数据库预编译。Preparedstatement会引用着预编译后的结果。PreparedStatement pstmt = conn.prepareStatement(sql);// 设置参数 pstmt.setString(1, 1); pstmt.setInt(2, "张三");pstmt.setString(3, "123456");pstmt.executeUpdate();// 再次设置参数 pstmt.setString(1, 2); pstmt.setInt(2, "李四"); pstmt.setString(3, "66666"); pstmt.executeUpdate();

上面预编译好一条SQL,2次传入了不同的参数并执行。如果有1万条类似的插入数据的语句。数据库只需要预编译一次,传入1万次不同的参数并执行。减少了SQL语句的编译次数,提高了执行效率。

原理示意图

PreparedStatement好处

1、有预编译功能: preparestatement()会先将SQL语句发送给数据库预编译。Preparedstatement会引用着预编译后的结果。可以多次传入不同的参数给Preparedstatement对象并执行。执行时不需要再编译了。2、有缓冲功能:多次执行同一条SQL语句不需要多次编译。

3、安全性更高,没有SQL注入的隐患。

PreparedStatement和Statement区别-[面试题]

相同点:都是用来发送sql语句到数据库执行增删改查操作

不同点

1、PreparedStatement有预编译功能,Statement没有预编译功能。

2、PreparedStatement有缓存(缓存SQL语句编译的结果)功能,Statement没有缓存功能。

3、PreparedStatement没有SQL注入问题,Statement有SQL注入问题

4、PreparedStatement更安全,效率更高,可读性更好

3、PreparedStatement接口的基本使用

PreparedStatement接口继承Statement接口,PreparedStatement对象的作用是可以将SQL语法发送给数据库执行并获得结果

获取PreparedStatement对象

在java.sql.Connection有获取Preparedsatement对象的方法,即通过连接对象的方法获得PreparedStatement对象

PreparedStatement prepareStatement(String sql)//会先将SQL语句发送给数据库预编译。PreparedStatement对象会引用着预编译后的结果。

PreparedStatement对象方法

在java.sql.Preparedstatement中有设置SQL语句参数,和执行参数化的SQL语句的方法

//将指定参数设置为给定Java double值。void setDouble(int parameterIndex, double x)//将指定参数设置为给定Java float值。void setFloat(int parameterIndex, float x)//将指定参数设置为给定Java int值。void setInt(int parameterIndex, int x)//将指定参数设置为给定Java long值。void setLong(int parameterIndex, long x)//使用给定对象设置指定参数的值。void setObject(int parameterIndex, Object x)//将指定参数设置为给定Java String值。void setString(int parameterIndex, String x)//在此Preparedstatement对象中执行SQL查询,并返回该查询生成的ResultSet对象。ResultSet executeQuery()//在此Preparedstatement对象中执行SQL语句,该语句必须是一个SQL数据操作语言(Data Manipulation Language, DML)语句,比如INSERT、 UPDATE或DELETE语句;或者是无返回内容的SQL语句,比如DDL语句。int executeUpdate()

PreparedSatement使用步骤

1、编写SQL语句,未知内容使用?占位

SELECT * FROM user WHERE name=? AND password=?;

2、获得PreparedStatement对象

3、设置实际参数

4、执行参数化SQL语句

5、关闭资源

PreparedSatement使用示例

public class Demo08 {public static void main(String[] args) throws Exception {// 获取连接Connection conn = JDBCUtils.getConnection();// 编写SQL语句句,未知内容使用?占位String sql = "SELECT * FROM user WHERE name=? AND password=?;";// prepareStatement()会先将SQL语句句发送给数据库预编译。PreparedStatement pstmt = conn.prepareStatement(sql);// 指定?的值// parameterIndex: 第几个?,从1开始算// x: 具体的值pstmt.setString(1, "admin");pstmt.setString(2, "123"); // 正确的密码// pstmt.setString(2, "6666"); // 错误的密码ResultSet rs = pstmt.executeQuery();if (rs.next()) {String name = rs.getString("name");System.out.println("name:" + name);} else {System.out.println("没有找到数据...");}JDBCUtils.close(conn, pstmt, rs);}}

示例效果

输入正确的账号密码:

输入错误的密码

4、PreparedStatement实现增删改操作

package com.itheima._09预编译对象;import com.itheima._07JDBC工具类.JDBCUtils;import org.junit.Test;import java.sql.Connection;import java.sql.PreparedStatement;/**目标:使用PreparedStatement实现增删改功能*/public class JDBCDemo01 {// 添加数据: 向学生表添加3条记录@Testpublic void insertStudent() throws Exception {// 1. 获得连接对象Connection conn = JDBCUtils.getConnection();// 2. 准备SQL语句String sql = "insert into student values(null,?,?,?);";// 3. 获得预编译对象PreparedStatement ps = conn.prepareStatement(sql);// 4. 给占位符赋值ps.setString(1, "jack");ps.setString(2, "男");ps.setString(3, "-05-26");// 5. 执行SQL语句并获得结果int row = ps.executeUpdate();System.out.println(row);// 给占位符赋值ps.setString(1, "rose");ps.setString(2, "女");ps.setString(3, "-05-26");// 5. 执行SQL语句并获得结果row = ps.executeUpdate();System.out.println(row);// 给占位符赋值ps.setString(1, "lily");ps.setString(2, "男");ps.setString(3, "-06-16");// 5. 执行SQL语句并获得结果row = ps.executeUpdate();System.out.println(row);// 6. 关闭资源JDBCUtils.close(conn, ps);}// 修改数据: 将 id 为 3 的用户,姓名更新为 "嫦娥 " 性别换成女,@Testpublic void updateStudent() throws Exception {// 1. 获得连接对象Connection conn = JDBCUtils.getConnection();// 2. 准备SQL语句String sql = "update student set name = ?, gender = ? where id = ?;";// 3. 获得预编译对象PreparedStatement ps = conn.prepareStatement(sql);// 4. 给占位符赋值ps.setString(1, "嫦娥");ps.setString(2, "女");ps.setInt(3, 3);// 5. 执行SQL语句int row = ps.executeUpdate();System.out.println(row);// 6. 关闭资源JDBCUtils.close(conn, ps);}// 删除数据: 删除id为3的学生@Testpublic void deleteStudent() throws Exception {// 1. 获得连接对象Connection conn = JDBCUtils.getConnection();// 2. 准备SQL语句String sql = "delete from student where id = ?;";// 3. 获得预编译对象PreparedStatement ps = conn.prepareStatement(sql);// 4. 给占位符赋值ps.setInt(1, 3);// 5. 执行SQL语句int row = ps.executeUpdate();System.out.println(row);// 6. 关闭资源JDBCUtils.close(conn, ps);}}

小结:

PreparedStatement实现增删改的步骤

1、获得连接对象

2、准备SQL语句

3、获得预编译对象

4、给占位符赋值

5、调用预编译对象的executeUpdate方法执行SQL

6、关闭资源

5、PreparedStatement实现查询操作

需求:查询id小于4的学生信息,并保存将每一个记录封装成一个学生对象存储到List集合中

创建学生类

// 学生类package com.itheima._09预编译对象;import java.sql.Date;public class Student {private int id;private String name;private String gender;private Date birthday;public Student() {}public Student(int id, String name, String gender, Date birthday) {this.id = id;this.name = name;this.gender = gender;this.birthday = birthday;}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 String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", gender='" + gender + '\'' +", birthday=" + birthday +'}';}}

使用PreparedStatement对数据库进行查询

package com.itheima._09预编译对象;import com.itheima._07JDBC工具类.JDBCUtils;import org.junit.Test;import java.sql.Connection;import java.sql.Date;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;/**目标:使用PreparedStatement实现查询功能需求:查询所有学生,将每一个记录封装成一个学生对象存储到List集合中*/public class JDBCDemo02 {public static void main(String[] args) throws Exception{// 1. 获得连接对象Connection conn = JDBCUtils.getConnection();// 2. 获得预编译对象PreparedStatement ps = conn.prepareStatement("select * from student");// 3. 执行SQL语句获得结果集对象ResultSet rs = ps.executeQuery();// 4. 创建集合存储学生对象List<Student> list = new ArrayList<>();// 5. 遍历结果集对象while (rs.next()){// 5.1 获得每一列的值给对应成员变量赋值int id = rs.getInt("id");String name = rs.getString("name");String gender = rs.getString("gender");Date birthday = rs.getDate("birthday");// 5.2 每遍历到一条记录就创建学生对象Student stu = new Student(id,name,gender,birthday);// 5.3 将学生对象添加到集合中list.add(stu);}// 6. 遍历集合输出学生信息for (Student student : list) {System.out.println(student);}// 7. 关闭资源JDBCUtils.close(conn, ps,rs);}}

小结

PreparedStatement实现查询的步骤

1、获得连接对象

2、准备SQL语句

3、获得预编译对象

4、给占位符赋值

5、调用预编译对象的executeQuery方法执行SQL

6、关闭资源

八、使用PreparedStatement改造登录案例(解决SQL注入问题)

public class Demo11 {public static void main(String[] args) throws Exception {// 让用户输入账号和密码Scanner sc = new Scanner(System.in);System.out.println("请输入账号: ");String name = sc.nextLine();System.out.println("请输入密码: ");String password = sc.nextLine();// 获取连接Connection conn = JDBCUtils.getConnection();// 编写SQL语句,账号和密码使用?占位String sql = "SELECT * FROM user WHERE name=? AND password=?;";// 获取到PreparedStatement对象PreparedStatement pstmt = conn.prepareStatement(sql);// 设置参数pstmt.setString(1, name);pstmt.setString(2, password);// pstmt.setString(2, "a' or '1'='1");// 如果查询到数据,说明登录成功,如果查询不到数据,说明登录失败ResultSet rs = pstmt.executeQuery();if (rs.next()) {// 能进来查询到了数据.String name2 = rs.getString("name");System.out.println("欢迎您," + name2);} else {// 查询不到数据,说明登录失败System.out.println("账号或密码错误...");}JDBCUtils.close(conn, pstmt, rs);}}

案例效果

输入 “a’ or ‘1’='1” 作为密码

如果觉得《Java_16_JDBC连接池:JDBC(连接数据库技术)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。