- 一、引言
- 1.1如何操作数据库
- 1.2实际开发中,会采用客户端操作数据库吗?
- 二、JDBC
- 1.什么是JDBC?
- 2.2JDBC核心思想
- 2.3MySQL 数据库驱动
- 2.4JDBC核心API
- 三、JDBC 开发步骤【`重点`】
- 3.1 环境搭建
- 3.2 创建表
- 3.3编写测试类
- 四、 常见错误
- 五、 工具类
- 5.1在src目录下创建jdbc.properties
- 5.2创建工具类
- 六、SQL注入问题
- 6.1 什么是 SQL 注入
- 6.2 如何避免 SQL 注入
- 七、PreparedStatement【`重点`】
- 7.1 PreparedStatement的应用
- 7.2 参数标记
- 7.3 动态参数绑定
- 7.4 PreparedStatement vs Statment
一、引言 1.1如何操作数据库
使用客户端工具访问数据库,需要手工建立连接,输入用户名和密码登录,编写 SQL 语句,点击执行,查看操作结果(结果集或受影响行数)。
1.2实际开发中,会采用客户端操作数据库吗?二、JDBC 1.什么是JDBC?在实际开发中,当用户的数据发生改变时,不可能通过客户端操作执行 SQL 语句,因为操作量过大,无法保证效率和正确性。
2.2JDBC核心思想JDBC(Java Database Connectivity) Java连接数据库的规范(标准),可以使用Java语言连接数据库完成CRUD操作。
2.3MySQL 数据库驱动Java中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。由数据库厂商提供驱动实现类(Driver 数据库驱动)
- mysql-connector-java-5.1.X 适用于 5.X 版本
- mysql-connector-java-8.0.X 适用于 8.X版本
JDBC是由多个接口和类进行功能实现
| 类型 | 权限定名 | 简介 |
|---|---|---|
| interface | java.sql.Driver | 每个驱动程序类必须实现的接口 |
| class | java.sql.DriverManager | 管理多个数据库驱动类,提供了获取数据库连接的方法 |
| interface | java.sql.Connection | 代表一个数据库连接(当connection不是null时,表示已连接数据库) |
| interface | java.sql.Statement | 发送静态SQL语句访问数据库 |
| interface | java.sql.PreparedStatement | 发送预编译SQL语句访问数据库 |
| interface | java.sql.ResultSet | 保存SQL查询语句的结果数据(结果集) |
| class | java.sql.SQLException | 处理数据库应用程序时所发生的异常 |
java.sql.* 和 javax.sql.* |- Driver接口: 表示java驱动程序接口。所有的具体的数据库厂商要来实现此接口。 |- connect(url, properties): 连接数据库的方法。 url: 连接数据库的URL URL语法: jdbc协议:数据库子协议://主机:端口/数据库 user: 数据库的用户名 password: 数据库用户密码 |- DriverManager类: 驱动管理器类,用于管理所有注册的驱动程序 |-registerDriver(driver) : 注册驱动类对象 |-Connection getConnection(url,user,password); 获取连接对象 |- Connection接口: 表示java程序和数据库的连接对象。 |- Statement createStatement() : 创建Statement对象 |- PreparedStatement prepareStatement(String sql) 创建PreparedStatement对象 |- CallableStatement prepareCall(String sql) 创建CallableStatement对象 |- Statement接口: 用于执行静态的sql语句 |- int executeUpdate(String sql) : 执行静态的更新sql语句(DDL,DML) |- ResultSet executeQuery(String sql) :执行的静态的查询sql语句(DQL) |-PreparedStatement接口:用于执行预编译sql语句 |- int executeUpdate() : 执行预编译的更新sql语句(DDL,DML) |-ResultSet executeQuery() : 执行预编译的查询sql语句(DQL) |-CallableStatement接口:用于执行存储过程的sql语句(call xxx) |-ResultSet executeQuery() : 调用存储过程的方法 |- ResultSet接口:用于封装查询出来的数据 |- boolean next() : 将光标移动到下一行 |-getXX() : 获取列的值三、JDBC 开发步骤【重点】
3.1 环境搭建
3.2 创建表
- 创建JavaEE项目,在web目录下新建 lib 文件夹,用于存放 jar 文件。
- 将 mysql 驱动mysql-connector-java-5.1.X复制到项目的 lib 文件夹中。
- 选中 lib 文件夹右键 Add as Libraay,点击 OK。
create table t_user(
id int primary key auto_increment,
name varchar(50),
password varchar(50)
)default charset = utf8;
INSERT INTO t_user(NAME,PASSWORD) VALUES("jack","123");
INSERT INTO t_user(NAME,PASSWORD) VALUES("tom","456");
INSERT INTO t_user(NAME,PASSWORD) VALUES("rose","789");
3.3编写测试类
package com.qf.jdbc;
import com.mysql.jdbc.Driver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class Demo1 {
private static String url = "jdbc:mysql://localhost:3306/db_name";
private static String user = "root";
private static String password = "root";
private static String driver = "com.mysql.jdbc.Driver";
//第一种方式:通过Driver实现增删改
public static void test1()throws Exception{
//向驱动管理器中注册驱动
Driver driver = new Driver();
//创建Properties对象
Properties properties = new Properties();
properties.setProperty("user",user);
properties.setProperty("password",password);
//获取连接
Connection connection = driver.connect(url, properties);
//获取Statement对象,用于发送sql语句
Statement statement = connection.createStatement();
//准备sql
String sql = "INSERT INTO t_user(NAME,PASSWORD) VALUES('admin','123');";
//执行
int i = statement.executeUpdate(sql);
System.out.println(i+"条数据受到了影响");
//关闭
connection.close();
statement.close();
}
//第二种方式:通过DriverManager实现增删改
public static void test2()throws Exception{
//多个驱动
//Driver driver1 = new Driver();
//Driver driver2 = new Driver();
//可以通过驱动管理器管理
//DriverManager.registerDriver(driver1);
//DriverManager.registerDriver(driver2);
//向驱动管理器中注册驱动
//Class.forName("org.gjt.mm.mysql.Driver");
Class.forName(driver);
//获取连接
Connection connection = DriverManager.getConnection(url, user, password);
//获取Statement对象,用于发送sql语句
Statement statement = connection.createStatement();
//准备sql
String sql = "UPDATE t_user SET PASSWORD = '123456' WHERe id = 4";
//执行
int i = statement.executeUpdate(sql);
System.out.println(i+"条数据受到了影响");
//关闭
connection.close();
statement.close();
}
//查询
public static void test3()throws Exception{
//注册驱动
Class.forName(driver);
//获取连接
Connection connection = DriverManager.getConnection(url, user, password);
//获取执行静态sql语句的Statement对象
Statement statement = connection.createStatement();
//准备sql
String sql = "SELECT id,NAME,PASSWORD FROM t_user";
//查询
ResultSet resultSet = statement.executeQuery(sql);
//通过结果集对象遍历数据
//resultSet.next();//光标向下移一行
//通过列名来获取
// int id = resultSet.getInt("id");
// String name = resultSet.getString("name");
// String password = resultSet.getString("password");
//通过下标来获取
// int id = resultSet.getInt(1);
// String name = resultSet.getString(2);
// String password = resultSet.getString(3);
//
// System.out.println(id+"--"+name+"--"+password);
//全部获取
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String password = resultSet.getString("password");
System.out.println(id+"--"+name+"--"+password);
}
//关闭
connection.close();
statement.close();
resultSet.close();
}
public static void main(String[] args) throws Exception{
//test1();
//test2();
test3();
}
}
四、 常见错误
五、 工具类
- java.lang.ClassNotFoundException:找不到类(类名书写错误、没有导入jar包)
- java.sql.SQLException:与sql语句相关的错误 (约束错误、表名列名书写错误) 建议:在客户端工具中测试SQL语句之后再粘贴在代码中
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 原因:列值Sting类型没有加单引号
- Duplicate entry ‘1’ for key ‘PRIMARY’ 原因,主键值已存在或混乱,更改主键值或清空表
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column ‘password’ in
- 原因:可能输入的值的类型不对,确定是否插入的元素时对应的值的类型正确
5.1在src目录下创建jdbc.properties
jdbc.username = root jdbc.password = root jdbc.url = jdbc:mysql://localhost:3306/java2107 jdbc.driver = com.mysql.jdbc.Driver5.2创建工具类
package com.qf.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtil {
private static String username = null;
private static String password = null;
private static String url = null;
private static String driver = null;
static {
//读取jdbc.properties中的数据,jdbc.properties创建在src目录下
InputStream resourceAsStream = JdbcUtil.class.getResourceAsStream("/jdbc.properties");
//创建Properties对象
Properties properties = new Properties();
try {
//加载
properties.load(resourceAsStream);
//赋值
username = properties.getProperty("jdbc.username");
password = properties.getProperty("jdbc.password");
url = properties.getProperty("jdbc.url");
driver = properties.getProperty("jdbc.driver");
//注册驱动
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接的方法
public static Connection getConnection(){
try {
Connection connection = DriverManager.getConnection(url, username, password);
return connection;
} catch (SQLException e) {
e.printStackTrace();
}
//return null;
throw new RuntimeException("无法连接到数据库");
}
//关闭
public static void close(Connection connection, Statement statement){
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//关闭
public static void close(Connection connection, Statement statement, ResultSet resultSet){
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
六、SQL注入问题
6.1 什么是 SQL 注入
6.2 如何避免 SQL 注入用户输入的数据中有 SQL 关键字或语法并且参与了 SQL 语句的编译,导致 SQL 语句编译后的条件含义为 true,一直得到正确的结果。这种现象称为 SQL 注入。
七、PreparedStatement【重点】由于编写的 SQL 语句是在用户输入数据,整合后再进行编译。所以为了避免 SQL 注入的问题,我们要使 SQL 语句在用户输入数据前就已进行编译成完整的 SQL 语句,再进行填充数据。
7.1 PreparedStatement的应用PreparedStatement 继承了 Statement 接口,执行 SQL 语句的方法无异。
7.2 参数标记好处:
预编译SQL 语句,效率高。
安全,避免SQL注入 。
可以动态的填充数据,执行多个同构的 SQL 语句。
//1.预编译 SQL 语句
PreparedStatement pstmt = conn.prepareStatement("select * from t_user where name=? and password=?");
- 注意:JDBC中的所有参数都由 ?符号占位,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。
pstmt.setXxx(下标,值) 参数下标从 1 开始,为指定参数下标绑定值
//1.预编译 SQL 语句
PreparedStatement pstmt = conn.prepareStatement("select * from t_user where name=? and password=?");
//2.为参数下标赋值
pstmt.setString(1,username);
pstmt.setString(2,password);
7.4 PreparedStatement vs Statment
1)语法不同:PreparedStatement可以使用预编译的sql,而Statment只能使用静态的sql
2)效率不同: PreparedStatement可以使用sql缓存区,效率比Statment高
3)安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。推荐使用PreparedStatement



