JavaWeb学习的第四天(如何利用Java语言操作数据库_JDBC基本概念_JDBC中各个接口和类详解)

一、JDBC基本概念

1.什么是关系型数据库

不仅能够存储数据,还能够存储数据与数据之间的关系

2.如何操作数据库

通过sql语句在控制台和sqlyog上操作数据库

3.如何通过Java程序去操作数据库--JDBC的由来和JDBC和数据库驱动的关系

3.1 以前想使用java程序去操作mysql oracle db2等关系型数据库,都需要写一个特定的数据库去操作对应得数据库,这个时候就希望有人能够写一个程序可以用来操作所有的关系型数据库
3.2 sun公司写了一套程序可以操作所有的关系型数据库--JDBC
3.3 sun公司为了减轻自己的任务,把JDBC只是定义成一套规则,操作某个具体的数据库所使用到的一些方法就交给数据库自身厂家去写
3.4 具体操作本身数据库的方法的类的集合,称呼为数据库驱动(jar包)
3.5 每一个数据库的数据库驱动都不一样,根据需要导入对应得jar包
3.6 JDBC相当于是一个接口,而数据库驱动相当于一个具体的实现类

4.JDBC的本质

其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。
各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

二、如何使用JDBC去操作数据库??

从下方的百度网盘中下载mysql的数据库驱动jar包

链接:https://pan.baidu.com/s/15fO2Yc200UgmFlRMftj1Pw 
提取码:9ktl 

1.步骤

1.1 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
		复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
		右键-->Add As Library
1.2 注册驱动
1.3 获取数据库连接对象 Connection
1.4 定义sql
1.5 获取执行sql语句的对象 Statement
1.6 执行sql,接受返回结果
1.7 处理结果
1.8 释放资源

2.JDBC需要注意的地方

2.1 在mysql5.0版本之后可以注册驱动,但是建议大家不要省略
		Class.forName("com.mysql.jdbc.Driver"); //使用反射将这个类加载到内存中去
2.2 真正起到注册驱动的代码 DriverManager.registerDriver(new Driver());
		DriverManager.registerDriver(new Driver());
		//为什么不用上面这种这种格式
	因为:会重复注册两次,因为真正起到注册驱动的代码放在static修饰的静态代码块中,当我们加载字节码文件时就已经执行了注册驱动的代码,如果通过创建对象加载进内存,我们手写的驱动代码已经执行过一次了,但是当我们加载进内存时,静态代码块中的驱动代码,又执行了一次,一共加载了两次,浪费了空间

2.主要代码演示

//1. 导入驱动jar包
//2.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//3.获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "123");
//4.定义sql语句
String sql = "update account set balance = 500 where id = 1";
//5.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//6.执行sql
int count = stmt.executeUpdate(sql);
//7.处理结果
System.out.println(count);
//8.释放资源
stmt.close();
conn.close();

3.完整代码演示

package com.bianyiit.cast;

import java.sql.*;

public class JDBCDemo1 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //使用JDBC操作数据库
        //第一步:导入数据库驱动jar包,添加依赖
        //第二步:注册数据库驱动(加载驱动实现类) --- Driver
        //想把一句具体的实现类加载进内存,不推荐使用创建对象,而是加载字节码文件
        Connection connection=null;
        Statement statement=null;
        try {
            //在mysql5.0版本之后可以注册驱动,但是建议大家不要省略
            Class.forName("com.mysql.jdbc.Driver");
            //真正起到注册驱动的代码 DriverManager.registerDriver(new Driver());
            //第三步:使用驱动管理这个类去(DriverManager)获取操作数据库的连接对象
            String url="jdbc:mysql://localhost:3306/student02";
            //String url="jdbc:mysql:///student02"; //协议和要操作的数据库student02
            String uername="root";  //数据库的登录名
            String password="123";  //数据库的登录密码
            connection = DriverManager.getConnection(url, uername, password);
            //注意:connection只是与数据库产生了连接,并不能直接去操作数据库(不能执行sql语句)
            //第四步:通过连接对象创建能够执行sql语句的statement对象
            statement = connection.createStatement();
            //statament能直接操作数据库
            //第五步:执行sql语句
            String sql="INSERT INTO emp(id,NAME,gender,salary,join_date,dept_id)VALUE(10,'白龙马','男','7800',NULL,'2')";
            statement.execute(sql);//出现了错误,释放资源的代码就执行不了了
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭连接对象(mysal默认的最大连接数100,手动设置的最大连接数只有300或者400左右)
            //为什么要关闭数据库的连接对象---因为数据库连接是有限的,是非常宝贵的。
            try {
                    if(statement!=null){
                        statement.close();
                        statement=null; //为了快速被回收掉
                    }
                    if(connection!=null){
                        connection.close();
                        connection=null;
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
        }
    }
}

