JDBC
文章目录
1. JDBC概述
1.1 什么是JDBC
使用Java这种语言去访问各种关系型数据库,如:MySQL,Oracle。Java DataBase Connectivity Java的数据库连接技术。
1. 2 好处
- 使用接口编程,不用考虑实现类,实现类由厂商实现。
- 代码不需要修改或者少量修改就能访问另一种数据库。
- 代码工作量少,学习一组接口就可以访问所有数据库。
2. JDBC使用
2.1 所用的包
会使用到的包 | 说明 |
---|---|
java.sql | 访问数据库的核心包,今天要学习的所有的接口都在这个包中 |
javax.sql | 访问数据库的扩展名,使用数据库的高级特性。如:连接池 |
数据库的驱动 | 只需要导入即可,不需要对它进行任何的操作。 |
2.2 核心api
接口或类 | 作用 |
---|---|
DriverManager类 | 1) 加载和注册驱动2) 创建连接对象 |
**Connection接口 ** | 代表一个Java程序与数据库之间创建的一个连接对象 |
Statement接口 | 代表一条要发送给服务器的SQL语句 |
ResultSet接口 | 代表从服务器上返回的结果集 |
导包
2.3 使用步骤(以Mysql为例)
- 加载和注册驱动(可选)
Class.forName(数据库驱动实现类) 将驱动加载到内存
com.mysql.jdbc.Driver加载驱动的源代码
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static { //类加载的时候执行
try {
DriverManager.registerDriver(new Driver()); //DriveManager类注册了驱动
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!"); //注册失败,不能注册驱动
}
}
}
从JDK1.5以后这个注册驱动就可以省略了
- 由DriverManager创建一个连接对象Connection
Connection conn = DriverManager.createConnection();
- 由Connection对象创建一个执行的语句对象Statement
Statement conn.createStatement();
- 由Statement语句对象发送SQL语句给服务器,由服务器执行SQL语句。
//执行查询语句,返回结果集
ResultSet executeQuery(sql);
//执行DDL(数据库定义语言),返回布尔值
Boolean execute();
//执行增删改语句,返回影响的函数
int executeUpdate();
- 由服务器返回数据库的查询结果,封装成ResultSet结果集对象,返回给Java客户端。ResultSet方法如下
//移动到下一行,如果下一行为null则返回false:
Boolean next();
//XXX指的是数据类型
XXX rs.getXXX(int column); // 根据行号获取数据
XXX rs.getXXX(String name); // 根据名字获取数据
- 关闭资源
//关闭Result
Result的变量名.close();
//关闭Statement
Statement的变量名.close();
//关闭Connection
Connection的变量名.close();
案例:用JDBC操作数据库
package com.zmysna.test;
import com.zmysna.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class Test01 {
private final static String DRIVER_NAME= "com.mysql.jdbc.Driver";
private final static String URL = "jdbc:mysql://localhost:3306/day18";
private final static String USER = "root";
private final static String PASSWORD = "root";
public static void main(String[] args){
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try {
//注册驱动,JDK1.5之后可以省略
//Class.forName(DRIVER_NAME);
//连接数据库
connection = DriverManager.getConnection(URL, USER, PASSWORD);
statement = connection.createStatement();
//执行DDL语句
String ddl = "create table student (id int primary key auto_increment, name varchar(20) not null unique, gender char(1))";
statement.execute(ddl);
//执行DML语句(增删改)
String dml = "insert into student(name,gender) values('张三',‘男’)";
statement.executeUpdate(dml)
//执行DQL查询语句
String dql = "select * from student";
rs = statement.executeQuery(dql);
//遍历结果集
while(rs.next()){
String name = rs.getString("name");//获取名字
}
} catch (SQLException e) {
e.printStackTrace();
} finally {//关闭资源
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
3. JDBC工具类
为了减少写代码的工作量,创建一个工具类用于创建数据库连接和关闭资源。
- 方法:
Connection getConntection();
//获得一个数据库连接
void close(Connection conn,Statement st, Result rs)
//关闭资源
void close(Connection conn,Statement st)
//关闭资源
- 代码如下
package com.zmysna.utils;
import java.sql.*;
public class JDBCUtils {
private final static String DRIVER_NAME= "com.mysql.jdbc.Driver";
private final static String URL = "jdbc:mysql://localhost:3306/day18";
private final static String USER = "root";
private final static String PASSWORD = "awsed2zx";
static {
try {
Class.forName(DRIVER_NAME);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获得连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASSWORD);
}
/**
* 关闭Connection和Statement
* @param connection
* @param statement
*/
public static void close(Connection connection, Statement statement) {
close(connection, statement, null);
}
/**
* 关闭Connection、Statement以及ResultSet
* @param connection
* @param statement
* @param rs
*/
public static void close(Connection connection, Statement statement, ResultSet rs){
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
4. SQL注入问题以及解决办法
4.1 登录案例
package com.zmysna.test;
import com.zmysna.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
public class Test02 {
private static Connection connection = null;
private static Statement statement = null;
private static ResultSet rs = null;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
String pwd = scanner.nextLine();
try {
connection = JDBCUtils.getConnection();
statement = connection.createStatement();
prepareData(); //准备数据
login(name,pwd); //登录
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(connection, statement, rs);
}
scanner.close();
}
/**
* 用户登录功能(不能防止SQL注入)
* @param name
* @param pwd
* @throws SQLException
*/
private static void login(String name, String pwd) throws SQLException {
String sql = "SELECT * FROM user WHERE `name` = '" + name + "' AND password = '" + pwd + "'";
rs = statement.executeQuery(sql);
if (rs.next()) {
System.out.println("登录成功,"+name);
}else{
System.out.println("登录失败");
}
}
/**
* 准备数据
* @throws SQLException
*/
private static void prepareData() throws SQLException {
// statement.execute("create table user(id int auto_increment primary key, name varchar(50), password varchar(50))");
// System.out.println("成功创建用户表");
int i = statement.executeUpdate("insert into user values(1,'admin',123)");
System.out.println("成功插入" + i + "条记录");
}
}
由于字符串的拼接问题,输入a'or'1'='1
也能登录成功
4.2 PreparedStatement解决SQL注入
PreparedStatement是一个语句对象,它是Statement接口的子接口。功能比Statement语句对象功能更加强大。
a. PreparedStatement原理
b. 好处
-
有预编译的功能,在创建这个对象的时候就提供了SQL语句,预先编译好了。执行效率更高一些。
-
使用Statement有SQL注入的安全隐患,而使用子接口没有这个问题。安全性更高。
-
代码的可读性更好。
c. 主要方法
PreparedStatement中的方法 | 方法说明 |
---|---|
PreparedStatement prepareStatement(String sql) | 通过指定SQL语句创建预编译的语句对象,SQL语句中可能有占位符? |
int executeUpdate() | 执行DML语句,返回影响的行数 |
ResultSet executeQuery() | 执行查询语句,返回一个结果集 |
void set 数据类型(int 参数1,参数2) | 用真实值替换占位符? 参数1:占位符的索引,从1开始 参数2:用于替换占位符的真实值 |
练习
package com.zmysna.jdbc;
import org.junit.Test;
import java.sql.*;
/**
* 使用PreparedStatement
*/
public class Demo1Prepared {
@Test
public void testInsert() throws SQLException {
//得到连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql:///day19", "root", "root");
//编写SQL语句,未知内容使用占位符
String sql = "insert into student values(null,?,?,?)";
//获得PreparedStatement对象
PreparedStatement ps = connection.prepareStatement(sql);
//设置实际参数,替换占位符
ps.setString(1,"孙悟空");
ps.setBoolean(2,true);
ps.setDate(3, Date.valueOf("2000-11-11")); //将字符串转成日期类型
//执行参数化SQL语句
int i = ps.executeUpdate();
System.out.println(i);
//关闭资源
ps.close();
connection.close();
}
//将id为2的用户,姓名更新为"嫦娥",性别换成女
@Test
public void testUpdate() throws SQLException {
//得到连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql:///day19", "root", "root");
//编写SQL语句,未知内容使用占位符
String sql = "update student set name=?, gender=? where id=?";
//获得PreparedStatement对象
PreparedStatement ps = connection.prepareStatement(sql);
//设置实际参数,替换占位符
ps.setString(1,"嫦娥");
ps.setBoolean(2,false);
ps.setInt(3,2);
//执行参数化SQL语句
int i = ps.executeUpdate();
System.out.println(i);
//关闭资源
ps.close();
connection.close();
}
//将id为4的学员删除
@Test
public void testDelete() throws SQLException {
//得到连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql:///day19", "root", "root");
//编写SQL语句,未知内容使用占位符
String sql = "delete from student where id=?";
//获得PreparedStatement对象
PreparedStatement ps = connection.prepareStatement(sql);
//设置实际参数,替换占位符
ps.setInt(1,4);
//执行参数化SQL语句
int i = ps.executeUpdate();
System.out.println(i);
//关闭资源
ps.close();
connection.close();
}
}
d. 改写登录案例
package com.zmysna.jdbc;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
/**
* 改写登录程序
*/
public class Demo2Login {
public static void main(String[] args) throws SQLException {
//得到用户名和密码
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String name = scanner.nextLine();
System.out.println("请输入密码:");
String pwd = scanner.nextLine();
//创建连接对象
Connection conn = JdbcUtils.getConnection();
//创建预编译语句对象,用户名和密码使用占位符
PreparedStatement ps = conn.prepareStatement("select * from user where name=? and password=?");
//替换占位符
ps.setString(1,name);
ps.setString(2,pwd);
//执行查询操作
ResultSet rs = ps.executeQuery();
//如果结果集有记录表示登录成功
if (rs.next()) {
System.out.println("欢迎您,登录成功" + name);
}
else {
//否则登录失败
System.out.println("登录失败");
}
//关闭连接
JdbcUtils.close(conn,ps,rs);
}
}