1. JDBC概述
1.1 JDBC概念
- JDBC 就是使用Java语言操作关系型数据库的一套API。
- 全称:( Java DataBase Connectivity ) Java 数据库连接。
1.2 JDBC本质
- 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包。
- 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
1.3 JDBC好处
- 各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发。
- 可随时替换底层数据库,访问数据库的Java代码基本不变。
2. JDBC快速入门
package com.ydh.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* JDBC的快速入门
*/
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/test";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义sql \表示转义
String sql = "update book set book_name = \"JavaWeb\" where book_isbn = \"1001\"";
//4.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5.执行sql 返回结果是受影响的行数
int count = stmt.executeUpdate(sql);
//6.处理结果
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
3. JDBC-API详解
3.1 DriverManager
DriverManager(驱动管理类)的作用:
- 注册驱动
- 获取数据库的连接
3.1.1 注册驱动
Driver.class
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
在该类中的静态代码块中已经执行了
DriverManager
对象的registerDriver() 方法进行驱动的注册了,那么我们只需要加载 Driver
类,该静态代码块就会执行。
3.1.2 获取数据库的连接
//2.获取连接
//如果连接的是本机mysql服务器,并且mysql服务器的默认端口是3306,则可以省略ip地址和端口号
//useSSL=false参数 禁用安全连接方式,解决警告提示
String url = "jdbc:mysql:///test?useSSL=false";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);
3.2 Connection
Connection
(数据库连接对象)作用:
- 获取执行 SQL 的对象
- 管理事务
3.2.1 获取执行SQL对象
- 普通执行SQL对象
Statement createStatement()
- 预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(sql)
通过这种方式获取的
PreparedStatement
SQL
语句执行对象是可以防止SQL
注入。
3.2.2 事务管理
//4.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
try {
//5.开启事务 true为自动提交事务;false为手动提交事务,即为开启事务
conn.setAutoCommit(false);
//6.执行sql 返回结果是受影响的行数
int count1 = stmt.executeUpdate(sql1);
//7.处理结果
System.out.println(count1);
//int i = 3/0;
int count2 = stmt.executeUpdate(sql2);
System.out.println(count2);
//8.提交事务
conn.commit();
} catch (SQLException throwables) {
//回滚事务
conn.rollback();
throwables.printStackTrace();
}
3.3 Statement
Statement
对象的作用就是用来执行
SQL
语句。而针对不同类型的SQL语句使用的方法也不一样。
- 执行DDL、DML语句
- 执行DQL语句
3.3.1 执行DDL、DML语句
package com.ydh.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* JDBC-API详解-Statement
*/
public class JDBCDemo4_Statement {
public static void main(String[] args) throws Exception {
//1.注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
//如果连接的是本机mysql服务器,并且mysql服务器的默认端口是3306,则可以省略ip地址和端口号
//useSSL=false参数 禁用安全连接方式,解决警告提示
String url = "jdbc:mysql:///test?useSSL=false";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义sql \表示转义
//执行DML语句,返回结果是影响的行数
String sql1 = "update book set book_name = \"JavaWeb\" where book_isbn = \"1001\"";
//执行DDL语句,执行成功后也可能返回0
String sql2 = "drop database test2";
//4.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5.执行sql 返回结果是受影响的行数
int count1 = stmt.executeUpdate(sql1);
int count2 = stmt.executeUpdate(sql2);
//6.处理结果
if (count1 > 0){
System.out.println("修改成功~");
}else{
System.out.println("修改失败~");
}
// 0
System.out.println(count2);
//7.释放资源
stmt.close();
conn.close();
}
}
注意
- 以后开发很少使用java代码操作DDL语句。
3.3.2 执行DQL语句
package com.ydh.jdbc;
import com.ydh.pojo.Account;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
/**
* JDBC-API详解-ResultSet
*/
public class JDBCDemo5_ResultSet {
public static void main(String[] args) throws Exception {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/ydh";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);
//定义sql
String sql = "select * from Account";
//获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//执行sql 返回结果集
ResultSet rs = stmt.executeQuery(sql);
//创建集合,存储account对象
ArrayList<Account> array = new ArrayList<Account>();
//6.处理结果
//光标向下移动一行,判断当前行是否为有数据
while(rs.next()){
//通过下标可以获取每行对应的每列的数据(下标从1开始)
// int id = rs.getInt(1);
// String name = rs.getString(2);
// double money = rs.getDouble(3);
//通过字段名也可以获取每行对应的每列的数据
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
//创建account对象
Account account = new Account();
//给每个对象的三个属性分别赋值
account.setId(id);
account.setName(name);
account.setMoney(money);
//分别将每个对象添加到集合中
array.add(account);
}
//打印集合中的元素
//[Account{id=1, name='张三', money=3000.0}, Account{id=2, name='李四', money=1000.0}, Account{id=3, name='王五', money=3000.0}]
System.out.println(array);
//释放资源
rs.close();
stmt.close();
conn.close();
}
}
3.4 PreparedStatement
PreparedStatement作用:
- 预编译SQL语句并执行。
- 预防SQL注入问题。
3.4.1 SQL注入
SQL注入是通过操作输入来
修改事先定义好的SQL语句
,用以达到执行代码对服务器进行攻击的方法。
package com.ydh.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 用户登录
*/
public class JDBCDemo6_UserLogin {
public static void main(String[] args) throws Exception {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/test2";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户输入的用户名和密码
// String name = "zhangsan";
// String pwd = "123";
//sql注入
String name = "fskhkq";
String pwd = "'or'1'='1";
//定义sql
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
//select * from tb_user where username = 'fskhkq' and password = ''or'1'='1'
// System.out.println(sql);
//获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//执行sql
ResultSet rs = stmt.executeQuery(sql);
//判断登录是否成功
if(rs.next()){
//如果结果集中有数据,则登录成功
System.out.println("登录成功~");
}else{
//如果结果集中无数据,则登录失败
System.out.println("登录失败~");
}
//释放资源
rs.close();
stmt.close();
conn.close();
}
}
3.4.2 使用PreparedStatement改进
package com.ydh.jdbc;
import java.sql.*;
/**
* 用户登录
*/
public class JDBCDemo7_PreparedStatement {
public static void main(String[] args) throws Exception {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
//useServerPrepStmts=true 开启预编译功能
String url = "jdbc:mysql://127.0.0.1:3306/test2?useServerPrepStmts=true";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户输入的用户名和密码
String name = "zhangsan";
String pwd = "123";
//sql注入失败
// String name = "fskhkq";
// String pwd = "'or'1'='1";
//定义sql 参数值使用占位符?代替
String sql = "select * from tb_user where username = ? and password = ?";
//获取pstmt对象并传入sql语句
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置参数值
//参数1:占位符?的位置编号,从1开始
//参数2:占位符?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
//执行sql,获取结果集对象
ResultSet rs = pstmt.executeQuery();
//判断登录是否成功
if(rs.next()){
//如果结果集中有数据,则登录成功
System.out.println("登录成功~");
}else{
//如果结果集中无数据,则登录失败
System.out.println("登录失败~");
}
//释放资源
rs.close();
pstmt.close();
conn.close();
}
}
执行上面语句就可以发现不会出现
SQL
注入漏洞问题了。那么PreparedStatement又是如何解决的呢?它是
将特殊字符进行了转义
,转义的SQL
如下:
select * from tb_user where username = 'sjdljfld' and password = '\'or \'1\' = \'1'
PreparedStatement预编译原理
- 在获取PreparedStatement对象时,将sql语句发送给mysql服务器后检查SQL语法,编译SQL(生成可执行的函数)。这两个步骤很耗时。
- 执行SQL时就不用再进行以上两个步骤,只需传入相应的参数。
- 如果SQL模板一样,则只需要进行一次检查、编译即可。
3.5 数据库地址池
- 数据库连接池是个容器,负责分配、管理数据库连接 (Connection)。
- 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
- 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。
好处
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
之前我们代码中使用连接是没有使用都创建一个
Connection
对象, 使用完毕就会将其销毁。这样重复创建销毁的过程是特别耗费计算机的性能的及消耗时间的。 而数据库使用了数据库连接池后,就能达到Connection
对象的复用。
3.6 JDBC综合案例
数据库:
3.6.1 查询数据
package com.ydh.example;
import com.ydh.pojo.Brand;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 查询所有
* 1.sql:select * from tb_brand
* 2.参数:无
* 3.返回结果:结果集
*/
public class BrandTest {
public static void main(String[] args) throws Exception {
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/ydh?useServerPrepStmts=true";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
//定义sql
String sql = "select * from tb_brand";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//执行sql,获取rs对象
ResultSet rs = pstmt.executeQuery();
//创建brand对象
Brand brand;
//创建brands集合
List<Brand> brands = new ArrayList<>();
//处理结果
while(rs.next()){
brand = new Brand();
//获取每个brand对象的每个属性的值
int id = rs.getInt("id");
String brandName = rs.getString("brand_name");
String companyName = rs.getString("company_name");
int ordered = rs.getInt("ordered");
String description = rs.getString("description");
int status = rs.getInt("status");
//给每个brand对象的每个属性赋值
brand.setId(id);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setStatus(status);
//将每个brand对象添加到brands集合中
brands.add(brand);
}
//打印brands集合
System.out.println(brands);
//关闭资源
rs.close();
pstmt.close();
conn.close();
}
}
3.6.2 添加数据
package com.ydh.example;
import com.ydh.pojo.Brand;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
* 添加数据:
* 1.sql:insert into tb_brand(brand_name,company_name, ordered, description, status) values(?,?,?,?,?);
* 2.参数:除id之外所有的参数信息
* 3.返回结果:受影响的行数
*/
public class BrandTest02 {
public static void main(String[] args) throws Exception {
//接受页面提交的数据
String brandName = "香飘飘";
String companyName = "香飘飘公司";
int ordered = 1;
String description = "绕地球一圈";
int status = 1;
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/ydh?useServerPrepStmts=true";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
//定义sql
String sql = "insert into tb_brand(brand_name,company_name, ordered, description, status) values(?,?,?,?,?)";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置参数的值
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
//执行sql
int count = pstmt.executeUpdate();
//判断是否添加成功
if (count > 0){
System.out.println("添加成功~");
}else{
System.out.println("添加失败~");
}
//关闭资源
pstmt.close();
conn.close();
}
}
3.6.3 修改数据
package com.ydh.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
/**
* 修改数据:
* 1.sql:update tb_brand
* set brand_name = ?,company_name = ?,ordered = ?,description = ?,status = ?
* where id = ?;
* 2.参数:所有参数信息
* 3.返回结果:受影响的行数
*/
public class BrandTest03 {
public static void main(String[] args) throws Exception {
//接受页面提交的数据
String brandName = "优乐美";
String companyName = "优乐美公司";
int ordered = 2;
String description = "绕地球三圈";
int status = 1;
int id = 4;
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/ydh?useServerPrepStmts=true";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
//定义sql
String sql = "update tb_brand\n" +
"set brand_name = ?,company_name = ?,ordered = ?,description = ?,status = ?\n" +
"where id = ?";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置参数的值
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
pstmt.setInt(6,id);
//执行sql
int count = pstmt.executeUpdate();
//判断是否添加成功
if (count > 0){
System.out.println("修改成功~");
}else{
System.out.println("修改失败~");
}
//关闭资源
pstmt.close();
conn.close();
}
}
3.6.4 删除数据
package com.ydh.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
/**
* 删除数据:
* 1.sql:delete from tb_brand
* where id = ?;
* 2.参数:只有id参数信息
* 3.返回结果:受影响的行数
*/
public class BrandTest04 {
public static void main(String[] args) throws Exception {
//接受页面提交的数据
int id = 4;
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/ydh?useServerPrepStmts=true";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
//定义sql
String sql = "delete from tb_brand\n" +
"where id = ?";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置参数的值
pstmt.setInt(1,id);
//执行sql
int count = pstmt.executeUpdate();
//判断是否添加成功
if (count > 0){
System.out.println("删除成功~");
}else{
System.out.println("删除失败~");
}
//关闭资源
pstmt.close();
conn.close();
}
}