三、JDBC各个对象的详解

1.DriverManager:驱动管理对象

1.1 注册驱动:告诉程序该使用哪一个数据库驱动jar
	static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。 
	写代码使用:  Class.forName("com.mysql.jdbc.Driver");
	通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
	static {
		try {
			java.sql.DriverManager.registerDriver(new Driver());
		} catch (SQLException E) {
			throw new RuntimeException("Can't register driver!");
		}
	}
注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。

1.2 获取数据库连接:
	方法:static Connection getConnection(String url, String user, String password) 
	参数:
	url:指定连接的路径
	语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
	例子:jdbc:mysql://localhost:3306/db3
	细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称
	user:用户名
	password:密码 

2.Connection:数据库连接对象

2.1 获取执行sql 的对象
	Statement createStatement()
	PreparedStatement prepareStatement(String sql)  
2.2 管理事务:
	开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
	提交事务:commit() 
	回滚事务:rollback() 

3.Statement:执行sql的对象

3.1 执行sql
	boolean execute(String sql) :可以执行任意的sql 了解 
	int executeUpdate(String sql) :执行DML(insert、update、delete)语句     DDL(create,alter、drop)语句
    返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
    ResultSet executeQuery(String sql)  :执行DQL(select)语句

4.ResultSet:结果集对象,封装查询结果

	boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
	getXxx(参数):获取数据, Xxx:代表数据类型   如: int getInt() ,	String getString()
参数:
	1. int:代表列的编号,从1开始   如: getString(1)
	2. String:代表列名称。 如: getDouble("balance")

注意:使用步骤:
	1. 游标向下移动一行
	2. 判断是否有数据
	3. 获取数据
//循环判断游标是否是最后一行末尾。

while(rs.next()){
	//获取数据
	int id = rs.getInt(id);
	String name = rs.getString("name");
	System.out.println(id + "---" + name);
}

5.PreparedStatement:执行sql的对象

1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
	1. 输入用户随便,输入密码:a' or 'a' = 'a
	2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a' 

2. 解决sql注入问题:使用PreparedStatement对象来解决
3. 预编译的SQL:参数使用?作为占位符
4. 步骤:
	1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
	2. 注册驱动
	3. 获取数据库连接对象 Connection
	4. 定义sql
		* 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
	5. 获取执行sql语句的对象 PreparedStatement  Connection.prepareStatement(String sql) 
	6. 给?赋值:
		* 方法: setXxx(参数1,参数2)
			* 参数1:?的位置编号 从1 开始
			* 参数2:?的值
	7. 执行sql,接受返回结果,不需要传递sql语句
	8. 处理结果
	9. 释放资源

5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
	1. 可以防止SQL注入
	2. 效率更高

四、抽取JDBC工具类 : JDBCUtils

1.为什么要将一些代码抽取出来封装成JDBC工具类

1.1 目的:简化书写
1.2 分析:
	1. 注册驱动也抽取
	2. 抽取一个方法获取连接对象
	* 需求:不想传递参数(麻烦),还得保证工具类的通用性。
	* 解决:配置文件
		jdbc.properties
		url=
		user=
		password=
	3. 抽取一个方法释放资源

2.代码演示

package com.bianyiit.cast;

import java.sql.*;

