JDBC学习笔记 2021-10-03 10:26:32

JDBC学习笔记

一、 基础概念:

  • java database connection

  • JDBC定义了操作所有关系型数据库的规则(接口)

  • 每个数据库厂商提供自己数据库的实现类(数据库驱动

  • JDBC本质:

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

二、 快速入门

入门代码示例 :

public class JdbcDemo1 {
    public static void main(String[] args) throws Exception {
//        1.导入驱动jar
//        2.注册驱动
        Class.forName("com.mysql.jdbc.Driver");
//        3.获取数据库连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/student", "root", "123456");
//        4. 定义sql语句
        String sql = "update student set age = 11 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();//释放执行sql语句的对象
        conn.close();//释放连接数据库的对象
    }
}

规范化代码:

*	处理异常
*	释放资源
*	判断结果
public class JDBCDemo2 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        try {
//              1. 注册驱动
            Class.forName("com.mysql.jdbc.Driver");
//              2. 获取数据库连接对象
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/student", "root", "123456");
//              3. 定义sql语句
            String sql = "insert into student value(null,'K',10)";
//              4. 获取执行sql的对象
            stmt = conn.createStatement();
//              5. 执行sql语句
            int count = stmt.executeUpdate(sql);//影响的行数
            System.out.println(count);//打印
//              6. 处理结果
            if(count > 0){
                System.out.println("添加成功!");
            }else{
                System.out.println("添加失败!");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            if(stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

步骤:

​ 1. 导入mysql的驱动jar包

  1. jar包名:mysql-connector-java-5.1.37-bin.jar

  2. 复制 mysql-connector-java-5.1.37-bin.jar 到项目的libs目录下(方便管理工具包)

  3. 在项目中对包点击右键–>Add as Library(真正将jar包加入项目工作空间中)

​ 2. 注册驱动

Class.forName("com.mysql.jdbc.Driver");

​ 3. 获取数据库连接对象Connection

​ 4.定义sql字符串存储sql语句

​ 5. 获取执行sql语句的对象Statement

​ 6. 执行sql语句,接受返回结果

​ 7. 处理结果

​ 8. 释放资源

三、 JDBC中的各个类和接口详解

1. DriverManager: 数据库驱动管理对象

①、注册驱动
1. 作用:

告诉程序应该用哪个数据库的驱动jar包

static void registerDriver(Driver driver)方法: 注册与给定的驱动程序 DriverManager

写代码则使用:Class.forName(“com.mysql.jdbc.Driver”); 加载名为com.mysql.jdbc.Driver的类进内存

com.mysql.jdbc.Driver包中的Driver类中写了静态代码块,调用了registerDriver()方法,从而实现了驱动注册

static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
}
2. 注意事项:

mysql 5 之后可以不用写注册驱动语句 ,因为jar包提供了一个java.mysql.Driver文件,里面写了类名com.mysql.jdbc.Driver,所以如果没有写注册驱动语句,则jar包会自动读取文件中的类名自动注册驱动。

所以mysql 5 之后的驱动jar包可以省略注册驱动的步骤

image-20211003100832764

②、连接数据库
  • 方法:static Connection``getConnection(String url, String user, String password)

  • 参数:

    • url:指定连接的数据库路径
    //        3.获取数据库连接对象
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/student", "root", "123456");
    
    语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
    例子:jdbc:mysql://localhost:3306/student
    拓展:如果连接的是本机的mysql服务器,并且mysql服务器默认端口是3306,则url可以简写为:jdbc:mysql:///student
    
    • user:数据库用户名
    • password:数据库密码

2.Connection:数据库连接对象

1. 功能:
①、获取执行sql语句的对象
  • Statement creatStatement()
  • PrepareStatement prepareStatement(String sql)
②、管理事务
  • 开启事务:void setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务。

    将此连接的自动提交模式设置为给定状态

  • 提交事务:void commit()

    使自上次提交/回滚以来所做的所有更改都将永久性,并释放此 Connection对象当前持有的任何数据库锁

  • 回滚事务:void rollback()

    撤消在当前事务中所做的所有更改,并释放此 Connection对象当前持有的任何数据库锁

3.Statment:执行sql语句的对象

1. 执行sql
①、(了解boolean execute(String sql) 方法:
  • 作用:

    ​ 执行此 Statement对象中的任意SQL语句,静态的sql语句:在sql字符串拼接好的时候就已经生成完整字符串

  • 返回值:

    true:如果第一个结果是一个ResultSet对象;

    false:如果第一个结果是更新计数或没有结果

②、int executeUpdate(String sql) 方法:
  • 作用:

    ​ 执行DML(insertupdatedelete)语句(常用,修改表的数据)

    ​ 执行DDL(creat,alter,drop)语句(不常用,因为表的结构设计一般在数据库中自己定义好了)

  • 返回值:

    ​ 操作影响的行数,可以通过这个影响的行数来判断DML语句是否执行成功,返回值大于0,则代表成功,反之则失败

③、ResultSet executeQuery()方法 :
  • 作用:

    ​ 执行DQL(select)查询语句

  • 返回值:

    ​ 一个包含查询产生的数据的ResultSet对象;从不null;

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

image-20211003140053807

①、boolean next()方法: 将光标从当前位置向下移动一行

返回值:

如果新的当前行有效,则返回true,此时游标还没有到达最后一行的末尾

如果新的当前行无效,则返回false,此时游标在最后一行之后的一行

②、Xxx getXxx()方法:获取相应数据类型的数据

有方法重载: 如:int getInt(参数)方法 String getString(参数)

int getInt(int columnIndex) 根据列的编号获取,编号从1开始,如getInt(3)
int getInt(String columnLabel) 根据列的名称获取,如getInt(“age”)

常用写法:
  int rs = stmt.executeQuery(sql);
  while(rs.next()){//当没有达到最后一行的末尾时
    int age = rs.getInt("age");
    System.out.println(age);
  }
③、将查询返回的结果数据封装成JSON对象(重点):
任务:将数据库中的student表中数据封装成JSON对象

数据库中的表:

库名称:student 表名称:student

image-20211003163018700

image-20211003163537178

实现代码:

student.class

package cn.itcast.doamin;

public class student {
    private String name;
    private int age;
    private int id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}

JDBCDemo6.class

package cn.itcast.jdbc;

import cn.itcast.doamin.student;

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

public class JDBCDemo6 {
    /**
     * 测试findAll()方法
     *
     * @param args
     */
    public static void main(String[] args) {
//        根据类JDBCDemo6,创建一个对象并调用其中的findAll()方法获取student数据
        List<student> list = new JDBCDemo6().findAll();
        System.out.println(list);
    }

    /**
     * 查询所有student对象
     *
     * @return
     */
    public List<student> findAll() {
        List<student> list = null;//声明一个List,存放student对象
        student stu = null;//声明student类的引用
        Connection conn = null;
        Statement stmt = null;
        ResultSet res = null;
        try {
//           1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
//           2、获取数据库连接对象
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/student", "root", "123456");
//           3、定义sql语句
            String sql = "select * from student";
//           4、获取sql语句执行对象
            stmt = conn.createStatement();
//           5、执行sql语句
            res = stmt.executeQuery(sql);
//           6、遍历结果集中的对象,封装对象,装载集合
//            创建list对象
            list = new ArrayList<student>();
            while (res.next()) {
                int id = res.getInt("id");
                String name = res.getString("name");
                int age = res.getInt("age");
//           6.1、创建一个student对象
                stu = new student();
//           6.2、给student对象赋值
                stu.setId(id);
                stu.setName(name);
                stu.setAge(age);
//           6.3、将student对象存放到list中,装载集合
                list.add(stu);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
//            7、释放资源
            if (res != null) {
                try {
                    res.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
//      8、返回封装好的list
        return list;
    }
}

控制台输出

"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=1989:D:\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\IDEA 工作间\itcast\out\production\jdbc;D:\IDEA 工作间\itcast\jdbc\libs\mysql-connector-java-5.1.37-bin.jar" cn.itcast.jdbc.JDBCDemo6
[student{name='Kevin', age=100, id=1}, student{name='K', age=100, id=2}, student{name='K', age=10, id=20}, student{name='K', age=10, id=21}, student{name='K', age=10, id=22}, student{name='K', age=10, id=23}, student{name='K', age=10, id=24}, student{name='K', age=10, id=25}, student{name='K', age=10, id=26}, student{name='K', age=10, id=27}, student{name='K', age=10, id=28}, student{name='K', age=10, id=29}]

Process finished with exit code 0

5.(*重要)PrepareStatement:执行sql语句的对象

①、SQL注入问题

在拼接sql语句时,有一些sql字符串的特殊字符参与字符串的拼接,会造成安全性的问题

​ 1.用户名任意输入:adwa,输入密码:a’ or ‘1’ = '1

​ 2.执行的sql语句为:select * from user where username = 'adwa' and password = 'a' or '1' = '1'

②、解决:

使用PrepraeStatement对象来解决

③、预编译的sql语句:

字符串中的参数使用?作为占位符替代

④、步骤:

​ 1. 导入mysql的驱动jar包

  1. jar包名:mysql-connector-java-5.1.37-bin.jar

  2. 复制 mysql-connector-java-5.1.37-bin.jar 到项目的libs目录下(方便管理工具包)

  3. 在项目中对包点击右键–>Add as Library(真正将jar包加入项目工作空间中)

​ 2. 注册驱动

Class.forName("com.mysql.jdbc.Driver");

​ 3. 获取数据库连接对象Connection

​ 4.定义sql字符串存储sql语句

  • 注意:用PrepareStatement对象执行sql语句
  • sql的参数用?作为占位符替代,如:String sql = "select * from user where username = ? and password = ?";

​ 5. 获取执行sql语句的对象PrepareStatement

PreparedStatement``prepareStatement(String sql) 创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。

​ 6. 给占位符?赋值

	*  	方法:setXxx(参数1,参数2)
	*  	参数1:占位符的位置编号,从1开始
	*  	参数2:占位符的值

​ 6. 执行sql语句,接受返回结果,不需要传递sql语句作为参数

​ 7. 处理结果

​ 8. 释放资源

⑤、注意:

后期都用PrepareStatement对象进行增删改查的所有操作

  • 可以防止sql注入
  • 效率更高

四、抽取JDBC工具类:JDBCUtils

1. 目的:简化书写

2. 分析:

①、注册驱动也需要抽取

②、抽取一个方法获取连接对象

  • 需求:不想传递参数(比较麻烦),还需要保证工具类的通用性
  • 解决:配置文件

文件名:jdbc.prrperties

路径:src目录下

内容:

url=jdbc:mysql://localhost:3306/student
user=root
password=123456
driver=com.mysql.jdbc.Driver

③、抽取一个方法释放资源

3. 注意:

  • 项目路径不能包含中文或者空格,否则会报错:系统找不到类的路径

  • 当jdbc.properties配置文件存放在src目录下时,需要先获取配置文件的路径,再进行文件加载

  • 获取配置文件的内容时,括号里应该填属性名字符串

    image-20211004143905063

4. 项目目录结构:

image-20211003232736990

5. 实现代码:

①、抽取的JDBCUtils工具类:
package cn.itcast.utils;

import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils {
    //    只有静态变量才能够被静态代码块和静态方法访问
    private static String url;
    private static String user;
    private static String password;
    private static String driver;

    /**
     * 静态代码块,只执行一次
     * 实现配置文件jdbc.properties内容的读取,只需要读取一次即可拿到这些值
     */
    static {
//    读取配置文件的内容
        try {
            /*
//            方法一:
//            1.获取当前类的类加载器
                ClassLoader classLoader = JDBCUtils.class.getClassLoader();
//            2.使用类加载器加载资源文件,并将其转换为输入流
                InputStream inputStream = classLoader.getResourceAsStream("jdbc.properties");
//            3.新建资源属性对象
                Properties pro = new Properties();
//            4.加载资源文件
                pro.load(inputStream);
//            5.打印资源的属性信息
                System.out.println("资源文件的内容-->"+ pro.toString());
            */


//          /*
//          方法二:
//          1. 获取文件的路径
//            ①、用绝对路径
//            String path = "D:\\IDEA_WorkSpace\\itcast\\jdbc\\src\\jdbc.properties";
//            ②、用类加载器ClasssLoader获取 src 路径下的文件的方式
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();//获取当前类的类加载器(可以加载字节码文件进内存,可以获取src目录下资源文件的路径)
            URL res = classLoader.getResource("jdbc.properties");//获取相对于src目录下指定文件名的资源对象,返回统一文件定位符,可以定位文件的绝对路径
            String path = res.getPath();//获取资源的字符串路径
            System.out.println("path-->" + path);
//          2. 创建集合对象
            Properties pro = new Properties();
//          3. 加载文件
            pro.load(new FileReader(path));
//          4. 打印资源的属性信息
            System.out.println("资源文件的内容-->" + pro.toString());
//          */


//          给类的成员变量赋值
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");
//          注册驱动
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 数据库连接
     *
     * @return 数据库连接对象
     */
    public static Connection getConnection() throws SQLException {
//        常用写法为配置文件获取mysql配置好的参数
        return DriverManager.getConnection(url, user, password);
    }

    /**
     * 释放资源,实现重载
     */
    public static void close(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void close(ResultSet res, Statement stmt, Connection conn) {
        if (res != null) {
            try {
                res.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
②、JDBCDemo6测试类(封装数据库数据):
package cn.itcast.jdbc;

import cn.itcast.doamin.student;
import cn.itcast.utils.JDBCUtils;

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

public class JDBCDemo6 {
    /**
     * 测试findAll()方法
     *
     * @param args
     */
    public static void main(String[] args) {
//        根据类JDBCDemo6,创建一个对象并调用其中的findAll()方法获取student数据
        List<student> list = new JDBCDemo6().findAll2();
        System.out.println(list);
    }

    /**
     * 查询所有student表
     * @return student对象数组
     */
    public List<student> findAll2() {
        List<student> list = null;//声明一个List,存放student对象
        student stu = null;//声明student类的引用
        Connection conn = null;
        Statement stmt = null;
        ResultSet res = null;
        try {
           1、注册驱动
//            Class.forName("com.mysql.jdbc.Driver");
           2、获取数据库连接对象
//            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/student", "root", "123456");
            //替换成:
            conn = JDBCUtils.getConnection();
//           3、定义sql语句
            String sql = "select * from student";
//           4、获取sql语句执行对象
            stmt = conn.createStatement();
//           5、执行sql语句
            res = stmt.executeQuery(sql);
//           6、遍历结果集中的对象,封装对象,装载集合
//            创建list对象
            list = new ArrayList<student>();
            while (res.next()) {
                int id = res.getInt("id");
                String name = res.getString("name");
                int age = res.getInt("age");
//           6.1、创建一个student对象
                stu = new student();
//           6.2、给student对象赋值
                stu.setId(id);
                stu.setName(name);
                stu.setAge(age);
//           6.3、将student对象存放到list中,装载集合
                list.add(stu);
            }

        }  catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
//            7、释放资源
//            替换成:
            JDBCUtils.close(res,stmt,conn);
//            if (res != null) {
//                try {
//                    res.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
//            if (stmt != null) {
//                try {
//                    stmt.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
//            if (conn != null) {
//                try {
//                    conn.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
        }
//      8、返回封装好的list
        return list;
    }
}

5. 输出结果:

"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=1583:D:\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IDEA_WorkSpace\itcast\out\production\jdbc;D:\IDEA_WorkSpace\itcast\jdbc\libs\mysql-connector-java-5.1.37-bin.jar cn.itcast.jdbc.JDBCDemo6
path-->/D:/IDEA_WorkSpace/itcast/out/production/jdbc/jdbc.properties
资源文件的内容-->{password=123456, driver=com.mysql.jdbc.Driver, user=root, url=jdbc:mysql://localhost:3306/student}
[student{name='Kevin', age=100, id=1}, student{name='K', age=100, id=2}, student{name='K', age=10, id=20}, student{name='K', age=10, id=21}, student{name='K', age=10, id=22}, student{name='K', age=10, id=23}, student{name='K', age=10, id=24}, student{name='K', age=10, id=25}, student{name='K', age=10, id=26}, student{name='K', age=10, id=27}, student{name='K', age=10, id=28}, student{name='K', age=10, id=29}]

Process finished with exit code 0

五、JDBC连接数据库练习

1. 需求:

连接数据库db,查询user表,实现用户登录验证逻辑

image-20211004102524529

2. 代码实现:

package cn.itcast.jdbc;

import cn.itcast.utils.JDBCUtils;

import java.sql.*;
import java.util.Scanner;

public class JDBCDemo7 {
    public static void main(String[] args) {
//        1.键盘输入账号密码
        Scanner in = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = in.nextLine();
        System.out.println("请输入密码:");
        String password = in.nextLine();
        boolean flag = new JDBCDemo7().login2(username, password);
        if (flag) {
            System.out.println("登录成功");
        } else {
            System.out.println("账号或密码错误");
        }


    }

    /**
     * 登录方法一:Statement对象,执行sql语句可能会产生sql注入问题,不安全
     */
    public boolean login(String username, String password) {
        if (username == null) {
            System.out.println("请输入账号");
            return false;
        }
        if (password == null) {
            System.out.println("请输入密码");
            return false;
        }
//        获取配置的资源文件路径
        Connection conn = null;
        Statement stmt = null;//Statement对象
        ResultSet res = null;
        try {
//            1.注册驱动,获取数据库连接对象
            conn = JDBCUtils.getConnection();
//            2.拼接字符串,定义sql语句
            String sql = "select * from user where username = '" + username + "' and password = '" + password + "'";
            System.out.println("sql语句-->" + sql);
//            3.创建执行sql语句的对象
            stmt = conn.createStatement();
//            4.执行sql语句
            res = stmt.executeQuery(sql);
//            5.如果查找到,则返回true,反之返回false
            return res.next();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
//            6.释放资源
            JDBCUtils.close(res, stmt, conn);
        }
        return false;
    }


    /**
     * 登录方法二:PrepareStstement对象,占位符替代参数,解决sql注入问题
     */
    public boolean login2(String username, String password) {
        if (username == null) {
            System.out.println("请输入账号");
            return false;
        }
        if (password == null) {
            System.out.println("请输入密码");
            return false;
        }
//        获取配置的资源文件路径
        Connection conn = null;
        PreparedStatement stmt = null;//PrepareStatement对象
        ResultSet res = null;
        try {
//            1.注册驱动,获取数据库连接对象
            conn = JDBCUtils.getConnection();
//            2.拼接字符串
            String sql = "select * from user where username = ? and password = ?";
//            3.创建执行sql的对象
            stmt = conn.prepareStatement(sql);//传入sql语句
//            4.给sql语句赋值
            stmt.setString(1, username);//赋值username
            stmt.setString(2, password);//赋值password
            System.out.println("sql语句-->" + sql);
//            5.执行sql语句,不用传sql语句
            res = stmt.executeQuery();
//            6.如果查找到,则返回true,反之返回false
            return res.next();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
//            7.释放资源
            JDBCUtils.close(res, stmt, conn);
        }
        return false;
    }

}

3. 控制台输出:

①、样例1:调用login()方法
"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=5190:D:\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IDEA_WorkSpace\itcast\out\production\jdbc;D:\IDEA_WorkSpace\itcast\jdbc\libs\mysql-connector-java-5.1.37-bin.jar cn.itcast.jdbc.JDBCDemo7
请输入用户名:
kevin
请输入密码:
kevin
sql语句-->select * from user where username = 'kevin' and password = 'kevin'
登录成功

Process finished with exit code 0

②、样例2:调用login()方法
"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=5199:D:\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IDEA_WorkSpace\itcast\out\production\jdbc;D:\IDEA_WorkSpace\itcast\jdbc\libs\mysql-connector-java-5.1.37-bin.jar cn.itcast.jdbc.JDBCDemo7
请输入用户名:
zhangsan
请输入密码:
123
sql语句-->select * from user where username = 'zhangsan' and password = '123'
登录成功

Process finished with exit code 0

③、样例3:(Statement对象执行sql可能会产生SQL注入问题)调用login()方法
"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=4753:D:\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IDEA_WorkSpace\itcast\out\production\jdbc;D:\IDEA_WorkSpace\itcast\jdbc\libs\mysql-connector-java-5.1.37-bin.jar cn.itcast.jdbc.JDBCDemo7
请输入用户名:
adwa
请输入密码:
a' or '1' = '1
sql语句-->select * from user where username = 'adwa' and password = 'a' or '1' = '1'
登录成功

Process finished with exit code 0

④、样例4:(PrepareStatement对象解决sql注入问题)调用login2()方法
"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=5173:D:\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IDEA_WorkSpace\itcast\out\production\jdbc;D:\IDEA_WorkSpace\itcast\jdbc\libs\mysql-connector-java-5.1.37-bin.jar cn.itcast.jdbc.JDBCDemo7
请输入用户名:
adwad
请输入密码:
a' or '1' = '1
sql语句-->select * from user where username = ? and password = ?
账号或密码错误

Process finished with exit code 0

六、JDBC控制事务:

1. 事务的概念:

一个包含多个步骤的业务操作。如果这个业务被事务管理,则这多个步骤要么同时成功,要么同时失败

2. 操作:

开启事务

提交事务

回滚事务

3.使用Connection对象管理事务

  • 开启事务:void setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务。

    将此连接的自动提交模式设置为给定状态

    在执行sql前开启事务

  • 提交事务:void commit()

    使自上次提交/回滚以来所做的所有更改都将永久性,并释放此 Connection对象当前持有的任何数据库锁

    当所有sql都执行完提交事务

  • 回滚事务:void rollback()

    撤消在当前事务中所做的所有更改,并释放此 Connection对象当前持有的任何数据库锁

    在catch中回滚事务

示例代码:

package cn.itcast.jdbc;

import cn.itcast.utils.JDBCUtils;

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

public class JDBCDemo8 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("请输入改变1的金额:");
        int num1 = in.nextInt();
        System.out.println("请输入改变1的金额:");
        int num2 = in.nextInt();
        Connection conn = null;
        PreparedStatement stmt1 = null;
        PreparedStatement stmt2 = null;
        try {
//            1.连接数据库
            conn = JDBCUtils.getConnection();
//            开启事务
            conn.setAutoCommit(false);
//            2.定义sql(更新book表中的金额)
            String sql1 = "update book set price = price + ? where bookName = 'C prime plus'";
            String sql2 = "update book set price = price + ? where bookName = 'offer'";
//            3.定义执行sql的PrepareStatement对象
            stmt1 = conn.prepareStatement(sql1);
            stmt2 = conn.prepareStatement(sql2);
//            4.给占位符赋值
            stmt1.setDouble(1, num1);
            stmt2.setDouble(1, num2);
//            5.执行sql更新数据库
            stmt1.executeUpdate();

//            制造异常
            int a = 2 / 0;

            stmt2.executeUpdate();

//            如果执行过程没有异常,则提交事务
            conn.commit();
        } catch (SQLException e) {
            if (conn != null) {//如果连接不为空,则回滚事务
                try {
                    conn.rollback();
                } catch (Exception ex) {//捕获大一点的异常
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
//            6.释放资源
            JDBCUtils.close(stmt1, conn);
            JDBCUtils.close(stmt2, null);
        }
    }
}

七、数据库连接池技术

1. 概念:

其实就是一个容器(集合),存放数据库连接对象的容器

当系统初始化好后,容器被创建,容器会申请一些数据库连接对象,当用户来访问数据库时,从容器中获取数据库连接对象,用户访问完之后,会将连接对象归还给容器

image-20211004144338446

2. 好处:

  • 节约资源
  • 用户访问高效

3. 实现:

①、标准接口:DataSource
  •  获取连接对象的方法:`getConnection()`
    
  •  归还连接对象的方法:如果连接对象是Connection是从连接池中获取的,那么调用`Connection.close()`方法时,则不是关闭连接,而是将连接对象归还到数据库连接池中,
    
②、拓展:
  • 数据库连接池技术一般是通过数据库厂商实现
    • C3P0:数据库连接池技术
    • Druid:数据库连接池技术,由阿里巴巴提供的

4、C3P0:数据库连接技术

①、步骤:
  • 1.导入数据库连接池jar包(两个c3p0-0.9.5.2.jarmchange-commons-java-0.2.12.jar

  • 2.导入数据库驱动jar包:

    1. 对项目点右键,new一个Directory文件夹,名称为libs,将jar包ctrl+v到libs文件夹中
    2. 注意:需要对libs点击右键,Add as Library
  • 3.定义配置文件:

    1. 名称:c3p0.properties 或者 c3p0-config.xml

    2. 路径1:直接将配置文件放到src目录下

  • 4.获取数据库连接池对象ComboPooledDataSource

    1. (*常用)使用默认c3p0配置: 方法括号中不传参数,则会使用c3p0的默认配置

    2. 使用指定c3p0配置:在xml文件中执行配置名称,方法括号中传入指定的c3p0配置文件名

    3. (*重要)由于指定了配置文件名称为c3p0.properties 或者 c3p0-config.xml,所以系统会自动加载配置文件

    4. image-20211005135050019

  • 5.常用的方法

      	1. 获取单个数据库连接对象:`getConnection()`
      	2. 归还数据库连接对象:`close()`
    
②、代码示例:
package cn.itcast.datasource.c3p0;

import com.mchange.v2.c3p0.ComboPooledDataSource;

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

public class C3P0Demo2 {
    public static void main(String[] args) throws SQLException {
//		1.获取数据库连接池对象,系统会自动加载配置文件
        ComboPooledDataSource ds = new ComboPooledDataSource();//使用默认c3p0配置
//        ComboPooledDataSource ds = new ComboPooledDataSource("pointedC3P0");//使用指定的名称为:pointedC3P0的c3p0配置
//        2.获取多个数据库连接对象
        for (int i = 1; i <= 10; i++) {
            Connection conn = ds.getConnection();
            System.out.println(i + " " + conn);
        }
    }
}

5. Druid数据库连接池技术:

①、步骤:
  • 1.导入jar包
  • 2.定义配置文件:
    1. properties形式的配置文件
    2. 可以叫任意名称,可以放在任意目录下
  • 3.获取数据库连接池对象:
  • 4.通过工厂类来获取 DruidDataSourceFactory()
    1. 括号中的参数为properties或者Map
    2. (*重要)需要手动加载properties配置文件
    3. image-20211005141807924
  • 5.常用方法:
    1. 获取单个单个数据库连接对象:getConnection()
    2. 归还单个数据库连接对象:close()
②、示例代码:
package cn.itcast.datasource.druid;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

public class DruidDemo1 {
    public static void main(String[] args) throws Exception {
//        1.导入Druid的jar包
//        2.定义配置文件
//        3.加载配置文件
        Properties pro = new Properties();
//        通过当前类加载器获取配置资源的文件路径
        InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
//        加载配置文件
        pro.load(is);
//        4.获取数据库连接池对象
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//        5.获取单个数据库连接对象
        Connection conn = ds.getConnection();
        System.out.println(conn);
    }
}

6. 抽取Druid数据库连接池的JDBCUtils工具类

①、步骤:
  1. 定义一个JDBCUtils工具类

  2. 提供静态代码块加载配置文件,并且初始化连接池对象

  3. 提供可以给外界访问的方法:

    1. DataSource getDataSource():返回数据库连接池对象

    2. Connection getConnection():放回单个数据库连接对象

    3. void close():释放资源、归还数据库连接对象

②、示例代码:
i、JDBCUtils工具类
package cn.itcast.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * Druid数据库连接池的工具类
 */
public class JDBCUtils {
    //    定义数据库连接池对象
    private static DataSource ds;

    //    定义静态代码块,只执行一次
    static {
        try {
//        1.获取配置文件的路径
            InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//        2.加载配置文件
            Properties pro = new Properties();
            pro.load(is);
//        3.获取数据库连接池对象
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 一、获取数据库连接池对象的方法
     */
    public static DataSource getDataSource(){
        return ds;
    }

    /**
     * 二、获取单个数据库连接的对象
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }


    /**
     * 三、释放资源,归还单个连接对象
     */
    public static void close(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();//归还连接
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 释放资源,归还单个连接对象
     */
    public static void close(ResultSet res, Statement stmt, Connection conn) {
        if (res != null) {
            try {
                res.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();//归还连接
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
ii. DruidDemo2测试类:
package cn.itcast.datasource.druid;

import cn.itcast.utils.JDBCUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

public class DruidDemo2 {
    public static void main(String[] args) {
        /**
         * 演示Druid的JUDBUtils工具类的使用
         */
        Scanner in = new Scanner(System.in);
        System.out.println("请输入student的昵称:");
        String name = in.nextLine();
        Connection conn = null;
        PreparedStatement stmt = null;
        try {
//        1.获取单个数据库的连接对象
            conn = JDBCUtils.getConnection();
//        2.定义sql语句
            String sql = "insert into student value(null,?,15)";
//        3.获取sql执行对象
            stmt = conn.prepareStatement(sql);
//         4.给占位符赋值
            stmt.setString(1,name);
//            执行sql语句
            int count = stmt.executeUpdate();
            System.out.println(count);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(stmt,conn);
        }
    }
}
iii. 控制台输出:
"C:\Program Files\Java\jdk-13.0.2\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=4453:D:\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IDEA_WorkSpace\jdbc\out\production\DatabaseConnection;D:\IDEA_WorkSpace\DatabaseConnection\libs\druid-1.0.9.jar;D:\IDEA_WorkSpace\DatabaseConnection\libs\c3p0-0.9.5.2.jar;D:\IDEA_WorkSpace\DatabaseConnection\libs\mchange-commons-java-0.2.12.jar;D:\IDEA_WorkSpace\DatabaseConnection\libs\mysql-connector-java-5.1.37-bin.jar cn.itcast.datasource.druid.DruidDemo2
请输入student的昵称:
lisi
1005, 2021 3:29:24 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1

Process finished with exit code 0

iv.数据库中的数据

八、Spring JDBC

1. 概念:

​ Spring框架对JDBC的简单封装,提供了一个JDBCTemplate对象简化JDBC的开发

2. 步骤:

  • 1.导入jar包(5个)

    image-20211005161402425

    注意:

    添加到libs目录下,并且Add as Library

    JDBCTemplate需要依赖于mysql驱动jar包和Druid数据库连接池的jar包

  • 2.创建JdbcTemplate对象。依赖于数据源DataSource

    ​ JdbcTemplate template = new JdbcTemplate(DataSource ds);

  • 3.调用JdbcTemplate的方法来完成CRUD的操作

    update():执行DML语句。增、删、改

    queryForMap():查询结果,将结果集封装成map集合

    queryForList():查询结果,将结果集封装成list集合

    query():查询结果,将结果集封装成JavaBean对象

    queryForObject():查询结果,将结果集封装为对象

3. 示例代码:

package cn.itcast.datasource.jdbctemplate;

import cn.itcast.utils.JDBCUtils;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 * JDBCTemplate入门学习
 */
public class JavaTemplateDemo1 {
    public static void main(String[] args) {
//        1.导入jar包
//        2.创建JdbcTemplate对象,传参为数据源,即数据库连接池对象
        JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//        3.定义sql语句
        String sql = "update student set name = ? where id = 2";
        int count = template.update(sql, "haha");
        System.out.println(count);
    }
}

由于时间关系:以下为简略笔记,以后会再找个时间进行详细记录

一、概述: JDBC从物理结构上说就是Java语言访问数据库的一套接口集合。从本质上来说就是调用者(程序员)和实现者(数据库厂商)之间的协议。JDBC的实现由数据库厂商以驱动程序的形式提供。JDBC API 使得开发人员可以使用纯Java的方式来连接数据库,并进行操作。 ODBC:基于C语言的数据库访问接口。 JDBC也就是Java版的ODBC。 JDBC的特性:高度的一致性、简单性(常用的接口只有4、5个)。 1.在JDBC中包括了两个包:java.sql和javax.sql。 ① java.sql 基本功能。这个包中的类和接口主要针对基本的数据库编程服务,如生成连接、执行语句以及准备语句和运行批处理查询等。同时也有一些高级的处理,比如批处理更新、事务隔离和可滚动结果集等。 ② javax.sql 扩展功能。它主要为数据库方面的高级操作提供了接口和类。如为连接管理、分布式事务和旧有的连接提供了更好的抽象,它引入了容器管理的连接池、分布式事务和行集等。 注:除了标出的Class,其它均为接口。 API 说明 java.sql.Connection 与特定数据库的连接(会话)。能够通过getMetaData方法获得数据库提供的信息、所支持的SQL语法、存储过程和此连接的功能等信息。代表了数据库java.sql.Driver 每个驱动程序类必需实现的接口,同时,每个数据库驱动程序都应该提供一个实现Driver接口的类。 java.sql.DriverManager (Class) 管理一组JDBC驱动程序的基本服务。作为初始化的一部分,此接口会尝试加载在”jdbc.drivers”系统属性中引用的驱动程序。只是一个辅助类,是工具。 java.sql.Statement 用于执行静态SQL语句并返回其生成结果的对象。 java.sql.PreparedStatement 继承Statement接口,表示预编译的SQL语句的对象,SQL语句被预编译并且存储在PreparedStatement对象中。然后可以使用此对象高效地多次执行该语句。 java.sql.CallableStatement 用来访问数据库中的存储过程。它提供了一些方法来指定语句所使用的输入/输出参数。 java.sql.ResultSet 指的是查询返回的数据库结果集。 java.sql.ResultSetMetaData 可用于获取关于ResultSet对象中列的类型和属性信息的对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值