一、JDBC概述
基本介绍
1、JDBC为访问不同的数据库提供了统一的接口,为使用者屏蔽了细节问题
2、Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作
3、JDBC原理图
JDBC带来的好处
JDBC是Java提供一套用于数据库操作的接口API,Java程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口提供不同实现
JDBC API
JDBC API是一系列接口,它统一和规范了应用程序与数据库的连接、 执行SQL语句,并得到返回结果等各类操作,相关类和接口在 java.sql 与 javax.sql 包中
二、JDBC快速入门
JDBC程序编写步骤
1、注册驱动 - 加载 Driver 类
2、获取连接 - 得到 Connection
3、执行增删改查 - 发送SQL给 mysql 执行
4、释放资源 - 关闭相关连接
import com.mysql.jdbc.Driver;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* 第一个JDBC程序,完成简单的操作
*/
public class Jdbc01 {
public static void main(String[] args) throws SQLException {
//前置工作:在项目下创建一个文件, 比如libs
//将mysql.jar文件拷贝到文件夹,点击add to project .. 加入到项目中
//1. 注册驱动
Driver driver = new Driver();//创建driver对象
//2. 得到连接
//解读:jdbc:mysql// 规定好的表示协议,通过jdbc的方式连接mysql
// localhost 主机,也可以是ip地址
// 3306 表示mysql监听的端口
// db01 连接到mysql dbms 的哪个数据库
// mysql的连接本质就是socket连接
String url = "jdbc:mysql://localhost:3306/db01?characterEncoding=utf8&useSSL=false";
//将用户名和密码放入到 Properties 对象
//user 和 password key是规定好的,后面的值根据情况写
Properties properties = new Properties();
properties.setProperty("user", "root"); //用户
properties.setProperty("password", "md"); //密码
Connection connect = driver.connect(url, properties);
//3. 执行sql
//String sql = "insert into actor values(null, '张三', '男', '1900-11-11', '123')";
//String sql = "update actor set `name`='老六' where id = 5";
String sql = "delete from actor where id = 5";
//statement 用于执行静态sql语句并返回其生成的结果的对象
Statement statement = connect.createStatement();
//如果是dml语句,返回的就是受影响的行数
int rows = statement.executeUpdate(sql);
System.out.println(rows > 0 ? "成功" : "失败");
//4. 关闭连接资源
statement.close();
connect.close();
}
}
三、获取数据库连接5种方式
方式1
方式2
方式3
方式4
方式5
package com.javase.jdbc;
import com.mysql.jdbc.Driver;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* 分析java连接mysql的五种方式
*/
public class JdbcConn {
public static void main(String[] args) throws Exception {
connect01();
connect02();
connect03();
connect04();
connect05();
}
//方式1
public static void connect01() throws SQLException {
Driver driver = new Driver();//创建driver对象
String url = "jdbc:mysql://localhost:3306/db01?characterEncoding=utf8&useSSL=false";
//将用户名和密码放入到 Properties 对象
//user 和 password key是规定好的,后面的值根据情况写
Properties properties = new Properties();
properties.setProperty("user", "root"); //用户
properties.setProperty("password", "md"); //密码
Connection connect = driver.connect(url, properties);
System.out.println(connect);
}
//方式2
public static void connect02() throws Exception {
//使用反射加载Driver,动态加载,更加的灵活,减少了依赖性
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) aClass.newInstance();
String url = "jdbc:mysql://localhost:3306/db01?characterEncoding=utf8&useSSL=false";
//将用户名和密码放入到 Properties 对象
//user 和 password key是规定好的,后面的值根据情况写
Properties properties = new Properties();
properties.setProperty("user", "root"); //用户
properties.setProperty("password", "mdzz"); //密码
Connection connect = driver.connect(url, properties);
System.out.println(connect);
}
//方式3 使用DriverManger 替代 driver 进行统一管理
public static void connect03() throws Exception {
//使用反射加载Driver
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) aClass.newInstance();
//创建url,user,password
String url = "jdbc:mysql://localhost:3306/db01?characterEncoding=utf8&useSSL=false";
String user = "root";
String password = "mdzz";
DriverManager.registerDriver(driver);//注册driver驱动
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
}
//方式4 使用Class.forNAME 自动完成注册驱动,简化代码
//使用的最多的,推荐使用
public static void connect04() throws Exception {
//使用反射加载Driver
//在加载 Driver 类时,完成注册
/*源码:1. 静态代码块,在类加载时会执行一次
2. DriverManager.registerDriver(new Driver());
3. 因此底层注册driver已经完成
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
*/
Class.forName("com.mysql.jdbc.Driver");
//创建url,user,password
String url = "jdbc:mysql://localhost:3306/db01?characterEncoding=utf8&useSSL=false";
String user = "root";
String password = "mdzz";
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
}
//方式5,在方式4的基础上改进,增加配置文件,让连接mysql更加灵活
public static void connect05() throws Exception {
//通过Properties对象获取配置文件信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
}
}
四、ResultSet(结果集)
1、表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
2、ResultSet对象保持一个光标指向其当前的数据行。最初,光标位于第一行之前
3、next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false,因此可以在while循环中使用循环来遍历结果集
package com.javase.jdbc.resultset_;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
/**
* 演示select语句返回ResultSet,并取出结果
*/
public class ResultSet01 {
public static void main(String[] args) throws Exception {
//通过Properties对象获取配置文件信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);
//2. 得到和mysql的连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到statement
Statement statement = connection.createStatement();
//4. 组织sql
String sql = "select id, name, sex, borndate from actor";
//执行给定的sql语句,该语句返回单个ResultSet对象
ResultSet resultSet = statement.executeQuery(sql);
//5. 使用while循环取出
while(resultSet.next()) { //让光标向后移动,如果没有更多的记录返回false
int id = resultSet.getInt(1);//获取该行第一列
String name = resultSet.getString(2);//获取该行第二列
String sex = resultSet.getString(3);//获取该行第三列
Date borndate = resultSet.getDate(4);
System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate);
}
//6. 关闭连接
resultSet.close();
statement.close();
connection.close();
}
}
五、Statement
基本介绍
1、Statement对象用于执行静态SQL语句并返回其生成的结果的对象
2、在连接建立后,需要对数据库进行访问,执行命名或是SQL语句,可以通过以下三种方法
Statement(存在SQL注入)
PreparedStatement(预处理)
CallableStatement(存储过程)
3、Statement对象执行SQL语句,存在SQL注入风险
4、SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库
5、要防范SQL注入,只要用PreparedStatement(从Statement扩展而来的)取代Statement就可以了
SQL注入问题
-- 演示sql注入
-- 创建一张表
CREATE TABLE admin ( -- 管理员表
`name` VARCHAR(32) NOT NULL UNIQUE,
pwd VARCHAR(32) NOT NULL DEFAULT'') CHARACTER SET utf8;
-- 添加数据
INSERT INTO admin VALUES('tom', '123');
-- 查找某个管理是否存在
SELECT *
FROM admin
WHERE `name` = 'tom' AND pwd = '123';
-- SQL注入
-- 输入用户名为 1'or
-- 输入密码为 or'1'='1
SELECT *
FROM admin
WHERE `name` = '1'OR' AND pwd = 'OR'1'='1';
package com.javase.jdbc;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
/**
* 演示statement的注入问题
*/
public class statement_ {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//让用户输入管理员名和密码
System.out.print("请输入管理员的名字:");
String admin_name = scanner.nextLine();
System.out.print("请输入管理员的密码:");
String admin_pwd = scanner.nextLine();
//通过Properties对象获取配置文件信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);
//2. 得到和mysql的连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到statement
Statement statement = connection.createStatement();
//4. 组织sql
String sql = "select name, pwd from admin where name = '"+ admin_name + "' and pwd = '" + admin_pwd + "'";
//执行给定的sql语句,该语句返回单个ResultSet对象
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()) { //如果查询到一条记录,则说明该管理员存在
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
//6. 关闭连接
resultSet.close();
statement.close();
connection.close();
}
}
六、PreparedStatement
基本介绍
1、PreparedStatement执行的SQL语句中的参数用问号(?)来表示,调用PreparedStatement对象setXxx()方法来设置这些参数。setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值
2、调用executeQuery(),返回ResultSet对象
3、调用executeQuery():执行更新,包括增、删、修改
预处理的好处
1、不再使用加号(+)拼接sql语句,减少语法错误
2、有效的解决了sql注入问题
3、大大减少了编译次数,效率提高
SELECT演示
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
/**
* 演示PreparedStatement的使用
*/
public class PreparedStatement01 {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//让用户输入管理员名和密码
System.out.print("请输入管理员的名字:");
String admin_name = scanner.nextLine();
System.out.print("请输入管理员的密码:");
String admin_pwd = scanner.nextLine();
//通过Properties对象获取配置文件信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);
//2. 得到和mysql的连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到PreparedStatement
//组织sql,SQL语句的 ? 就相当于占位符
String sql = "select name, pwd from admin where name = ? and pwd = ?";
//preparedStatement 对象是实现了 PreparedStatement 接口的实现类的对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//给 ? 复制
preparedStatement.setString(1, admin_name);
preparedStatement.setString(2, admin_pwd);
//执行 select 语句使用 executeQuery() 方法
//执行 dml 语句 executeUpdate() 方法
//这里执行查询的时候,不需要再写sql
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) { //如果查询到一条记录,则说明该管理员存在
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
//6. 关闭连接
resultSet.close();
preparedStatement.close();
connection.close();
}
}
DML演示
package com.javase.jdbc.preparedstatement_;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
/**
* DML语句演示
*/
public class PreparedStatement02 {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//让用户输入管理员名和密码
System.out.print("请输入要删除的管理员的名字:");
String admin_name = scanner.nextLine();
//System.out.print("请输入管理员的密码:");
//String admin_pwd = scanner.nextLine();
//通过Properties对象获取配置文件信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);
//2. 得到和mysql的连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到PreparedStatement
//组织sql,SQL语句的 ? 就相当于占位符
//添加数据
//String sql = "insert into admin values(?, ?)";
//修改数据
//String sql = "update admin set pwd=? where name = ?";
//删除数据
String sql = "delete from admin where name = ?";
//preparedStatement 对象是实现了 PreparedStatement 接口的实现类的对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//给 ? 复制
//preparedStatement.setString(2, admin_name);
preparedStatement.setString(1, admin_name);
//执行 select 语句使用 executeQuery() 方法
//执行 dml 语句 executeUpdate() 方法
//这里执行查询的时候,不需要再写sql
int rows = preparedStatement.executeUpdate();
if (rows > 0) { //如果查询到一条记录,则说明该管理员存在
System.out.println("执行成功");
}else {
System.out.println("执行失败");
}
//6. 关闭连接
preparedStatement.close();
connection.close();
}
}
七、JDBC的相关API小结
八、封装JDBCUtils
在JDBC操作中,获取连接和释放资源是经常使用到的,可以将其封装成JDBC连接的工具JDBCUtils
package com.javase.jdbc.utils;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
/**
* 这是一个工具类,完成mysql的连接和关闭资源
*/
public class JDBCUtils {
//定义相关的属性(4个),因为只需要一份,我们做出static
private static String user; //用户名
private static String password; //密码
private static String url; //url
private static String driver; //驱动名
//在 static代码块初始化
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//获取相关属性
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
} catch (IOException e) {
//在实际开发中,我们可以这样处理
//1. 将编译异常转成运行异常
//2. 这时调用者,可以选择捕获该异常,也可以选择默认处理异常,比较方便
throw new RuntimeException(e);
}
}
//编译方法连接数据库,返回Connection
public static Connection getConnection() {
try {
return DriverManager.getConnection(url, user, password);
} catch (SQLException throwables) {
throw new RuntimeException(throwables);
}
}
//关闭相关资源
//1. ResultSet 结果集
//2. Statement 或 PreparedStatement
//3. Connection
//4. 如果需要关闭资源就传入对象,否则传入null
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
//判断是否为null
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException throwables) {
throw new RuntimeException(throwables);
}
}
}
案例演示
package com.javase.jdbc.utils;
import java.sql.*;
/**
* 演示如何使用JDBCUtils工具类
*/
public class JDBCUtils_Use {
public static void main(String[] args) {
testDML();
testSelect();
}
public static void testDML() {
//1. 得到连接
Connection connection = null;
//2. 组织sql语句
String sql = "update actor set name = ? where id = ?";
//3. 创建PreparedStatement对象
PreparedStatement preparedStatement = null;
try {
connection = JDBCUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
//给 ? 赋值
preparedStatement.setString(1, "李四");
preparedStatement.setInt(2, 7);
//执行
preparedStatement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(null, preparedStatement, connection);
}
}
public static void testSelect() {
//1. 得到连接
Connection connection = null;
//2. 组织sql语句
String sql = "select * from actor where id = ?";
ResultSet set = null;
//3. 创建PreparedStatement对象
PreparedStatement preparedStatement = null;
try {
connection = JDBCUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 6);
//执行,得到结果集
set = preparedStatement.executeQuery();
//遍历该结果集
while( set.next()) {
int id = set.getInt("id");
String name = set.getString("name");
String sex = set.getString("sex");
Date borndate = set.getDate("borndate");
String phone = set.getString("phone");
System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(set, preparedStatement, connection);
}
}
}