一、JDBC概念
代码演示:
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
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/db1"; // db1数据库 当中的account表
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 3、定义sql
String sql =" update account set money =1000 where id =1 ";
// 4 、获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
// 5、执行sql
int Count =stmt.executeUpdate(sql); // 受影响的行数 就 id =1 的钱数受了影响所以返回1
// 6、处理结果
System.out.println(Count);
// 7、释放资源
stmt.close();
conn.close();
}
}
输出结果:
数据库count表中信息(JDBC没连接操作前):
操作后:
二、DriverManager -API详解
DriverManager作用:
1、注册驱动
2、获取数据库连接
2.1、静态方法:registerDriver(Driver driver)
DriverManager 本身是个类
静态方法:
registerDriver(Driver driver)
注册与给定的驱动程序 DriverManager (注册驱动)
所以我们第一步:Class.forName("com.mysql.jdbc.Driver");
Driver底层本身调用的是DriverManager的registerDriver(Driver driver) 静态方法
2.2、getConnection(url,username,password) 方法
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* JDBC API 详解 - DriverManager类
*/
public class JDBCDemo02_DriverManager {
public static void main(String[] args) throws Exception {
// 1、注册驱动(可省略不屑)
// 2、获取连接对象:如果连接的是本机mysql 并且端口是默认的 3306 可以简化书写
String url ="jdbc:mysql:///db1?useSSL=false"; // 简化端口 并且把红色提示去掉(注意别有空格)
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 3、定义sql
String sql =" update account set money =1000 where id =1 ";
// 4 、获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
// 5、执行sql
int Count =stmt.executeUpdate(sql); // 受影响的行数 就 id =1 的钱数受了影响所以返回1
// 6、处理结果
System.out.println(Count);
// 7、释放资源
stmt.close();
conn.close();
}
}
三、Connection
Connection是一个接口
两个方法作用:
1、获取执行SQL的对象
2、开启事务管理
代码演示如下 (sql执行期间无异常情况时): try....catch 快捷键: Ctrl+alt+t
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* JDBC API 详解 - Connection接口 作用演示
*/
public class JDBCDemo02_Connection {
public static void main(String[] args) throws Exception {
// 1、注册驱动(可省略不屑)
// 2、获取连接对象:如果连接的是本机mysql 并且端口是默认的 3306 可以简化书写
String url ="jdbc:mysql:///db1?useSSL=false"; // 简化端口 并且把红色提示去掉(注意别有空格)
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
/**
* 下列的需求是:同时对数据库当中两个sql语句进行操作修改
* 要求:两个sql语句要么全部修改操作成功,要么全部失败
* 因此需要我们利用Connection的作用 (事务管理)
*/
// 3、定义两个sql
String sql1 =" update account set money =3000 where id =1 ";
String sql2 =" update account set money =3000 where id =2 ";
// 4 、获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
/**
* 因为由上述的要求: 所以我们需要在执行sql之前开启事务
* 当执行sql之间都没有发生异常的时候 就提交事务
* 有异常的时候 就回滚事务 (也就是说返回到执行sql之前 不修改数据保证数据的安全)
*/
conn.setAutoCommit(false); // 手动提交事务/开启
try {
// 5、执行sql
int Count1 =stmt.executeUpdate(sql1); // 受影响的行数 就 id =1 的钱数受了影响所以返回1
// 6、处理结果
System.out.println(Count1);
// 5、执行sql
int Count2 =stmt.executeUpdate(sql2); // 受影响的行数 就 id =2 的钱数受了影响所以返回1
// 6、处理结果
System.out.println(Count2);
conn.commit(); // sql执行完毕之后 提交事务
} catch (SQLException e) {
// 当执行SQL之间出现异常的时候就会进入catch分支 在此我们可以直接回滚事务 (保证数据的安全)
conn.rollback();
}
// 7、释放资源
stmt.close();
conn.close();
}
}
执行前:
执行后:
代码演示:(当sql执行期间出现异常的时):
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* JDBC API 详解 - Connection接口 作用演示
*/
public class JDBCDemo02_Connection {
public static void main(String[] args) throws Exception {
// 1、注册驱动(可省略不屑)
// 2、获取连接对象:如果连接的是本机mysql 并且端口是默认的 3306 可以简化书写
String url ="jdbc:mysql:///db1?useSSL=false"; // 简化端口 并且把红色提示去掉(注意别有空格)
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
/**
* 下列的需求是:同时对数据库当中两个sql语句进行操作修改
* 要求:两个sql语句要么全部修改操作成功,要么全部失败
* 因此需要我们利用Connection的作用 (事务管理)
*/
// 3、定义两个sql
String sql1 =" update account set money =3000 where id =1 ";
String sql2 =" update account set money =3000 where id =2 ";
// 4 、获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
/**
* 因为由上述的要求: 所以我们需要在执行sql之前开启事务
* 当执行sql之间都没有发生异常的时候 就提交事务
* 有异常的时候 就回滚事务 (也就是说返回到执行sql之前 不修改数据保证数据的安全)
*/
conn.setAutoCommit(false); // 手动提交事务/开启
try {
// 5、执行sql
int Count1 =stmt.executeUpdate(sql1); // 受影响的行数 就 id =1 的钱数受了影响所以返回1
// 6、处理结果
System.out.println(Count1);
// 5、执行sql
int Count2 =stmt.executeUpdate(sql2); // 受影响的行数 就 id =1 的钱数受了影响所以返回1
/**
* 假设这里在执行sql期间 出现了异常情况 虽然sal1语句执行完成了 但是由于开启了事务
* 所以会进入到catch分支 回滚事务, 此时sql1 和 sql2数据都不会发生变化(保证数据安全)
*/
int a =10/0;
// 6、处理结果
System.out.println(Count2);
conn.commit(); // sql执行完毕之后 提交事务
} catch (SQLException e) {
// 当执行SQL之间出现异常的时候就会进入catch分支 在此我们可以直接回滚事务 (保证数据的安全)
conn.rollback();
}
// 7、释放资源
stmt.close();
conn.close();
}
}
虽然sql1修改了数据 但是因为开启了事务 回滚事务了 所以sql1 和 sql2 对应的数据都不发生变化
四、Statement
executeUpdate方法 执行DML (对表中数据的增删改查) 演示如下:
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* Statement 作用演示
*/
public class JDBCDemo04_Statement {
public static void main(String[] args) throws Exception {
// 1、注册驱动
Class.forName("com.mysql.jdbc.Driver"); // 固定写法
// 2、获取连接对象
String url ="jdbc:mysql:///db1?useSSL=false";
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 3、定义sql
String sql =" update account set money =1000 where id =5 ";
// 4 、获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
// 5、执行sql
int Count =stmt.executeUpdate(sql);
// 6、处理结果
// System.out.println(Count);
/**
* 这里我们可以进行改进: 比如我们不希望看到 0(定义sql语句的增删改查中没有定义的sql语句的时候)
* 比如 表中数据就两个 id =1 id =2 但是我们sql语句整个id =5 (说明影响了0行数据)那么就会返回 0
* 我们不想让他返回0 或者 1 想返回更直观的 操作如下
*/
if (Count >0){ // 大于0 说明对数据进行操作成功了
System.out.println("修改成功~");
}else if (Count ==0){ // 等于 0 说明sql语句 在数据库中对应不到该sql条数据
System.out.println("修改失败~");
}
// 7、释放资源
stmt.close();
conn.close();
}
}
executeUpdate方法 执行DDL (对表结构[表框架]的增删改查) 演示如下:
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* Statement 作用演示
*/
public class JDBCDemo04_Statement {
public static void main(String[] args) throws Exception {
// 1、注册驱动
Class.forName("com.mysql.jdbc.Driver"); // 固定写法
// 2、获取连接对象
String url ="jdbc:mysql:///db1?useSSL=false";
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 3、定义sql
String sql =" drop database db2";
// 4 、获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
// 5、执行sql
int Count =stmt.executeUpdate(sql);
// 6、处理结果
System.out.println(Count);
/**
* 操作DDL的时候 我们会发现,即使我们sql语句是删除一条的数据 虽然也影响了一条
* 但是对于DDL的返回结果仍然为 0 所以我们不能用if判断 来增加我们的直观性了
*/
// 7、释放资源
stmt.close();
conn.close();
}
}
返回值 ResultSet 详解
代码演示:
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* JDBC的快速入门
*/
public class JDBCDemo_ResultSet {
public static void main(String[] args) throws Exception {
// 1、注册驱动
Class.forName("com.mysql.jdbc.Driver"); // 固定写法
// 2、获取连接对象
String url ="jdbc:mysql:///db1?useSSL=false";
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 3、定义sql
String sql ="select * from account";
// 4 、获取执行sql的statement对象
Statement stmt = conn.createStatement();
// 5、执行sql
/**
* 因为这里 我们是查询account表中的数据 所以这时我们就用executeQuery()方法
* 返回ResultSet集合对象
*而 executeUpdate()方法 不能用来做查询
*/
ResultSet rs =stmt.executeQuery(sql);
// 处理结果 遍历rs中的所有数据
while (rs.next()){ // 光标依次向下移动一行 并且判断当前行是否有数据
// 可以理解为:先拿到select * from account SQL语句对应的的数据库表格数据 然后对此表格数据依次一行的移动取数据
// 有数据的话 获取数据 getXxx()
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");
*/
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("--------------");
}
// 7、释放资源
stmt.close();
conn.close();
rs.close();
}
}
eg:
Account类:
package com.itheima.pojo;
/**
* Account 类
*/
public class Account {
private int id;
private String name;
private double money;
public Account(int id, String name, double money) {
this.id = id;
this.name = name;
this.money = money;
}
public Account() {
}
// getter and setter 方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
/**
* toString()方法 : 当输出该对象引用的时候 调用toString方法进行输出
* @return
*/
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
通过JDBC操作数据库把数据封装到Account对象当中依次存放到ArrayList集合当中:
package com.itheima.jdbc;
import com.itheima.pojo.Account;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* 查询account账户表数据,封装为Account对象中,并且储存到Arraylist集合中
*/
public class JDBCDemo_ResultSet1 {
public static void main(String[] args) throws Exception {
// 1、注册驱动
// 2、获取连接对象
String url ="jdbc:mysql:///db1?useSSL=false";
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 3、定义sql
String sql ="select * from account";
// 4 、获取执行sql的statement对象
Statement stmt = conn.createStatement();
// 5、执行sql
/**
* 因为这里 我们是查询account表中的数据 所以这时我们就用executeQuery()方法
* 返回ResultSet集合对象
*/
ResultSet rs =stmt.executeQuery(sql);
/**
* 把每循环一次遍历出的数据库数据封装到对象当中的 东西依次存放到ArrayList集合当中
*/
// 创建集合
List<Account> list =new ArrayList<>();
// 处理结果 遍历rs中的所有数据
while (rs.next()){ // 光标依次向下移动一行 并且判断当前行是否有数据
/**
* 每循环一次就把这次循环的数据库中的id name money 赋到Account对象属性当中
*/
Account account =new Account();
// 属性赋值
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getDouble("money"));
// 存放到集合当中
list.add(account);
}
// 查看集合数据 (注意:这里不能在while上面 因为在上面时数据还没存放到集合中)
System.out.println(list);
// 7、释放资源
stmt.close();
conn.close();
rs.close();
}
}
五、Connection当中的PreparedStatement方法
用户登录演示:用户名和密码校验问题
当用户在网页上输入用户名和密码后我们需要拿到用户输入的用户名和密码和数据库中的用户名和密码作比较,一致登陆成功、不一致登录失败
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 普通用户登录 用户名和密码校验问题
*/
public class JDBCDemo_UserLogin {
public static void main(String[] args) throws Exception {
// 1、注册驱动
// 2、获取连接对象
String url ="jdbc:mysql:///db1?useSSL=false";
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
/**
* 这里我们接收用户输入(比如网页用户输入的用户名和密码) 用户名 和 密码
* 注意:真正开发中,用户肯定输入的用户名和密码不是固定的 因此下面我们定义sql语句的时候需要拼接字符串成不固定的
* 这里我们假设用户输入的是 Kitty 12345
* 得到用户输入的用户名和密码后 和我们数据库当中的用户名和密码比较,一样的话登录成功 不一样登陆失败
*/
String name ="Kitty";
String pwd ="12345";
// 3、定义sql
String sql =
"select * from tb_user where username ='"+name+"' and password ='"+pwd+"'";
// 4 、获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
// 5、执行sql
ResultSet rs =stmt.executeQuery(sql);
// 6、处理结果
// 判断登录是否成功
if (rs.next()){ // 如果光标在数据库表中指到了查找用户名和密码的位置 说明表中有用户输入进来的用户名和密码
System.out.println("用户登录成功~");
}else {
System.out.println("用户登录失败");
}
// 7、释放资源
stmt.close();
conn.close();
rs.close();
}
}
数据库当中储存的用户的用户名和密码:(用于用户输入进来的用户名和密码作比较)
以上操作用注入问题演示:
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 注入问题演示:
*/
public class JDBCDemo_UserLogin {
public static void main(String[] args) throws Exception {
// 1、注册驱动
// 2、获取连接对象
String url ="jdbc:mysql:///db1?useSSL=false";
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
/**
* 注入问题:
* 尽管用户输入的 用户名和密码 在数据库当中不存在 但是用户名通过输入特殊的密码符号
* 可以通过SQL的注入进行破解进入网站
*/
String name ="wafwagges";
String pwd =" ' or '1' = '1";
/**
* 通过上面用户随便写的用户名 和 密码 当我们拿着用户输入进来的 用户名和密码 去数据库当中对比校验的时候
* 发现竟然登录成功了 这就是注入问题
*/
// 3、定义sql (通过查找数据库 校验用户名和密码)
String sql =
"select * from tb_user where username ='"+name+"' and password ='"+pwd+"'";
System.out.println(sql);
/**
* 我们可以在这里输入下查找SQL语句看看是怎么在数据库当中查找的用户名和密码
* select * from tb_user where username ='wafwagges' and password =' ' or '1' = '1'
* 分析SQL查找语句: 当 and 和 or 连用的时候 先执行 and
* select * from tb_user where username ='wafwagges' and password =' ' 会发现这个为 false
* 但是 '1' = '1' 为 true
* false or true 结果为 true 所以会把tb_user表中的所有数据查出来 最后判断的时候查找的有结果 因此就登陆成功了
*
* 这就是注入问题 :通过特殊的符号破解SQL拼接问题 从而登陆成功网站
*/
// 4 、获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
// 5、执行sql
ResultSet rs =stmt.executeQuery(sql);
// 6、处理结果
// 判断登录是否成功
if (rs.next()){ // 如果光标在数据库表中指到了查找用户名和密码的位置 说明表中有用户输入进来的用户名和密码
System.out.println("用户登录成功~");
}else {
System.out.println("用户登录失败");
}
// 7、释放资源
stmt.close();
conn.close();
rs.close();
}
}
注入问题的原因:就是用户输入进来的用户名和密码 会通过SQL语句拼接字符串 特殊的就会不安全, 下面我们解决注入问题 (不拼接字符串了 用 ?占位)
PreparedStatement:
package com.itheima.jdbc;
import java.sql.*;
/**
* 解决注入问题演示:
*/
public class JDBCDemo_PreparedStatement {
public static void main(String[] args) throws Exception {
// 1、注册驱动
// 2、获取连接对象
String url ="jdbc:mysql:///db1?useSSL=false";
String username ="root";
String password ="123456";
Connection conn = DriverManager.getConnection(url,username,password);
/**
* name : 用户名
* pwd : 用户名密码
*/
String name ="wafwagges";
String pwd =" ' or '1' = '1";
// 3、定义sql (用 ? 符占位 防止用户输入的用户名和密码 和SQL语句拼接字符串)
String sql =" select * from tb_user where username = ? and password =? ";
// 4 、获取执行sql的对象 PreparedStatement对象
PreparedStatement preparedStatement =conn.prepareStatement(sql);
// 设置 ? 参数值
preparedStatement.setString(1,name); // 第一个 ? 传入 用户输入的用户名
preparedStatement.setString(2,pwd); // 能够把特殊字符串进行转义操作
// 5、执行sql
ResultSet rs =preparedStatement.executeQuery();
// 6、处理结果
// 判断登录是否成功
if (rs.next()){ // 如果光标在数据库表中指到了查找用户名和密码的位置 说明表中有用户输入进来的用户名和密码
System.out.println("用户登录成功~");
}else {
System.out.println("用户登录失败~");
}
// 7、释放资源
preparedStatement.close();
conn.close();
rs.close();
}
}
六、数据库连接池
数据库连接池实现:
properties配置文件:
package com.itheima.druid;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
/**
* Druid数据库连接池演示
*/
public class DruidDemo {
public static void main(String[] args) throws Exception {
// 1.导入jar包
// 2.定义配置文件
// 3.加载配置文件
Properties prop =new Properties();
prop.load(new FileInputStream("jdbc-demo/src/druid.properties")); // 把读出来的properties文件 加载到prop集合中
// 4.获取数据库连接池对象 conn
DataSource dataSource =DruidDataSourceFactory.createDataSource(prop);
// 5.获取数据库连接 Connection
Connection connection =dataSource.getConnection();
System.out.println(connection);
}
}