1【第一章】JDBC概念/入门案例/API讲解【理解】
1 JDBC概念
2 入门案例
2.1 入门案例步骤
【前提】:导入mysql的驱动jar包
【第一步】:注册驱动,告诉程序使用哪种数据
【第二步】:获取连接,需要url、用户名、密码
【第三步】:获取执行SQL的对象,负责CRUD
【第四步】:执行查询操作,获取结果
【第五步】:处理结果
【第六步】:释放资源
2.2 代码实现
- 准备数据库数据
-- 创建db14数据库
CREATE DATABASE db14;
-- 使用db14数据库
USE db14;
-- 创建student表
CREATE TABLE student(
sid INT PRIMARY KEY AUTO_INCREMENT, -- 学生id
NAME VARCHAR(20), -- 学生姓名
age INT, -- 学生年龄
birthday DATE -- 学生生日
);
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23,'1999-09-23'),(NULL,'李四',24,'1998-08-10'),(NULL,'王五',25,'1996-06-06'),(NULL,'赵六',26,'1994-10-20');
- 代码实现
public class JdbcDemo1 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//【前提】:导入mysql的驱动jar包
//【第一步】:注册驱动,告诉程序使用哪种数据
Class.forName("com.mysql.jdbc.Driver");
//【第二步】:获取连接,需要url、用户名、密码
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db14", "root", "root");
//【第三步】:获取执行SQL的对象,负责CRUD
Statement statement = conn.createStatement();
//【第四步】:执行查询操作,获取结果
ResultSet rs = statement.executeQuery("select * from student");
//【第五步】:处理结果
while (rs.next()){ //如果返回true表示有下一行元素
//获取并打印
int sid = rs.getInt("sid");
String name = rs.getString("name");
int age = rs.getInt("age");
String birthday = rs.getString("birthday");
System.out.println(sid+","+name+","+age+","+birthday);
}
//【第六步】:释放资源
rs.close();
statement.close();
conn.close();
}
}
3 API讲解
3.1 DriverManager的作用
作用一:注册驱动
DriverManager.registerDriver(new Driver()),但是我们不使用,我们使用Class.forName(“com.mysql.jdbc.Driver”)。
作用二:获取连接
Connection conn = DriverManager.getConnection(“jdbc:mysql://localhost:3306/db14”, “root”, “root”);
参数1:连接的URL地址,如果是本机并且端口号是3306,那么localhost:3306可以省略不写,也就是**jdbc:mysql:///db14**。
参数2:用户名
参数3:密码
3.2 Connection的作用
作用一:创建执行SQL语句的执行者对象
Statement对象:Statement statement = conn.createStatement();
PreparedStatement预编译对象:PreparedStatement pstmt=conn.prepareStatement("")
作用二:事务管理
conn.setAutoCommit(false); //设置自动提交为false就表示开启事务
conn.commit(); //提交事务
conn.rollback();//回滚事务
3.3 Statement的作用
作用:执行SQL语句
执行DQL语句(查询):ResultSet executeQuery(SQL);
参数:传递要执行的查询语句
返回值:封装查询结果的结果集对象。
执行DML语句(增删改):int executeUpdate(SQL);
参数:要执行的增删改语句
返回值:影响的行数,可以通过影响的行数判断是否执行成功。
3.4 ResultSet的作用
作用一:判断是否有下一行数据:boolean next()
作用二:获取改行的数据: Xxx getXxx(“列名”);
Xxx表示不同的数据类型,例如:int getInt(“sid”); String getString(“name”)
【第二章】JDBC案例【理解】
1 案例流程,以查询所有为例
20200914110357495.png)
2 环境搭建
2.1 Student类
public class Student {
private Integer sid;
private String name;
private Integer age;
private String birthday;
//空参/有参构造、getter()/setter()方法、toString()方法自己生成
}
2.2 StudentDao接口
/*
Dao层接口
*/
public interface StudentDao {
//查询所有学生信息
public abstract ArrayList<Student> findAll();
//条件查询,根据id获取学生信息
public abstract Student findById(Integer id);
//新增学生信息
public abstract int insert(Student stu);
//修改学生信息
public abstract int update(Student stu);
//删除学生信息
public abstract int delete(Integer id);
}
2.3 StudentService接口
/*
Service层接口
*/
public interface StudentService {
//查询所有学生信息
public abstract ArrayList<Student> findAll();
//条件查询,根据id获取学生信息
public abstract Student findById(Integer id);
//新增学生信息
public abstract int insert(Student stu);
//修改学生信息
public abstract int update(Student stu);
//删除学生信息
public abstract int delete(Integer id);
}
需求一:查询所有学生信息
1 StudentDaoImpl代码实现
@Override
public ArrayList<Student> findAll() {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
ArrayList<Student> list= null;
try {
//1 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2 获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db14", "root", "root");
//3 创建执行SQL的对象
statement = connection.createStatement();
//4 执行SQL得到结果
rs = statement.executeQuery("select * from student");
list = new ArrayList<>();
//5 处理结果
while (rs.next()){
int sid = rs.getInt("sid");
String name = rs.getString("name");
int age = rs.getInt("age");
String birthday = rs.getString("birthday");
//封装成Student对象,保存到ArrayList集合中
list.add(new Student(sid,name,age,birthday));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//6 释放资源
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();
}
}
}
//7 返回结果
return list;
}
2 StudentServiceImpl代码实现
private StudentDao studentDao=new StudentDaoImpl();
@Override
public ArrayList<Student> findAll() {
return studentDao.findAll();
}
3 StudentController代码实现
@Test
public void testFindAll(){
ArrayList<Student> list = studentService.findAll();
//Lambda表达式语法:()->{}
list.forEach(student ->System.out.println(student));
}
需求二:根据id查询学生信息
1 StudentDaoImpl代码实现
@Override
public Student findById(Integer id) {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
Student student=null;
try {
//1 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2 获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db14", "root", "root");
//3 创建执行SQL的对象
statement = connection.createStatement();
//4 执行SQL得到结果
rs = statement.executeQuery("select * from student where sid="+id);
//5 处理结果
if (rs.next()){
int sid = rs.getInt("sid");
String name = rs.getString("name");
int age = rs.getInt("age");
String birthday = rs.getString("birthday");
//封装成Student对象
student=new Student(sid,name,age,birthday);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//6 释放资源
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();
}
}
}
return student;
}
2 StudentServiceImpl代码实现
@Override
public Student findById(Integer id) {
return studentDao.findById(id);
}
3 StudentController代码实现
@Test
public void testFindById(){
Student student = studentService.findById(3);
System.out.println(student);
}
需求三:添加学生信息
1 StudentDaoImpl代码实现
@Override
public int insert(Student stu) {
Connection connection = null;
Statement statement = null;
int count=0;
try {
//1 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2 获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db14", "root", "root");
//3 创建执行SQL的对象
statement = connection.createStatement();
//4 执行SQL得到结果
String sql="insert into student values(null,'" + stu.getName() + "'," + stu.getAge() + ",'" + stu.getBirthday() + "')";
count= statement.executeUpdate(sql);
//5 处理结果
} catch (Exception e) {
e.printStackTrace();
} finally {
//6 释放资源
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return count;
}
2 StudentServiceImpl代码实现
@Override
public int insert(Student stu) {
return studentDao.insert(stu);
}
3 StudentController代码实现
@Test
public void testInsert(){
Student stu=new Student(null,"tom",20,"2020-9-14");
int count = studentService.insert(stu);
//判断是否执行成功
System.out.println(count>0?"添加成功":"添加失败");
}
需求四:修改学生信息
1 StudentDaoImpl代码实现
@Override
public int update(Student stu) {
Connection connection = null;
Statement statement = null;
int count=0;
try {
//1 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2 获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db14", "root", "root");
//3 创建执行SQL的对象
statement = connection.createStatement();
//4 执行SQL得到结果
String sql="update student set name='"+stu.getName()+"',age="+stu.getAge()+",birthday='"+stu.getBirthday()+"' where sid="+stu.getSid();
count= statement.executeUpdate(sql);
//5 处理结果
} catch (Exception e) {
e.printStackTrace();
} finally {
//6 释放资源
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return count;
}
2 StudentServiceImpl代码实现
@Override
public int update(Student stu) {
return studentDao.update(stu);
}
3 StudentController代码实现
@Test
public void testUpdate(){
Student stu=new Student(5,"rose",21,"2019-9-14");
int count = studentService.update(stu);
//判断是否执行成功
System.out.println(count>0?"修改成功":"修改失败");
}
需求五:删除学生信息
1 StudentDaoImpl代码实现
@Override
public int delete(Integer id) {
Connection connection = null;
Statement statement = null;
int count=0;
try {
//1 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2 获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db14", "root", "root");
//3 创建执行SQL的对象
statement = connection.createStatement();
//4 执行SQL得到结果
String sql="delete from student where sid="+id;
count= statement.executeUpdate(sql);
//5 处理结果
} catch (Exception e) {
e.printStackTrace();
} finally {
//6 释放资源
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return count;
}
2 StudentServiceImpl代码实现
@Override
public int delete(Integer id) {
return studentDao.delete(id);
}
3 StudentController代码实现
@Test
public void testDelete(){
int count = studentService.delete(5);
//判断是否执行成功
System.out.println(count>0?"删除成功":"删除失败");
}
【第三章】JDBC工具类【重点】
1 将哪些操作抽取到工具类中【重要】
为什么要抽取工具类?
我们在执行CRUD的过程中,有太多的重复代码需要写,例如:注册驱动、获取连接、释放资源...
1 加载properties配置文件,获取连接数据库的相关参数,4个
2 注册驱动
加载一次,写到static静态代码块中
3 获取连接
4 释放资源
2 在src中书写jdbc.properties配置文件【重要】
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db14
username=root
password=root
注意:不要写到包中了
3 书写JDBCUtils工具类【重要】
public class JDBCUtils {
private static String url;
private static String username;
private static String password;
static {
//1 加载properties配置文件,获取连接数据库的相关参数,4个
//1.1 创建Properties对象
Properties properties=new Properties();
//1.2 调用load方法加载文件
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
properties.load(is);
//1.3 根据key获取value值
String driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//2 注册驱动
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
//3 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//4 释放资源
public static void close(Statement statement,Connection connection){
close(null,statement,connection);
}
public static void close(ResultSet rs, Statement statement,Connection connection){
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();
}
}
}
}
4 将页面我们的dao层代码整合到给定的web项目中
4.1 在db14数据库中添加user表
-- 创建用户表
CREATE TABLE USER(
uid VARCHAR(50) PRIMARY KEY, -- 用户id
ucode VARCHAR(50), -- 用户标识
loginname VARCHAR(100), -- 登录用户名
PASSWORD VARCHAR(100), -- 登录密码
username VARCHAR(100), -- 用户名
gender VARCHAR(10), -- 用户性别
birthday DATE, -- 出生日期
dutydate DATE -- 入职日期
);
-- 添加一条测试数据
INSERT INTO USER VALUES ('11111111', 'zhangsan001', 'zhangsan', '1234', '张三', '男', '2008-10-28', '2018-10-28');
4.2 修改config.properties属性文件
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db14
username=root
password=root
4.3 将自己的StudentDaoImpl替换给的dao
【第四章】JDBC的SQL注入漏洞【重点】
1 SQL注入漏洞的原因
使用Statement对象执行SQL时,如果SQL中拼接的变量保护SQL关键字,那么就会出现SQL注入漏洞。
2 SQL注入漏洞的解决办法
使用PreparedStatement对象代替Statement对象执行SQL,该对象可以预编译SQL语句,固定SQL的格式和关键字,用?占位符表示传递的数据,后期设置数据即可。
3 使用PreparedStatement对象的思路【重点】
【第一步】:使用Connection对象获取PreparedStatement对象预编译sql
【第二步】:如果SQL中有几个?占位符,那么就设置几个参数。
【第三步】:调用executeQuery()或者executeUpdate()方法执行SQL,但是不用再传递SQL。
例如:
//3 创建执行SQL的对象
String sql="insert into student values(null,?,?,?)";
pstmt = connection.prepareStatement(sql);
//有几个?就设置几个参数
pstmt.setString(1,stu.getName());
pstmt.setInt(2,stu.getAge());
pstmt.setString(3,stu.getBirthday());
//4 执行SQL得到结果
count= pstmt.executeUpdate();
【第五章】JDBC事务管理【理解】
1 事务概念
一组SQL操作要么同时成功要么同时失败。
2 JDBC事务操作的API
conn.setAutoCommit(false); //设置自动提交为false就表示开启事务
conn.commit(); //提交事务
conn.rollback();//回滚事务
3 修改之前的批量添加的代码
总结
1 jdbc相关api的作用【理解】
DriverManager:
1 注册驱动(不用)
2 获取连接:DriverManager.getConnection(url,username,password);
Connection:
1 获取执行SQL的对象(PreparedStatement)
2 事务管理
前提:一组SQL操作必须使用同一个Connection对象
setAutoCommit(false); //获取连接之后开启事务
commit();//提交事务
rollback();//回滚事务
PreparedStatement:
1 预编译SQL:connection.preparedStatement(SQL)
2 执行DQL语句:executeQuery();
3 执行DML语句:executeUpdate();
ResultSet:结果集对象
1 判断是否有下一个元素:boolean next();
2 根据列名获取值:Xxx getXxx("列名"); //Xxx表示数据类型
'2 JDBCUtils工具类【重点】
public class JDBCUtils{
//静态代码块中的代码很关键
static{
//1 加载jdbc.properties配置文件
Properties properties=new Properties()
InputStream is=JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(is);
//后面就是获取值
String driverClass=properties.getProperty("driverClass"); //容易将参数的引号掉了
...
//2 注册驱动
Class.forName(driverClass);
}
//3 对外提供获取连接的方法
public static Connection getConnection(){}
//4 对外提供释放资源的方法
public static void close(Connection conn,Statemet stmt){}
public static void close(Connection conn,Statemet stmt,ResultSet rs){}
}
'3 JDBC的SQL注入漏洞【重要】
原因:使用Statement对象执行SQL时,如果拼接的参数中有SQL关键字,就会出现注入漏洞。
解决:使用PreparedStatement对象代替Statement对象执行SQL。
原理:在获取PreparedStatement对象可以预编译SQL,固定SQL的格式和关键字,后期的参数使用?占位符代替,将来给占位符传参即可。
'PreparedStatement对象的使用步骤:【重要】
执行增删改:
1 通过JDBCUtils工具类获取连接得到Connection对象
2 通过Connection对象获取PreparedStatement对象,预编译SQL。
3 有几个?就设置几个参数
4 执行增删改操作,得到影响的行数。
5 处理结果。
6 释放资源。
执行查询:
1 通过JDBCUtils工具类获取连接得到Connection对象
2 通过Connection对象获取PreparedStatement对象,预编译SQL。
3 有几个?就设置几个参数
4 执行查询操作,得到ResultSet结果集对象。
5 处理结果(遍历/判断是否有下一行)。
6 释放资源。