//因为会重复使用该代码,所以定义了一个工具类
//1.获取连接对象
//2.关闭连接对象
public class JDBCUtil {
    /**
     * 用来获取连接对象的一个方法
     * @return
     */
    public static Connection getconnection() throws Exception {
        Connection connection=null;
        Statement statement=null;
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql://localhost:3306/student02";
        String uername="root";
        String password="123";
        connection = DriverManager.getConnection(url, uername, password);
        return connection;
    }
    /**
     * 关闭增删改连接对象用的(增删改操作没有结果集)
     */
    public static void close(Statement statement, Connection connection){
        try {
            if(statement!=null){
                statement.close();
                statement=null; //为了快速被回收掉
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 关闭查找时的连接对象用的
     */
    public static void close(ResultSet resultSet,Statement statement, Connection connection){
        try {
            if(resultSet!=null){
                resultSet.close();
                resultSet=null;
            }
            if(statement!=null){
                statement.close();
                statement=null; //为了快速被回收掉
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
package com.bianyiit.cast;

import java.sql.Connection;
import java.sql.Statement;

public class JDBCDemo2 {
    public static void main(String[] args) {
        Connection connection=null;
        Statement statement=null;
        //注册驱动和获取连接对象
        try {
            connection = JDBCUtil.getconnection();
            String sql="INSERT INTO emp(id,NAME,gender,salary,join_date,dept_id)VALUE(11,'奔波儿霸','男','10000',NULL,'1')";
            //创建执行sql语句对象
            statement = connection.createStatement();
            statement.execute(sql);//出现了错误,释放资源的代码就执行不了了
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtil.close(statement,connection);
        }
    }
}

五、如何将在数据库中查询的结果在控制台显示??

专门使用executeQuery()用来操作数据库的查询

1.使用statement..execute(sql)方法无法得到想要的结果,包括查询的内容返回的结果

1.1 statement对象执行sql的时候,使用execute()如果是查询操作,无法得到我们想要的结果
1.2 execute()可以执行增删该查的操作,但是进行查询操作,无法得到我们想要的结果,所以就专门细分
1.3 使用专门用来查询操作的方法 executeQuery()
1.4 使用executeQuery()执行sql进行查找的时候,返回的是一个结果集
	ResultSet resultSet = statement.executeQuery(sql);

2.如何从结果集中取一条数据显示在控制台上

//第一种方式
//得到结果集之后,相当于得到了一个指针,要进行判断,如果有下一个数据,指针就往下移,把这条数据取出来
//通过next()判断是否有下一个数据
resultSet.next();
//取数据,将字段都设置了编号,数据库中的索引是从1开始 id=1 name=2 gender=3 salary=4 join_date=5 dept_id=6
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
String gender = resultSet.getString(3);
String salary = resultSet.getString(4);
Date date = resultSet.getDate(5);
String dept_id = resultSet.getString(6);
//打印输出的结果
System.out.println(id+name+gender+salary+date+dept_id);
//第二种方式
//得到结果集之后,相当于得到了一个指针,要进行判断,如果有下一个数据,指针就往下移,把这条数据取出来
//通过next()判断是否有下一个数据
resultSet.next();
//取数据,直接通过数据库的字段名作为参数来获取结果
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String gender = resultSet.getString("gender");
String salary = resultSet.getString("salary");
Date date = resultSet.getDate("join_date");
String dept_id = resultSet.getString("dept_id");
System.out.println(id+"\t"+name+"\t"+gender+"\t"+salary+"\t"+date+"\t"+dept_id);

3.假如有十天匹配成功的数据,如何取两条数据呢?

//执行两遍代码
//第一遍先判断是否有第一个数据,如果有通过下述方式获取第一条数据
//通过next()判断是否有下一个数据
resultSet.next();
//取数据,直接通过数据库的字段名作为参数来获取结果
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String gender = resultSet.getString("gender");
String salary = resultSet.getString("salary");
Date date = resultSet.getDate("join_date");
String dept_id = resultSet.getString("dept_id");
System.out.println(id+"\t"+name+"\t"+gender+"\t"+salary+"\t"+date+"\t"+dept_id);

//在这里通过next(),指针往下移动一位,判断是否有第二条数据
resultSet.next();
//取数据,直接通过数据库的字段名作为参数来获取结果
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String gender = resultSet.getString("gender");
String salary = resultSet.getString("salary");
Date date = resultSet.getDate("join_date");
String dept_id = resultSet.getString("dept_id");
System.out.println(id+"\t"+name+"\t"+gender+"\t"+salary+"\t"+date+"\t"+dept_id);

4.是不是感觉上述代码很繁琐,所以可以使用循环来获取查询到的所有的结果

//当resultSet.next()返回值为true的时候代表有下一条数据
while (resultSet.next()){
	int id = resultSet.getInt("id");
	String name = resultSet.getString("name");
	String gender = resultSet.getString("gender");
	String salary = resultSet.getString("salary");
	Date date = resultSet.getDate("join_date");
	String dept_id = resultSet.getString("dept_id");
	System.out.println(id+"\t"+name+"\t"+gender+"\t"+salary+"\t"+date+"\t"+dept_id);
}
专门使用executeUpdate()用来操作数据库的增删改
package com.bianyiit.cast;

import java.sql.*;

//因为会重复使用该代码,所以定义了一个工具类
//1.获取连接对象
//2.关闭连接对象
public class JDBCUtil {
    /**
     * 用来获取连接对象的一个方法
     * @return
     */
    public static Connection getconnection() throws Exception {
        Connection connection=null;
        Statement statement=null;
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql://localhost:3306/student02";
        String uername="root";
        String password="123";
        connection = DriverManager.getConnection(url, uername, password);
        return connection;
    }
    /**
     * 关闭增删改连接对象用的(增删改操作没有结果集)
     */
    public static void close(Statement statement, Connection connection){
        try {
            if(statement!=null){
                statement.close();
                statement=null; //为了快速被回收掉
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 关闭查找时的连接对象用的
     */
    public static void close(ResultSet resultSet,Statement statement, Connection connection){
        try {
            if(resultSet!=null){
                resultSet.close();
                resultSet=null;
            }
            if(statement!=null){
                statement.close();
                statement=null; //为了快速被回收掉
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
package com.bianyiit.cast;

import java.sql.Connection;
import java.sql.Statement;

public class JDBCDemo4 {
    public static void main(String[] args) {
        Connection connection=null;
        Statement statement=null;
        //注册驱动和获取连接对象
        try {
            connection = JDBCUtil.getconnection();
            String sql1="INSERT INTO emp(id,NAME,gender,salary,join_date,dept_id)VALUES(10,'白龙马','男','7800',NULL,'2'),(11,'奔波儿灞','男','9600',NULL,'1')";
            String sql2="DELETE FROM emp WHERE id=9";
            //创建执行sql语句对象
            statement = connection.createStatement();
            //使用专门用来对数据库进行增删改的方法 executeUpdate()
            int i = statement.executeUpdate(sql2);  //返回值代表的是影响的数据的条数
            System.out.println("影响的条数"+i);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtil.close(statement,connection);
        }
    }
}

六、结合集合、实体类、对象和属性对查询到的数据进行封装

最好新建一个包用来存储实体类
在这里插入图片描述

package com.bianyiit.domian;

import java.sql.Date;

public class Student {
    private int id;
    private String name;
    private String gender;
    private String salary;
    private Date date;
    private String dept_id;

    public Student() {

    }

    public Student(int id, String name, String gender, String salary, Date date, String dept_id) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.salary = salary;
        this.date = date;
        this.dept_id = dept_id;
    }

    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 String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getSalary() {
        return salary;
    }

    public void setSalary(String salary) {
        this.salary = salary;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getDept_id() {
        return dept_id;
    }

    public void setDept_id(String dept_id) {
        this.dept_id = dept_id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", salary='" + salary + '\'' +
                ", date=" + date +
                ", dept_id='" + dept_id + '\'' +
                '}';
    }

}
package com.bianyiit.cast;
//查找emp这个表中名字有马的数据,并打印在控制台
import com.bianyiit.domian.Student;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class JDBCDemo5 {
    public static void main(String[] args) {
        List<Student> array=new ArrayList<Student>();
        List studentList = getstudent(array);
        for (Object o : studentList) {
            System.out.println((Student)o);
        }
    }

    private static List<Student> getstudent(List<Student> array) {
        Connection connection=null;
        Statement statement=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/student02", "root", "123");
            String sql="SELECT * FROM emp WHERE NAME LIKE '%精%'";
            statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            while(resultSet.next()){
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String gender = resultSet.getString("gender");
                String salary = resultSet.getString("salary");
                Date date = resultSet.getDate("join_date");
                String dept_id = resultSet.getString("dept_id");
               
                Student s=new Student();
                s.setId(id);
                s.setName(name);
                s.setGender(gender);
                s.setSalary(salary);
                s.setDate(date);
                s.setDept_id(dept_id);
                array.add(s);
            }
            //表对应一个实体类,表中的每一条数据对应的都是一个对象(实例)
            //而表中的字段对应一个属性
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(statement!=null){
                    statement.close();
                    statement=null;
                }
                if(connection!=null){
                    connection.close();
                    connection=null;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return array;
    }
}

数据库的存储的数据如下

输出结果截图:

七、使用JDBC实现登录功能

1.先创建一个登录表

2.代码实现登录功能

package com.bianyiit.cast;

import java.sql.*;

//因为会重复使用该代码,所以定义了一个工具类
//1.获取连接对象
//2.关闭连接对象
public class JDBCUtil {
    /**
     * 用来获取连接对象的一个方法
     * @return
     */
    public static Connection getconnection() throws Exception {
        Connection connection=null;
        Statement statement=null;
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql://localhost:3306/student02";
        String uername="root";
        String password="123";
        connection = DriverManager.getConnection(url, uername, password);
        return connection;
    }
    /**
     * 关闭增删改连接对象用的(增删改操作没有结果集)
     */
    public static void close(Statement statement, Connection connection){
        try {
            if(statement!=null){
                statement.close();
                statement=null; //为了快速被回收掉
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 关闭查找时的连接对象用的
     */
    public static void close(ResultSet resultSet,Statement statement, Connection connection){
        try {
            if(resultSet!=null){
                resultSet.close();
                resultSet=null;
            }
            if(statement!=null){
                statement.close();
                statement=null; //为了快速被回收掉
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
package com.bianyiit.cast;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

//登录案例
/*
输入用户名和密码,验证是否登录成功或者失败
* */
public class JDBCDemo6 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username = sc.next();
        System.out.print("请输入密码:");
        String password = sc.next();
        boolean login = login(username, password);
        //进行判断
        if(login){
            System.out.println("登录成功!");
        }else{
            System.out.println("登录失败!");
        }
    }

    /**
     * 用来输入的用户名和密码是否与数据中的数据匹配
     * @param username
     * @param password
     * @return
     */
    public static boolean login(String username,String password){
        Connection connection=null;
        Statement statement=null;
        ResultSet resultSet=null;
        try {
            connection = JDBCUtil.getconnection();
            //定义sql语句
            //因为传入到sql语句中的参数是一个变量,为了识别变量,需要把变量抽取出来
            String sql="SELECT * FROM denglu WHERE username='"+username+"' AND PASSWORD='"+password+"'";
            System.out.println(sql);
            //创建操作sql语句对象
            statement = connection.createStatement();
             //执行sql语句
            resultSet = statement.executeQuery(sql);
            //只需要resultSet.next()==true 代表在数据库中找到了输入的用户名和密码对应的数据
            if(resultSet.next()){
                return true;
            }else{
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //调用工具类的查询的释放资源的方法
            JDBCUtil.close(resultSet,statement,connection);
        }
        return false;
    }
}

已经存在数据库的账号和密码

运行结果截图:

但是这里会出现一个很严重的安全问题—数据库中没有该用户和密码,但是也登录成功了


sql注入问题及解决方案

请输入用户名:student
请输入密码:78484'or'2'='2'#
登录成功!

---sql注入的原因
因为存在一些特殊的sql语句与原先的sql语句中数据进行字符串拼接的时候,or前面的数据不管输入什么
都失效了,只会识别or 2=2(称之为sql注入)

---如何解决??
不再使用字符串拼接 使用占位符?代替
执行sql语句对象 使用预编译对象preparestatement代替statement
String sql="SELECT * FROM denglu WHERE username=? AND PASSWORD=? ";
正确的登录代码如下所示
package com.bianyiit.cast;

import java.sql.*;

//因为会重复使用该代码,所以定义了一个工具类
//1.获取连接对象
//2.关闭连接对象
public class JDBCUtil {
    /**
     * 用来获取连接对象的一个方法
     * @return
     */
    public static Connection getconnection() throws Exception {
        Connection connection=null;
        Statement statement=null;
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql://localhost:3306/student02";
        String uername="root";
        String password="123";
        connection = DriverManager.getConnection(url, uername, password);
        return connection;
    }
    /**
     * 关闭增删改连接对象用的(增删改操作没有结果集)
     */
    public static void close(Statement statement, Connection connection){
        try {
            if(statement!=null){
                statement.close();
                statement=null; //为了快速被回收掉
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 关闭查找时的连接对象用的
     */
    public static void close(ResultSet resultSet,Statement statement, Connection connection){
        try {
            if(resultSet!=null){
                resultSet.close();
                resultSet=null;
            }
            if(statement!=null){
                statement.close();
                statement=null; //为了快速被回收掉
            }
            if(connection!=null){
                connection.close();
                connection=null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
package com.bianyiit.cast;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

//登录案例
//输入用户名和密码,验证是否登录成功或者失败
public class JDBCDemo6 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username = sc.next();
        System.out.print("请输入密码:");
        String password = sc.next();
        boolean login = login(username, password);
        //进行判断
        if(login){
            System.out.println("登录成功!");
        }else{
            System.out.println("登录失败!");
        }
    }

    /**
     * 用来输入的用户名和密码是否与数据中的数据匹配
     * @param username
     * @param password
     * @return
     */
    public static boolean login(String username,String password){
        Connection connection=null;
        Statement statement=null;
        ResultSet resultSet=null;
        try {
            connection = JDBCUtil.getconnection();
            //不再使用字符串拼接 使用?作为占位符
            String sql="SELECT * FROM denglu WHERE username=? AND PASSWORD=? ";
            //预编译对象---sql语句在对象创建的时候就已经执行了,sql不能再进行更改(不能再进行字符串的拼接,只能给占位符进行赋值)
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            //使用预编译对象给占位符赋值
            preparedStatement.setString(1,username);
            preparedStatement.setString(2,password);
            //执行sql语句
            resultSet = preparedStatement.executeQuery();
            //只需要resultSet.next()==true 代表在数据库中找到了输入的用户名和密码对应的数据
            if(resultSet.next()){
                return true;
            }else{
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //调用工具类的查询的释放资源的方法
            JDBCUtil.close(resultSet,statement,connection);
        }
        return false;
    }
}

八、使用JDBC对事务进行处理

1.案例介绍
	//实现转账的案例
	/*张三和李四都有余额1000元
	* 张三余额减500
	* 李四余额加500*/
--如果在张三转完钱之后银行停电了,那么会导致这样一个结果,张三账号里面的钱减少了500元,但是李四账户里面的钱没有增加
--这个时候就要用到事务管理了,要么同时成功,要么同时失败

2. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
3. 操作:
	1. 开启事务
	2. 提交事务
	3. 回滚事务
4. 事务的四大特性
	1.原子性:不可分割的一个整体,要么同时成功,要么同时失败
	2.持久性:只要开启事务之后提交或回滚事务,数据会永久保存在数据库中
	3.隔离性:同时执行的事务是相互独立的(无法完全保证事务的隔离性)
	4.一致性:一个事务中多个操作中的数据总量是不会改变的*/
5. 使用Connection对象来管理事务
	1.开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
		* 在执行sql之前开启事务
	2.提交事务:commit() 
		* 当所有sql都执行完提交事务
	3.回滚事务:rollback() 
		* 在catch中回滚事务

代码演示

package com.bianyiit.cast;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCDemo7 {
    public static void main(String[] args) {
        Connection connection=null;
        try {
            //开启事务需要用到连接对象,关于事务所有的操作都是用Connection连接对象来完成
            //因为每一条sql语句自带commit提交事务的功能,
            //所以要设置开启事务---目的就是sql语句的自动提交设置成手动提交
            connection = JDBCUtil.getconnection();
            connection.setAutoCommit(false);  //设置成事务手动提交
            //定义一个sql语句---张三减500
            String sql="update account set balance=balance-? where id=?";
            //获取预编译执行对象
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            //通过preparedStatement给占位符赋值
            preparedStatement.setInt(1,500);
            preparedStatement.setInt(2,1);
            //进行sql语句得到
            preparedStatement.executeUpdate();

            //假如转账途中出现问题
            //int a=10/0;

            //定义一个sql语句---李四加500
            String sql1="update account set balance=balance+? where id=?";
            //获取预编译执行对象
            PreparedStatement preparedStatement1 = connection.prepareStatement(sql1);
            //通过preparedStatement给占位符赋值
            preparedStatement1.setInt(1,500);
            preparedStatement1.setInt(2,2);
            //进行sql语句得到
            preparedStatement1.executeUpdate();
            //关闭连接对象
            preparedStatement.close();
            preparedStatement1.close();
            //提交事务
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //进行事务的回滚
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

过程截图:
1.转账之前,张三和李四账户里面的余额

2.转账过程中不出现错误,张三和李四账户里面的余额

3.模拟张三转完钱之后,银行突然停电

IDEA的执行出现错误,如果不使用事务管理那么会出现下列结果

张三里面的500元已经扣掉了,但是李四的账户中没有增加500元

4.使用事务处理之后

如果这个业务(转账)操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
发布了73 篇原创文章 · 获赞 11 · 访问量 2452

猜你喜欢

转载自blog.csdn.net/weixin_43908333/article/details/103463026