• JDBC学习笔记


    JDBC

    文章目录

    本笔记学习自尚硅谷课程…

    1. 创建项目及环境

    1.1 创建项目

    JDBC
    JDBC

    1.2 加入JDBC jar包

    创建一个文件夹lib专门用来存放项目需要的jar包
    JDBC
    右键 lib文件夹,选择 Add as Library

    JDBC

    2. 创建 class (这里是一个水果管理的实例)

    package com.test.JDBC;
    
    public class Fruit {
        private Integer fid;
        private String fanme;
        private Integer price;
        private Integer fcount;
        private String remark;
    
        public Fruit() {
        }
    
        public Fruit(Integer fid, String fanme,String remark) {
            this.fid = fid;
            this.fanme = fanme;
            this.remark = remark;
        }
    
        public Fruit(Integer fid, String fanme, Integer price, Integer fcount, String remark) {
            this.fid = fid;
            this.fanme = fanme;
            this.price = price;
            this.fcount = fcount;
            this.remark = remark;
        }
    
        public Integer getFid() {
            return fid;
        }
    
        public void setFid(Integer fid) {
            this.fid = fid;
        }
    
        public String getFanme() {
            return fanme;
        }
    
        public void setFanme(String fanme) {
            this.fanme = fanme;
        }
    
        public Integer getPrice() {
            return price;
        }
    
        public void setPrice(Integer price) {
            this.price = price;
        }
    
        public Integer getFcount() {
            return fcount;
        }
    
        public void setFcount(Integer fcount) {
            this.fcount = fcount;
        }
    
        public String getRemark() {
            return remark;
        }
    
        public void setRemark(String remark) {
            this.remark = remark;
        }
    
        @Override
        public String toString() {
            return "Fruit{" +
                    "fid=" + fid +
                    ", fanme='" + fanme + '\'' +
                    ", price='" + price + '\'' +
                    ", fcount='" + fcount + '\'' +
                    ", remark='" + remark + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    3. JDBC 连接MySQL 数据库

    3.1 实现JDBC连接MySQL数据库

    package com.test.JDBC;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    /**
     * 目标:和数据库建立连接
     */
    public class demo1 {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            //1.添加jar
            //2. 加载驱动 Driver
            Class.forName("com.mysql.jdbc.Driver");
            //3. 通过驱动管理器获取连接对象 DriverManager是类,其他的都是接口
            //3-1 准备url ‘jdbc:mysql://’ 固定写法
            String url = "jdbc:mysql://localhost:3306/dbjavalearning";
            //3-2准备用户名
            String user = "root";
            //3-3准备密码
            String pwd = "root";
            Connection connection = DriverManager.getConnection(url, user, pwd);
            System.out.println("conn = " + connection);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    3.1.1 注意:Connection 的类名

    JDBC

    3.1.2 注意数据库URL

    数据库不一定在本地,测试服务器不会在本地,需要访问。socket连接,需要一台机器的ip和端口号

    jdbc:mysql://localhost:3306/dbjavalearning
    
    • 1

    3.2 JDBC 说明

    JDBC 用于服务器端连接数据库端,解决数据如何连接通讯的问题。

    JDBC

    3.3 常见错误

    a. ClassNotFoundException

    JDBC
    点击IDEA 左上角的File> -> Project Structure… 发现出现主项目 JavaWeb 存在刚才1.2中加入的jar包,
    JDBC
    但是子项目 JDBC 中却不存在jar包
    JDBC
    子项目添加一下jar包
    JDBC
    点击 Add Selected
    JDBC

    此时可以发现,编写代码时已经可以出现自动补充
    JDBC
    运行成功
    JDBC

    4. JDBC 对数据库进行增删改操作

    4.1 insert增加操作

    package com.test.JDBC;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    /**
     * JDBC - 插入
     */
    public class deom_Insert {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            //1.加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
    
            //2,通过驱动管理获取连接对象  如果出现警告: Establishing SSL connection without server 请在后面加入: ?useSSL=false&
            //如果还需要处理中文乱码,?useUnicode=true&characterEncoding=utf8 &useSSL=false
            //url表示 统一资源定位符——和数据库通信地址
            //如果url需要带参数,则需要使用?进行连接
            //如果需要带多个参数,则从第二个参数开始使用&连接
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            String user = "root";
            String pwd = "root";
            Connection connection = DriverManager.getConnection(url, user, pwd);
    
            //3.编写SQL语句
            // id , fname , price , fcount , remark
            String sql = "insert into t_fruit value(0,?,?,?,?)";
    
            //4. 创建预处理命令对象
            PreparedStatement psmt = connection.prepareStatement(sql);
            // 5. 填充参数
            psmt.setString(1,"樱桃");
            psmt.setInt(2,35);
            psmt.setInt(3,90);
            psmt.setString(4,"樱桃是一种好吃的水果");
            //6 执行更新(增删改),返回影响行数
            int count = psmt.executeUpdate();
            System.out.println(count > 0 ? "添加成功":"添加失败!");
            //7.释放资源(关闭连接)
            // 先关闭psmt 后关闭 connection 顺序不能错!
            psmt.close();
            connection.close();
        }
    }
    
    /*
      如果出现:
      Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
      将com.mysql.jdbc.Driver 改成 com.mysql.cj.jdbc.Driver
     */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    更新前
    JDBC
    更新后
    JDBC
    JDBC

    4.2 update修改操作

    package com.test.JDBC;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    /**
     * JDBC - 修改
      */
    public class demo_Update {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            Fruit fruit = new Fruit(33,"猕猴桃","猕猴桃真好吃!");
    
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            String user = "root";
            String pwd = "root";
            Connection conn = DriverManager.getConnection(url,user,pwd);
            String sql = "update t_fruit set fname = ?, remark = ? where fid = ?";
    
            PreparedStatement psmt = conn.prepareStatement(sql);
            // 这里的顺序和 sql字符串中的?顺序相同
            psmt.setString(1,fruit.getFanme());
            psmt.setString(2,fruit.getRemark());
            psmt.setInt(3,fruit.getFid());
    
            int count = psmt.executeUpdate();
    
            System.out.println(count > 0 ? "修改成功" : "修改失败!");
    
            psmt.close();
            conn.close();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    更新成功
    JDBC
    JDBC

    4.3 delete删除操作

    package com.test.JDBC;
    
    import java.sql.*;
    
    public class demo_Delete {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            String user = "root";
            String pwd = "root";
            Connection conn = DriverManager.getConnection(url, user, pwd);
            String sql = "delete from t_fruit where fid = ? ";
            PreparedStatement psmt = conn.prepareStatement(sql);
            psmt.setInt(1,35);
            int count = psmt.executeUpdate();
            psmt.close();
            conn.close();
            System.out.println( count > 0 ? "删除成功" : "删除失败" );
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    删除成功
    JDBC
    JDBC

    5. JDBC 对数据库进行查询操作

    5.1 列表

    package com.test.JDBC;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * JDBC - 查询所有的库存
     */
    public class demo_Select {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            //1.添加jar
            //2.加载驱动 Driver
            Class.forName("com.mysql.cj.jdbc.Driver");
            //3. 通过驱动管理器获取连接对象 DriverManager是类,其他的都是接口
            //3-1 准备url ‘jdbc:mysql://’ 固定写法
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            //3-2准备用户名
            String user = "root";
            //3-3准备密码
            String pwd = "root";
            Connection conn = DriverManager.getConnection(url, user, pwd);
            //4. 编写SQL语句
            String sql = "SELECT * from t_fruit";
            //5. 创建预处理命令对象
            PreparedStatement preparedStatement = conn.prepareStatement(sql);
            //6. 执行查询,返回结果集
            ResultSet rs = preparedStatement.executeQuery();
            //7. 解析结果集
            List<Fruit> fruitList = new ArrayList<>();
            while(rs.next()){ //rs.next 一行一行判断,如果行内有数据则返回true,否则返回false
    
                //1表示读取当前行的第一列的数据
                //getInt,因为这一列是int类型,所以是用getInt
                //getInt(结果集的列名)
                //int fid = rs.getInt("fid")
                int fid = rs.getInt(1);
                String fname = rs.getString("fname");
                int price = rs.getInt("price");
                int fcount = rs.getInt("fcount");
                String remark = rs.getString("remark");
    
                Fruit fruit = new Fruit(fid,fname,price,fcount,remark);
                fruitList.add(fruit);
            }
            //8.释放资源
            rs.close();
            preparedStatement.close();
            conn.close();
    
            fruitList.forEach(System.out::println);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    查询成功
    JDBC

    5.2 单个对象

    package com.test.JDBC;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class demo_SelectOne {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            //1.添加jar
            //2.加载驱动 Driver
            Class.forName("com.mysql.cj.jdbc.Driver");
            //3. 通过驱动管理器获取连接对象 DriverManager是类,其他的都是接口
            //3-1 准备url ‘jdbc:mysql://ip:port/dbname?参数列表’ 固定写法
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            //3-2准备用户名
            String user = "root";
            //3-3准备密码
            String pwd = "root";
            Connection conn = DriverManager.getConnection(url, user, pwd);
            //4. 编写SQL语句
            String sql = "SELECT * from t_fruit where fid = ?";
            //5. 创建预处理命令对象
            PreparedStatement psmt = conn.prepareStatement(sql);
            //6. 填充参数
            psmt.setInt(1,33);
            //7. 执行查询,返回结果集
            ResultSet rs = psmt.executeQuery();
            //8. 解析结果集
            if(rs.next()){ //rs.next 一行一行判断,如果行内有数据则返回true,否则返回false
                //1表示读取当前行的第一列的数据
                //getInt,因为这一列是int类型,所以是用getInt
                //getInt(结果集的列名)
                //int fid = rs.getInt("fid")
                int fid = rs.getInt(1);
                String fname = rs.getString("fname");
                int price = rs.getInt("price");
                int fcount = rs.getInt("fcount");
                String remark = rs.getString("remark");
    
                Fruit fruit = new Fruit(fid,fname,price,fcount,remark);
                System.out.println(fruit);
            }
            //9.释放资源
            rs.close();
            psmt.close();
            conn.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    查询成功
    JDBC

    5.3 查询总记录条数

    package com.test.JDBC;
    
    import java.sql.*;
    
    /**
     * JDBC -总记录条数
     */
    public class demo_SelectOne {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            //1.添加jar
            //2.加载驱动 Driver
            Class.forName("com.mysql.cj.jdbc.Driver");
            //3. 通过驱动管理器获取连接对象 DriverManager是类,其他的都是接口
            //3-1 准备url ‘jdbc:mysql://ip:port/dbname?参数列表’ 固定写法
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            //3-2准备用户名
            String user = "root";
            //3-3准备密码
            String pwd = "root";
            Connection conn = DriverManager.getConnection(url, user, pwd);
            //4. 编写SQL语句
            String sql = "SELECT count(*) from t_fruit";
            //5. 创建预处理命令对象
            PreparedStatement psmt = conn.prepareStatement(sql);
            //6. 执行查询,返回结果集
            ResultSet rs = psmt.executeQuery();
            //7. 解析结果集
            if(rs.next()){ //rs.next 一行一行判断,如果行内有数据则返回true,否则返回false
                int count = rs.getInt(1);
                System.out.println("总记录条数:"+count);
            }
            //8.释放资源
            rs.close();
            psmt.close();
            conn.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    查询成功
    JDBC

    6. 项目实战 - 水果库存系统

    6.1 项目说明

    一、
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:1
    ----------------------------------------------
    FID       名称       单价        库存        备注  
    1         苹果       5          100     苹果很好吃
    2         西瓜       3          55      西瓜很好吃
    3         榴莲       15         99   榴莲是一种神奇的水果
    ----------------------------------------------
    
    或者
    
    ----------------------------------------------
    FID       名称       单价        库存        备注 
    对不起,库存为空!
    ----------------------------------------------
    *****************************************************************************************************
    
    二、
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:1
    ----------------------------------------------
    FID       名称       单价        库存        备注  
    1         苹果       5          100     苹果很好吃
    2         西瓜       3          55      西瓜很好吃
    3         榴莲       15         99   榴莲是一种神奇的水果
    ----------------------------------------------
    
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:2
    请输入水果名称:苹果
    请输入添加的库存量:30
    添加成功!
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:1
    ----------------------------------------------
    FID       名称       单价        库存        备注  
    1         苹果       5          130     苹果很好吃
    2         西瓜       3          55      西瓜很好吃
    3         榴莲       15         99   榴莲是一种神奇的水果
    ----------------------------------------------
    
    或者
    
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:2
    请输入水果名称:番茄
    请输入水果单价:6
    请输入添加的库存量:90
    请输入水果备注:番茄也是水果
    添加成功!
    *****************************************************************************************************
    
    三、
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:1
    ----------------------------------------------
    FID       名称       单价        库存        备注  
    1         苹果       5          100     苹果很好吃
    2         西瓜       3          55      西瓜很好吃
    3         榴莲       15         99   榴莲是一种神奇的水果
    4         番茄       6          90   番茄也是水果
    ----------------------------------------------
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:3
    请输入水果名称: 菠萝蜜
    对不起,没有找到指定的水果库存记录!
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:3
    请输入水果名称:西瓜
    ----------------------------------------------
    FID       名称       单价        库存        备注  
    2         西瓜       3          55      西瓜很好吃
    ----------------------------------------------
    *****************************************************************************************************
    
    四、
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:4
    请输入水果名称: 菠萝蜜
    对不起,没有找到需要下架的水果库存记录!
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择:4
    请输入水果名称: 苹果
    是否确认下架?(Y/N)Y
    下架成功!
    *****************************************************************************************************
    
    五、
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择: 1
    ----------------------------------------------
    FID       名称       单价        库存        备注  
    2         西瓜       3          55      西瓜很好吃
    3         榴莲       15         99   榴莲是一种神奇的水果
    4         番茄       6          90   番茄也是水果
    ----------------------------------------------
    ===============欢迎使用水果库存列表===============
    1.查看水果库存列表
    2.添加水果库存信息
    3.查看特定水果库存信息
    4.水果下架
    5.退出
    ==============================================
    请选择: 5
    是否确认退出?(Y/N) Y
    谢谢使用!再见!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173

    6.2 DAO的概念和角色(水果库存系统项目设计理念):

    DAO(Data Access Object)称之为数据访问对象,其中的方法都是单精度方法。

    JDBC

    6.2.1 单精度

      单精度指的是这个方法的粒度不能再分了,已经非常细了(因此也称之为细粒度)一个方法只考虑一个功能,查询就是查询,添加就是添加。

    6.3 创建新项目 JDBC_Fruit

    JDBC

    6.4 添加jar包

    类似刚才给子项目JDBC添加jar包方式相同:

    JDBC

    6.5 文件结构

    包名一般以 公司名.项目名.模块名 命名 ,例如 com.test.jdbcFruit

    JDBC

    6.6 创建实体类 class

    package com.test.jdbcFruit.pojo;
    
    //水果类
    public class Fruit {
        private Integer fid;
        private String fname;
        private Integer price;
        private Integer fcount;
        private String remark;
    
        public Fruit() {
        }
    
        public Fruit(Integer fid, String fname, Integer price, Integer fcount, String remark) {
            this.fid = fid;
            this.fname = fname;
            this.price = price;
            this.fcount = fcount;
            this.remark = remark;
        }
    
        public Integer getFid() {
            return fid;
        }
    
        public void setFid(Integer fid) {
            this.fid = fid;
        }
    
        public String getFname() {
            return fname;
        }
    
        public void setFname(String fname) {
            this.fname = fname;
        }
    
        public Integer getPrice() {
            return price;
        }
    
        public void setPrice(Integer price) {
            this.price = price;
        }
    
        public Integer getFcount() {
            return fcount;
        }
    
        public void setFcount(Integer fcount) {
            this.fcount = fcount;
        }
    
        public String getRemark() {
            return remark;
        }
    
        public void setRemark(String remark) {
            this.remark = remark;
        }
    
        @Override
        public String toString() {
            return  fid + "\t\t" +
                    fname + "\t\t" +
                    price + "\t\t" +
                    fcount + "\t\t" +
                    remark + "\t\t" ;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    注意:需要toString方法,因为在调用System.out.println(fruit) 时,源码是在调用:

    JDBC
    .valueOf()方法是会调用toString()方法的:

    JDBC

    6.7 编写 Menu

    package com.test.jdbcFruit.controller;
    
    import com.test.jdbcFruit.dao.FruitDAO;
    import com.test.jdbcFruit.dao.impl.FruitDAOImpl;
    import com.test.jdbcFruit.pojo.Fruit;
    
    import java.util.List;
    import java.util.Scanner;
    
    //菜单类
    public class Menu {
    
        Scanner input = new Scanner(System.in);
        FruitDAO fruitDAO = new FruitDAOImpl();
    
        //显示主菜单
        public int showMainMenu(){
    
            System.out.println("===============欢迎使用水果库存列表===============");
            System.out.println("1.查看水果库存列表");
            System.out.println("2.添加水果库存信息");
            System.out.println("3.查看特定水果库存信息");
            System.out.println("4.水果下架");
            System.out.println("5.退出");
            System.out.println("==============================================");
            System.out.print("请选择:");
    
            int slt = input.nextInt();
            //System.out.println("你的选择是:"+slt);
    
            return slt;
        }
    
    
        //查看水果库存列表
        public void showFruitList(){
            List<Fruit> fruitList = fruitDAO.getFruitList();
            System.out.println("----------------------------------------------");
            System.out.println("FID\t\t名称\t\t单价\t\t库存\t\t备注");
            if (fruitList==null || fruitList.size()<=0){
                System.out.println("对不起库存为空!");
            }else{
                for (int i = 0;i<fruitList.size();i++){
                    Fruit fruit = fruitList.get(i);
                    System.out.println(fruit);
                }
            }
            System.out.println("----------------------------------------------");
        }
    
        //添加水果库存信息 -- 业务方法:添加库存记录
        public void addFruit(){
            System.out.print("请输入水果名称:");
            String fname = input.next();
            Fruit fruit = fruitDAO.getFruitByname(fname);
            if (fruit==null){
                System.out.print("请输入水果单价:");
                int price = input.nextInt();
                System.out.print("请输入水果库存量:");
                int fcount = input.nextInt();
                System.out.print("请输入水果备注:");
                String remark = input.next();
                //封装成一个新的fruit对象
                fruit = new Fruit(0,fname,price,fcount,remark);
                //调用DAO的添加方法
                fruitDAO.addFruit(fruit);
            }else{
                //说明库存中有这个名称的水果 - 修改
                System.out.print("请输入追加的库存量:");
                int fcount = input.nextInt();
                fruit.setFcount(fruit.getFcount()+fcount);
                //调用DAO的修改方法
                fruitDAO.updateFruit(fruit);
            }
            System.out.println("添加成功!");
        }
    
        //查看指定水果库存信息
        public void showFruitInfo(){
            System.out.println("请输入水果名称:");
            String fname = input.next();
            Fruit fruit = fruitDAO.getFruitByname(fname);
            if (fruit==null){
                System.out.println("对不起,没有找到指定的水果库存记录!");
            }else{
                System.out.println("----------------------------------------------");
                System.out.println("FID\t\t名称\t\t单价\t\t库存\t\t备注");
                System.out.println(fruit);
                System.out.println("----------------------------------------------");
            }
        }
    
        //水果下架
        public void deleteFruit(){
            System.out.print("请输入水果名称");
            String fname = input.next();
            Fruit fruit = fruitDAO.getFruitByname(fname);
            if (fruit==null){
                System.out.println("对不起,没有找到需要下载的水果信息!");
            }else{
                System.out.print("是否确认下载?(Y/N)");
                String slt = input.next();
                if ("y".equalsIgnoreCase(slt)){
                    fruitDAO.delFruit(fname);
                    System.out.println("下架成功!");
                }
            }
        }
    
        //退出
        public boolean exit(){
            System.out.print("是否确认退出?(Y/N)");
            String slt = input.next();
            return !"Y".equalsIgnoreCase(slt);//忽略大小写
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117

    6.8 编写 Client (运行文件)

    package com.test.jdbcFruit.view;
    
    import com.test.jdbcFruit.controller.Menu;
    
    public class Client {
        public static void main(String[] args) {
            Menu m = new Menu();
    
            boolean flag = true;
            while(flag){
                //调用显示主菜单的方法
                int slt = m.showMainMenu();
                switch(slt){
                    case 1:
                        //显示所有库存记录
                        m.showFruitList();
                        break;
                    case 2:
                        //添加水果库存信息
                        m.addFruit();
                        break;
                    case 3:
                        //查看特定水果库存信息
                        m.showFruitInfo();
                        break;
                    case 4:
                        //水果下架
                        m.deleteFruit();
                        break;
                    case 5:
                        //退出
                        flag = m.exit();
                        break;
                    default:
                        System.out.println("输入有误!");
                        break;
                }
            }
            System.out.println("谢谢使用!再见!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    6.9 编写DAO(Data Access Object)

    package com.test.jdbcFruit.dao.impl;
    
    import com.test.jdbcFruit.dao.FruitDAO;
    import com.test.jdbcFruit.pojo.Fruit;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class FruitDAOImpl implements FruitDAO {
    
        final String DRIVER = "com.mysql.cj.jdbc.Driver";
        String URL = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
        final String USER = "root";
        final String PWD = "root";
        Connection conn;
        PreparedStatement psmt;
        ResultSet rs;
    
        @Override
        public List<Fruit> getFruitList() {
            List<Fruit> fruitList = new ArrayList<>();
    
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL, USER, PWD);
                //3. 编写SQL语句
                String sql = "select * from t_fruit";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 执行查询
                rs = psmt.executeQuery();
                //6. 解析rs
                while (rs.next()) {
                    int fid = rs.getInt(1);
                    String fname = rs.getString(2);
                    int price = rs.getInt(3);
                    int fcount = rs.getInt(4);
                    String remark = rs.getString(5);
    
                    Fruit fruit = new Fruit(fid, fname, price, fcount, remark);
                    fruitList.add(fruit);
                }
    
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return fruitList;
        }
    
        @Override
        public boolean addFruit(Fruit fruit) {
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL, USER, PWD);
                //3. 编写SQL语句
                String sql = "insert into t_fruit values(0,?,?,?,?)";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setString(1, fruit.getFname());
                psmt.setInt(2, fruit.getPrice());
                psmt.setInt(3, fruit.getFcount());
                psmt.setString(4, fruit.getRemark());
                //6 执行更新(增删改),返回影响行数
                return psmt.executeUpdate() > 0;
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    
        @Override
        public boolean updateFruit(Fruit fruit) {
    
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL,USER,PWD);
                //3. 编写SQL语句
                String sql = "update t_fruit set fcount =? where fid = ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setInt(1,fruit.getFcount());
                psmt.setInt(2,fruit.getFid());
                //6 执行更新(增删改),返回影响行数
                return psmt.executeUpdate() > 0;
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    
        @Override
        public Fruit getFruitByname(String fname) {
            try{
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL, USER, PWD);
                //3. 编写SQL语句
                String sql = "select * from t_fruit where fname like ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setString(1,fname);
                //6 执行更新(增删改),返回影响行数
                rs = psmt.executeQuery();
                //7. 解析rs
                if (rs.next()){
                    int fid = rs.getInt(1);
                    int price = rs.getInt(3);
                    int fcount = rs.getInt(4);
                    String remark = rs.getString(5);
                    return new Fruit(fid,fname,price,fcount,remark);
                }
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    
        @Override
        public boolean delFruit(String fname) {
    
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL,USER,PWD);
                //3. 编写SQL语句
                String sql = "delete from t_fruit where fname like ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                psmt.setString(1,fname);
                return psmt.executeUpdate() > 0;
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213

    6.10 功能说明 (运行 Clenit.class)

    //客户端
    package com.test.jdbcFruit.view;
    
    import com.test.jdbcFruit.controller.Menu;
    
    public class Client {
        public static void main(String[] args) {
            Menu m = new Menu();
    
            boolean flag = true;
            while(flag){
                //调用显示主菜单的方法
                int slt = m.showMainMenu();
                switch(slt){
                    case 1:
                        //显示所有库存记录
                        m.showFruitList();
                        break;
                    case 2:
                        //添加水果库存信息
                        m.addFruit();
                        break;
                    case 3:
                        //查看特定水果库存信息
                        m.showFruitInfo();
                        break;
                    case 4:
                        //水果下架
                        m.deleteFruit();
                        break;
                    case 5:
                        //退出
                        flag = m.exit();
                        break;
                    default:
                        System.out.println("输入有误!");
                        break;
                }
            }
            System.out.println("谢谢使用!再见!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    6.10.0 程序开始时

    进入选择菜单,输入对应序号开始运行各个功能

    //调用showMainMenu()方法 输出显示主菜单
    public int showMainMenu(){
        System.out.println("===============欢迎使用水果库存列表===============");
        System.out.println("1.查看水果库存列表");
        System.out.println("2.添加水果库存信息");
        System.out.println("3.查看特定水果库存信息");
        System.out.println("4.水果下架");
        System.out.println("5.退出");
        System.out.println("==============================================");
        System.out.print("请选择:");
        int slt = input.nextInt(); //输入序号
        //System.out.println("你的选择是:"+slt);
        return slt;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    6.10.1 显示库存列表

    1 进入 显示库存列表 功能,调用 MenushowFruitList() 方法

    //查看水果库存列表
        public void showFruitList(){
            List<Fruit> fruitList = fruitDAO.getFruitList();
            System.out.println("----------------------------------------------");
            System.out.println("FID\t\t名称\t\t单价\t\t库存\t\t备注");
            if (fruitList==null || fruitList.size()<=0){
                System.out.println("对不起库存为空!");
            }else{
                for (int i = 0;i<fruitList.size();i++){
                    Fruit fruit = fruitList.get(i);
                    System.out.println(fruit);
                }
            }
            System.out.println("----------------------------------------------");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    随后该方法,继续调用fruitDAO.getFruitList()方法

     @Override
        public List<Fruit> getFruitList() {
            List<Fruit> fruitList = new ArrayList<>();
    
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL, USER, PWD);
                //3. 编写SQL语句
                String sql = "select * from t_fruit";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 执行查询
                rs = psmt.executeQuery();
                //6. 解析rs
                while (rs.next()) {
                    int fid = rs.getInt(1);
                    String fname = rs.getString(2);
                    int price = rs.getInt(3);
                    int fcount = rs.getInt(4);
                    String remark = rs.getString(5);
    
                    Fruit fruit = new Fruit(fid, fname, price, fcount, remark);
                    fruitList.add(fruit);
                }
    
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return fruitList;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    返回数据
    JDBC

    6.10.2 添加水果库存信息

    2 进入 添加水果库存信息 功能,调用 MenuaddFruit() 方法

    //添加水果库存信息 -- 业务方法:添加库存记录
        public void addFruit(){
            System.out.print("请输入水果名称:");
            String fname = input.next();
            Fruit fruit = fruitDAO.getFruitByname(fname);
            if (fruit==null){
                System.out.print("请输入水果单价:");
                int price = input.nextInt();
                System.out.print("请输入水果库存量:");
                int fcount = input.nextInt();
                System.out.print("请输入水果备注:");
                String remark = input.next();
                //封装成一个新的fruit对象
                fruit = new Fruit(0,fname,price,fcount,remark);
                //调用DAO的添加方法
                fruitDAO.addFruit(fruit);
            }else{
                //说明库存中有这个名称的水果 - 修改
                System.out.print("请输入追加的库存量:");
                int fcount = input.nextInt();
                fruit.setFcount(fruit.getFcount()+fcount);
                //调用DAO的修改方法
                fruitDAO.updateFruit(fruit);
            }
            System.out.println("添加成功!");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    随后该方法,继续调用fruitDAO.getFruitByname(fname)方法,判断数据库是否存在当前的水果相关信息

    @Override
        public Fruit getFruitByname(String fname) {
            try{
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL, USER, PWD);
                //3. 编写SQL语句
                String sql = "select * from t_fruit where fname like ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setString(1,fname);
                //6 执行更新(增删改),返回影响行数
                rs = psmt.executeQuery();
                //7. 解析rs
                if (rs.next()){
                    int fid = rs.getInt(1);
                    int price = rs.getInt(3);
                    int fcount = rs.getInt(4);
                    String remark = rs.getString(5);
                    return new Fruit(fid,fname,price,fcount,remark);
                }
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    如果不存在,则输入相关信息,并调用fruitDAO.addFruit(fruit) 进行添加

    //添加的水果不存在数据库中
    @Override
        public boolean addFruit(Fruit fruit) {
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL, USER, PWD);
                //3. 编写SQL语句
                String sql = "insert into t_fruit values(0,?,?,?,?)";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setString(1, fruit.getFname());
                psmt.setInt(2, fruit.getPrice());
                psmt.setInt(3, fruit.getFcount());
                psmt.setString(4, fruit.getRemark());
                //6 执行更新(增删改),返回影响行数
                return psmt.executeUpdate() > 0;
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    返回数据
    JDBC
    JDBC

    如果存在,则输入追加数量,并调用fruitDAO.updateFruit(fruit)进行信息更新

    //添加的水果数据库已经存储相关信息
    @Override
        public boolean updateFruit(Fruit fruit) {
    
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL,USER,PWD);
                //3. 编写SQL语句
                String sql = "update t_fruit set fcount =? where fid = ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setInt(1,fruit.getFcount());
                psmt.setInt(2,fruit.getFid());
                //6 执行更新(增删改),返回影响行数
                return psmt.executeUpdate() > 0;
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    JDBC
    JDBC

    6.10.3 查看特定水果库存信息

    3 进入 查看特定水果库存信息 功能,调用 Menu 类的showFruitInfo() 方法

     //查看指定水果库存信息
        public void showFruitInfo(){
            System.out.println("请输入水果名称:");
            String fname = input.next();
            Fruit fruit = fruitDAO.getFruitByname(fname);
            if (fruit==null){
                System.out.println("对不起,没有找到指定的水果库存记录!");
            }else{
                System.out.println("----------------------------------------------");
                System.out.println("FID\t\t名称\t\t单价\t\t库存\t\t备注");
                System.out.println(fruit);
                System.out.println("----------------------------------------------");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    随后该方法,继续调用fruitDAO.getFruitByname(fname)方法,判断数据库是否存在当前的水果相关信息,并输出查询结果

    @Override
    public Fruit getFruitByname(String fname) {
        try{
            //1. 加载驱动
            Class.forName(DRIVER);
            //2. 通过驱动管理获取连接对象
            conn = DriverManager.getConnection(URL, USER, PWD);
            //3. 编写SQL语句
            String sql = "select * from t_fruit where fname like ?";
            //4. 创建预处理命令对象
            psmt = conn.prepareStatement(sql);
            //5. 填充参数
            psmt.setString(1,fname);
            //6 执行更新(增删改),返回影响行数
            rs = psmt.executeQuery();
            //7. 解析rs
            if (rs.next()){
                int fid = rs.getInt(1);
                int price = rs.getInt(3);
                int fcount = rs.getInt(4);
                String remark = rs.getString(5);
                return new Fruit(fid,fname,price,fcount,remark);
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (psmt != null) {
                    psmt.close();
                }
                if (conn != null && !conn.isClosed()) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    存在水果数据:
    JDBC
    不存在水果数据:
    JDBC

    6.10.4 水果下架

    4 进入 水果下架 功能,调用 Menu 类的deleteFruit() 方法

    //水果下架
        public void deleteFruit(){
            System.out.print("请输入水果名称");
            String fname = input.next();
            Fruit fruit = fruitDAO.getFruitByname(fname);
            if (fruit==null){
                System.out.println("对不起,没有找到需要下载的水果信息!");
            }else{
                System.out.print("是否确认下载?(Y/N)");
                String slt = input.next();
                if ("y".equalsIgnoreCase(slt)){
                    fruitDAO.delFruit(fname);
                    System.out.println("下架成功!");
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    随后该方法,继续调用fruitDAO.getFruitByname(fname)方法,判断数据库是否存在当前的水果相关信息,没有就不用下架,有再次确认是否下架,确定下架后继续调用fruitDAO.delFruit(fname)方法,下架该商品

    @Override
        public boolean delFruit(String fname) {
    
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                conn = DriverManager.getConnection(URL,USER,PWD);
                //3. 编写SQL语句
                String sql = "delete from t_fruit where fname like ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                psmt.setString(1,fname);
                return psmt.executeUpdate() > 0;
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    if (psmt != null) {
                        psmt.close();
                    }
                    if (conn != null && !conn.isClosed()) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    返回数据
    JDBC
    JDBC

    如果没有该水果
    JDBC

    6.10.5 退出

    5 进入 退出 ,调用 Menu 类的exit() 方法,不用再调用DAO借口了,不需要操作数据库

    //退出
        public boolean exit(){
            System.out.print("是否确认退出?(Y/N)");
            String slt = input.next();
            return !"Y".equalsIgnoreCase(slt);//忽略大小写
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    返回数据

    JDBC

    7. JDBC 项目实战优化

    7.1 创建新项目 JDBC_Fruit2.0

    JDBC

    7.1.1 对JDBC_Fruit2.0中的获取连接操作以及释放连接操作做了提取
     //统一将链接数据库放到方法外面,让所有方法都能使用
        final String DRIVER = "com.mysql.cj.jdbc.Driver";
        String URL = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
        final String USER = "root";
        final String PWD = "root";
    
        Connection conn;
        PreparedStatement psmt;
        ResultSet rs;
    
        private Connection getConn(){
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                return DriverManager.getConnection(URL, USER, PWD);
            }catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private void close(ResultSet rs,PreparedStatement psmt,Connection conn){
            try {
                if (rs != null) {
                    rs.close();
                }
                if (psmt != null) {
                    psmt.close();
                }
                if (conn != null && !conn.isClosed()) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    修改FruitDAOImpl后全部代码

    package com.test.jdbcFruit.dao.impl;
    
    import com.test.jdbcFruit.dao.FruitDAO;
    import com.test.jdbcFruit.pojo.Fruit;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class FruitDAOImpl implements FruitDAO {
    
        final String DRIVER = "com.mysql.cj.jdbc.Driver";
        String URL = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
        final String USER = "root";
        final String PWD = "root";
    
        Connection conn;
        PreparedStatement psmt;
        ResultSet rs;
    
        private Connection getConn(){
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                return DriverManager.getConnection(URL, USER, PWD);
            }catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private void close(ResultSet rs,PreparedStatement psmt,Connection conn){
            try {
                if (rs != null) {
                    rs.close();
                }
                if (psmt != null) {
                    psmt.close();
                }
                if (conn != null && !conn.isClosed()) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public List<Fruit> getFruitList() {
            List<Fruit> fruitList = new ArrayList<>();
            try {
                //2.获取连接
                conn = getConn();
                //3. 编写SQL语句
                String sql = "select * from t_fruit";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 执行查询
                rs = psmt.executeQuery();
                //6. 解析rs
                while (rs.next()) {
                    int fid = rs.getInt(1);
                    String fname = rs.getString(2);
                    int price = rs.getInt(3);
                    int fcount = rs.getInt(4);
                    String remark = rs.getString(5);
    
                    Fruit fruit = new Fruit(fid, fname, price, fcount, remark);
                    fruitList.add(fruit);
                }
    
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
               close(rs,psmt,conn);
            }
            return fruitList;
        }
    
        @Override
        public boolean addFruit(Fruit fruit) {
            try {
                //2.获取连接对象
                conn = getConn();
                //3. 编写SQL语句
                String sql = "insert into t_fruit values(0,?,?,?,?)";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setString(1, fruit.getFname());
                psmt.setInt(2, fruit.getPrice());
                psmt.setInt(3, fruit.getFcount());
                psmt.setString(4, fruit.getRemark());
                //6 执行更新(增删改),返回影响行数
                return psmt.executeUpdate() > 0;
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                close(rs,psmt,conn);
            }
            return false;
        }
    
        @Override
        public boolean updateFruit(Fruit fruit) {
            try {
                //2.获取连接对象
                conn = getConn();
                //3. 编写SQL语句
                String sql = "update t_fruit set fcount =? where fid = ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setInt(1,fruit.getFcount());
                psmt.setInt(2,fruit.getFid());
                //6 执行更新(增删改),返回影响行数
                return psmt.executeUpdate() > 0;
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
              close(rs,psmt,conn);
            }
            return false;
        }
    
        @Override
        public Fruit getFruitByname(String fname) {
            try{
                //2. 获取连接对象
                conn = getConn();
                //3. 编写SQL语句
                String sql = "select * from t_fruit where fname like ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setString(1,fname);
                //6 执行更新(增删改),返回影响行数
                rs = psmt.executeQuery();
                //7. 解析rs
                if (rs.next()){
                    int fid = rs.getInt(1);
                    int price = rs.getInt(3);
                    int fcount = rs.getInt(4);
                    String remark = rs.getString(5);
                    return new Fruit(fid,fname,price,fcount,remark);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
               close(rs,psmt,conn);
            }
            return null;
        }
    
        @Override
        public boolean delFruit(String fname) {
            try {
                //2. 获取连接对象
                conn = getConn();
                //3. 编写SQL语句
                String sql = "delete from t_fruit where fname like ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                psmt.setString(1,fname);
                return psmt.executeUpdate() > 0;
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
               close(rs,psmt,conn);
            }
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174

    7.2 创建新项目 JDBC_Fruit3.0

    JDBC

    7.2.1 方法总结:

    addFruit:

    1. 获取连接
    2. 编写sql: insert
    3. psmt
    4. 填充参数: 4个参数
    5. 执行更新
    6. 释放资源

    updateFruit:

    1. 获取连接
    2. 编写sql: update
    3. psmt
    4. 填充参数: 2个参数
    5. 执行更新
    6. 释放资源

    各个方法存在大量重复操作,并且各方法之间也就 SQL语句不一样,传入SQL语句的参数不一样!需要继续修改

    7.2.2 创建了BaseDAO,去除了冗余的FruitDAOImpl代码。

    上一步,虽然将数据库连接相关代码做了整合减少了个方法中的代码,但是还存在相关代码的重复:

    //依旧存在代码重复
    //2.获取连接
    conn = getConn();
    //3. 编写SQL语句
    String sql = "select * from t_fruit";
    //4. 创建预处理命令对象
    psmt = conn.prepareStatement(sql);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    另外上一步中虽然做了数据库整合,但是数据库访问表都是写死了,可能还存在用户表、部门表等其他表,需要继续做提取

    创建了BaseDAO 继续抽取统一方法

    package com.test.jdbcFruit.dao.base;
    
    import java.sql.*;
    
    public abstract class BaseDAO {  //不允许 New 允许继承、
    
        public final String DRIVER = "com.mysql.cj.jdbc.Driver";
        public final String URL = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
        public final String USER = "root";
        public final String PWD = "root";
    
        protected Connection conn;
        protected PreparedStatement psmt;
        protected ResultSet rs;
    
        protected Connection getConn(){
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //1-1.通过驱动管理获取连接对象
                return DriverManager.getConnection(URL, USER, PWD);
            }catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        protected void close(ResultSet rs, PreparedStatement psmt, Connection conn){
            try {
                if (rs != null) {
                    rs.close();
                }
                if (psmt != null) {
                    psmt.close();
                }
                if (conn != null && !conn.isClosed()) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
        //执行更新,返回影响行数
        protected int executeUpdate(String sql,Object...params){
            try{
                conn = getConn();
                psmt = conn.prepareStatement(sql);
                if (params != null && params.length >0){
                    for (int i = 0; i < params.length; i++) {
                        psmt.setObject(i+1,params[i]);
                    }
                }
                return psmt.executeUpdate();
            }catch (SQLException e){
                e.printStackTrace();
            }finally {
                close(rs,psmt,conn);
            }
            return 0;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    修改后的FruitDAOImpl继承BaseDAO (查询操作没有改,放到了下部分叙述)

    package com.test.jdbcFruit.dao.impl;
    
    import com.test.jdbcFruit.dao.FruitDAO;
    import com.test.jdbcFruit.dao.base.BaseDAO;
    import com.test.jdbcFruit.pojo.Fruit;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class FruitDAOImpl extends BaseDAO implements FruitDAO {
    
        @Override
        public List<Fruit> getFruitList() {
            List<Fruit> fruitList = new ArrayList<>();
            try {
                //2.获取连接
                conn = getConn();
                //3. 编写SQL语句
                String sql = "select * from t_fruit";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 执行查询
                rs = psmt.executeQuery();
                //6. 解析rs
                while (rs.next()) {
                    int fid = rs.getInt(1);
                    String fname = rs.getString(2);
                    int price = rs.getInt(3);
                    int fcount = rs.getInt(4);
                    String remark = rs.getString(5);
    
                    Fruit fruit = new Fruit(fid, fname, price, fcount, remark);
                    fruitList.add(fruit);
                }
    
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
               close(rs,psmt,conn);
            }
            return fruitList;
        }
    
        @Override
        public boolean addFruit(Fruit fruit) {
            String sql = "insert into t_fruit values(0,?,?,?,?)";
            return super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark())>0;
        }
    
        @Override
        public boolean updateFruit(Fruit fruit) {
            String sql = "update t_fruit set fcount =? where fid = ?";
            return super.executeUpdate(sql,fruit.getFcount(),fruit.getFid())>0;
        }
    
        @Override
        public Fruit getFruitByname(String fname) {
            try{
                //2. 获取连接对象
                conn = getConn();
                //3. 编写SQL语句
                String sql = "select * from t_fruit where fname like ?";
                //4. 创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //5. 填充参数
                psmt.setString(1,fname);
                //6 执行更新(增删改),返回影响行数
                rs = psmt.executeQuery();
                //7. 解析rs
                if (rs.next()){
                    int fid = rs.getInt(1);
                    int price = rs.getInt(3);
                    int fcount = rs.getInt(4);
                    String remark = rs.getString(5);
                    return new Fruit(fid,fname,price,fcount,remark);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
               close(rs,psmt,conn);
            }
            return null;
        }
    
        @Override
        public boolean delFruit(String fname) {
            String sql = "delete from t_fruit where fname like ?";
            return super.executeUpdate(sql, fname) > 0;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    7.3 创建新项目 JDBC_Fruit4.0

    JDBC

    7.3.1 抽取通用的操作方法

    修改BaseDAO 增加泛型将代码普适化

    package com.test.jdbcFruit.dao.base;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public abstract class BaseDAO<T> {  //不允许 New 允许继承、
    
        public final String DRIVER = "com.mysql.cj.jdbc.Driver";
        public final String URL = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
        public final String USER = "root";
        public final String PWD = "root";
    
        protected Connection conn;
        protected PreparedStatement psmt;
        protected ResultSet rs;
    
        //T的Class对象
        private Class entityClass;
    
        public BaseDAO(){
            //getClass() 获取class对象,当前我们执行的是new FruitDAOImpl(),创建的是FruitDAOImpl的实例
            //那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
            //因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
            //所以getGenericSuperclass()获取到的是BaseDAO的Class
            Type genericType = getClass().getGenericSuperclass();//getGenericSuperclass()获取Type类型 BaseDAO
            //ParameterizedType 参数化类型 BaseDAO, T,A,B,C,D 就是参数化类型
            Type[] actualTypeArgument = ((ParameterizedType)genericType).getActualTypeArguments();
            //获取到的中的T的真实的类型
            Type actualType = actualTypeArgument[0];
            //System.out.println(actualType.getTypeName());//类型的名称
            try {
                entityClass = Class.forName(actualType.getTypeName());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        protected Connection getConn(){
            try {
                //1. 加载驱动
                Class.forName(DRIVER);
                //2. 通过驱动管理获取连接对象
                return DriverManager.getConnection(URL, USER, PWD);
            }catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        protected void close(ResultSet rs, PreparedStatement psmt, Connection conn){
            try {
                if (rs != null) {
                    rs.close();
                }
                if (psmt != null) {
                    psmt.close();
                }
                if (conn != null && !conn.isClosed()) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
    
        //给预处理命令对象设置参数
        private void setParams(PreparedStatement psmt,Object... params) throws SQLException{
            if (params != null && params.length >0){
                for (int i = 0; i < params.length; i++) {
                    psmt.setObject(i+1,params[i]);
                }
            }
        }
    
        //执行更新,返回影响行数
        protected int executeUpdate(String sql,Object...params){
            try{
                conn = getConn();
                psmt = conn.prepareStatement(sql);
               setParams(psmt,params);
                return psmt.executeUpdate();
            }catch (SQLException e){
                e.printStackTrace();
            }finally {
                close(rs,psmt,conn);
            }
            return 0;
        }
    
        //执行更新,返回影响行数 获取自增列的值
        protected int executeUpdate2(String sql,Object...params){
            boolean isInsertFlag  = false;
            isInsertFlag = sql.trim().toUpperCase().startsWith("INSERT");
            try{
                conn = getConn();
                if (isInsertFlag){
                    psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
                }else {
                    psmt = conn.prepareStatement(sql);
                }
                setParams(psmt,params);
                int count = psmt.executeUpdate();
    
                rs  = psmt.getGeneratedKeys();
                if (rs.next()){
                    return ((Long)rs.getLong(1)).intValue();
                }
    
                return count;
            }catch (SQLException e){
                e.printStackTrace();
            }finally {
                close(rs,psmt,conn);
            }
            return 0;
        }
    
    
        //通过反射技术给obj对象的property属性赋propertyValue值
        private void setValue(Object obj,String property,Object propertyValue){
            Class clazz = obj.getClass();
            try {
                // 获取property这个字符串对应的属性名,比如“fid” 去找obj对象中的fid属性
                Field field = clazz.getDeclaredField(property);
                if (field!=null){
                    field.setAccessible(true);//强制访问
                    field.set(obj,propertyValue);//对象和属性对应
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    
    
        //执行复杂查询,返回例如统计结果 (仅限单表)
        protected  Object[] executeComplexQuery(String sql,Object... params){
            try {
                //获取连接
                conn = getConn();
                //创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //设置参数
                setParams(psmt,params);
                //执行查询
                rs = psmt.executeQuery();
    
                //通过rs可以获取结果集的元数据
                //元数据:描述结果集数据的数据,就是指这个结果集有哪些列,什么类型等等
    
                ResultSetMetaData rsmd = rs.getMetaData();
                //获取结果集的列数
                int columnCount = rsmd.getColumnCount();
                Object[] columValueArr = new Object[columnCount];
                //解析rs
                if(rs.next()) {
                    for (int i = 0; i < columnCount; i++) {
                        Object columValue = rs.getObject(i + 1);  //  33    苹果       5
                        columValueArr[i] = columValue;
                    }
                    return columValueArr;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                close(rs,psmt,conn);
            }
            return null;
        }
    
        //执行查询,返回单个实体对象
        protected T load(String sql,Object...params){
            try {
                //获取连接
                conn = getConn();
                //创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //设置参数
                setParams(psmt,params);
                //执行查询
                rs = psmt.executeQuery();
    
                //通过rs可以获取结果集的元数据
                //元数据:描述结果集数据的数据,就是指这个结果集有哪些列,什么类型等等
                ResultSetMetaData rsmd = rs.getMetaData();
                //获取结果集的列数
                int columnCount = rsmd.getColumnCount();
                //解析rs
                if(rs.next()) {
                    T entity = (T)entityClass.newInstance();
                    for (int i = 0; i < columnCount; i++) {
                        String columnName = rsmd.getColumnName(i+1);         //  fic   fname    price
                        Object columValue = rs.getObject(i + 1);  //  33    苹果       5
                        setValue(entity,columnName,columValue);
                    }
                    return entity;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } finally {
                close(rs,psmt,conn);
            }
            return null;
        }
    
        //执行查询,返回List
        protected List<T> executeQuery(String sql, Object... params){ //List中的T由Base中的T决定
            List<T> list = new ArrayList<>();
            try {
                //获取连接
                conn = getConn();
                //创建预处理命令对象
                psmt = conn.prepareStatement(sql);
                //设置参数
                setParams(psmt,params);
                //执行查询
                rs = psmt.executeQuery();
    
                //通过rs可以获取结果集的元数据
                //元数据:描述结果集数据的数据,就是指这个结果集有哪些列,什么类型等等
                ResultSetMetaData rsmd = rs.getMetaData();
                //获取结果集的列数
                int columnCount = rsmd.getColumnCount();
                //解析rs
                while (rs.next()) {
                    T entity = (T)entityClass.newInstance();
                    for (int i = 0; i < columnCount; i++) {
                        String columnName = rsmd.getColumnName(i+1);  //  fic   fname    price
                        Object columValue = rs.getObject(i + 1);      //  33    苹果       5
                        setValue(entity,columnName,columValue);
                    }
                    list.add(entity);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } finally {
                close(rs,psmt,conn);
            }
            return list;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    7.3.2 说明:
     public BaseDAO(){
            //getClass() 获取class对象,当前我们执行的是new FruitDAOImpl(),创建的是FruitDAOImpl的实例
            //那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
            //因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
            //所以getGenericSuperclass()获取到的是BaseDAO的Class
            Type genericType = getClass().getGenericSuperclass();//getGenericSuperclass()获取Type类型 BaseDAO
            //ParameterizedType 参数化类型 BaseDAO, T,A,B,C,D 就是参数化类型
            Type[] actualTypeArgument = ((ParameterizedType)genericType).getActualTypeArguments();
            //获取到的中的T的真实的类型
            Type actualType = actualTypeArgument[0];
            //System.out.println(actualType.getTypeName());//类型的名称
            try {
                entityClass = Class.forName(actualType.getTypeName());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    JDBC
    输出结果
    JDBC
    修改FruitDAOImpl

    package com.test.jdbcFruit.dao.impl;
    
    import com.test.jdbcFruit.dao.FruitDAO;
    import com.test.jdbcFruit.dao.base.BaseDAO;
    import com.test.jdbcFruit.pojo.Fruit;
    
    import java.util.List;
    
    public class FruitDAOImpl extends BaseDAO<Fruit> implements FruitDAO {
    
        @Override
        public List<Fruit> getFruitList() {
            return super.executeQuery("select * from t_fruit");
        }
    
        @Override
        public boolean addFruit(Fruit fruit) {
            String sql = "insert into t_fruit values(0,?,?,?,?)";
            // 原来return super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark())>0;
            int count = super.executeUpdate2(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark());
            //insert 语句返回的是自增列的值,而不是影响行数
            System.out.println(count);
            return count > 0;
        }
    
        @Override
        public boolean updateFruit(Fruit fruit) {
            String sql = "update t_fruit set fcount =? where fid = ?";
            return super.executeUpdate(sql,fruit.getFcount(),fruit.getFid())>0;
        }
    
        @Override
        public Fruit getFruitByname(String fname) {
           return super.load("select * from t_fruit where fname like ?",fname);
        }
    
        @Override
        public boolean delFruit(String fname) {
            String sql = "delete from t_fruit where fname like ?";
            return super.executeUpdate(sql, fname) > 0;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    获取元数据

    //通过rs可以获取结果集的元数据
    //元数据:描述结果集数据的数据,就是指这个结果集有哪些列,什么类型等等
    ResultSetMetaData rsmd = rs.getMetaData();
    //获取结果集的列数
    int columnCount = rsmd.getColumnCount();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    元数据还有很多其他方法,比如getColumnName()getColumnType()

    JDBC

    8. 添加操作获取自增列主键值

    获取自增长键值

    ---为什么需要获取自增列的值---
    1.下单(结账)
    
    订单表:
    id  订单日期  订单金额   收货人姓名    收货人电话        收货地址
    1 2022/11/2   415        张三       13800138000      地址1
    
    订单详情表
    id    商品ID    商品价格    商品数量    订单ID
    1     1001       12          5       1
    2     1002        5          8       1
    
    
    1-1.insert订单表    --> 返回自增列的值
    1-2.insert订单详情表
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    --- 如何获取 ---
    1. 创建psmt的时候,设置第二个参数
    psmt = conn.prepareedStatement(sql,Statement.RETURN_GENERATED_KEYS)
    2. 执行完更新之后,再去获取结果集,结果集中就包含了自增列的值
    psmt.executeUpdate();
    ResultSet rs  = psmt.getGeneratedKeys();
    Long id = rs.getLong(1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    修改executeUpdate(String sql,Object...params)方法

     //执行更新,返回影响行数 获取自增列的值
        protected int executeUpdate2(String sql,Object...params){
            boolean isInsertFlag  = false;
            //trim()把首尾空格去掉
            //toUpperCase()转换成大写
            //startsWith("INSERT") 以INSERT开头
            isInsertFlag = sql.trim().toUpperCase().startsWith("INSERT");
            try{
                conn = getConn();
                if (isInsertFlag){
                    psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
                }else {
                    psmt = conn.prepareStatement(sql);
                }
                setParams(psmt,params);
                int count = psmt.executeUpdate();
     
                rs  = psmt.getGeneratedKeys();
                if (rs.next()){
                    return ((Long)rs.getLong(1)).intValue();//自增列
                }
    
                return count;
            }catch (SQLException e){
                e.printStackTrace();
            }finally {
                close(rs,psmt,conn);
            }
            return 0;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    FruitDAOImpl方法里修改:

        @Override
        public boolean addFruit(Fruit fruit) {
            String sql = "insert into t_fruit values(0,?,?,?,?)";
            // 原来return super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark())>0;
            int count = super.executeUpdate2(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark());
            //insert 语句返回的是自增列的值,而不是影响行数
            System.out.println(count);
            return count > 0;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    9. 批处理

    psmt.addBatch() //Batch 任务 批处理
    psmt.executeBatch() //执行批处理任务
    psmt.clearBatch() //清空
    
    • 1
    • 2
    • 3
    /**
     * 批处理:
     * 批处理sql
     * 
     * 例如:
     * (1)订单明细表的多条记录的添加
     * (2)批量添加模拟数据
     * ...
     * 
     * 
     * 不同批处理,和用批处理有什么不同
     * 批处理的效率很多
     * 
     * 如何进行批处理操作?
     * (1) 在url中要加一个参数
     * rewriteBatchedStatements = true
     * 那么我们的url就变成 jdbc:mysql://localhost:3306/dbjavalearning?rewriteBatchedStatements=true
     * 这里?,表示?后面的客户端给服务器传的参数,多个参数直接使用&分割
     * (2)调用方法不同
     * psmt。addBatch();
     * int[] all = psmt.executeBatch();
     * 
     * 注意:如果批量添加时,insert使用values,不要使用value;
     */
    
    
    /**
     * 示例
     */
    public class demo_1_Batch {
        public static void main(String[] args) throws Exception {
            
            long start = System.currentTimeMillis();
            //例如:在部门表t_fruit中添加10模拟数据
            //1.添加jar
            //2. 加载驱动 Driver
            Class.forName("com.mysql.jdbc.Driver");
            //3. 通过驱动管理器获取连接对象
            //批处理操作1 :如果要执行批处理任务,需要添加一个参数:rewriteBatchedStatements = true
            //3-1 准备url ‘jdbc:mysql://’ 固定写法
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false&rewriteBatchedStatements=true";
            //3-2准备用户名
            String user = "root";
            //3-3准备密码
            String pwd = "root";
            Connection connection = DriverManager.getConnection(url, user, pwd);
            System.out.println("conn = " + connection);
            //3.编写SQL语句
            // id , fname , price , fcount , remark
            String sql = "insert into t_fruit values(0,?,?,?,?)";
            //4. 创建预处理命令对象
            PreparedStatement psmt = connection.prepareStatement(sql);
            // 5. 填充参数 从1开始
            for (int i = 0; i < 10; i++) {
                psmt.setString(1,"樱桃"+i);
                psmt.setInt(2,35);
                psmt.setInt(3,90);
                psmt.setString(4,"樱桃是一种好吃的水果");
                //批处理操作2:psmt.addBatch();
                psmt.addBatch();//添加到批处理一组操作中,攒一块处理
                if (i%10==0){ //如果任务较多,可以分批次执行,每次执行完,清空任务队列
                    psmt.executeBatch();//执行
                    psmt.clearBatch();//清空
                }
            }
            //6 执行更新(增删改),返回影响行数  批处理操作3
            int[] count = psmt.executeBatch();//防止遗漏
            for (int i = 0; i < count.length; i++) {
                System.out.println(count[i]);
            }
            //7.释放资源(关闭连接)
            // 先关闭psmt 后关闭 connection 顺序不能错!
            psmt.close();
            connection.close();
            
            //计算时间
            long end  = System.currentTimeMillis();
            System.out.println("耗时:"+(end - start)); //耗时
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    10. 数据源连接池

    10.1 为什么需要数据连接池:

      每一次都是用的时候才去使用,先使用10个connection对象,就需要用一个,用完归还即可,提升了效率。

    • 1.响应时间更快
    • 2.对象利用率更高 不是真正断开,只是把状态修改

      我们建立一个连接池,这个池可以容纳一定数量的连接对象,一开始,我们可以腺体用户先创建好一些连接对象,等用户要拿连接对象时,就直接从池中拿,不用新建了,这样也可以节省时间。然后用户用完后,放回去,别人可以接着用。可以提高连接池使用里,当池中现有的连接都用完了,那么连接池可以向服务器申请新的链接放到池中。直到池中的链接达到“最大连接数”,就不能再申请新的连接了,如果没有拿到连接的用户只能等待了。

    10.2 市面上的连接池技术

    • JDBC:JDBC的数据连接池使用javax.sql.DataSource来表示,DataSource只是一个接口(通常被称为数据源),该接口通常由服务器(WebLogic,WebSphere,Tomcat)提供实现,也有一些开源组织提供实现。
    • C3P0:一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以
    • DBCP:Apache提供的数据库连接池,速度相对C3P0较快,但因自身存在BUG,Hibernate3已不再提供支持
    • Proxool:sourceforge下的一个开源项目数据库连接池,有监控链接池状态的功能,稳定性较C3P0差一点
    • BoneCP:一个开源组织提供的数据库连接池,速度快
    • Druid:阿里提供的数据库连接池,据说是集DBCP,C3P0,Proxool优点于一身的数据库连接池

    10.3 阿里的 Druid(德鲁伊)连接池技术

    Github地址:https://github.com/alibaba/druid/

    10.3.1 加入jar包

    例如:druid-1.1.10.jar
    JDBC

    10.3.2 代码步骤

    第一步:建立一个数据库连接池

    第二步:设置连接池的参数

    第三步:获取连接

    10.3.3 示例模板
    package com.test.jdbc_Batch;
    
    import com.alibaba.druid.pool.DruidDataSource;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public class demo_2_TestPool {
        public static void main(String[] args) throws SQLException {
            //1.创建数据库连接池
            DruidDataSource dataSource = new DruidDataSource();
    
            //2.设置参数
            //(1)设置基本参数
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false");
            dataSource.setUsername("root");
            dataSource.setPassword("root");
    
            //3. 获取连接
            Connection conn = dataSource.getConnection();
            System.out.println(conn);
    
            //如果这里没有关闭,就相当于没有还
            conn.close();//这里关闭,是还回连接池中
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    JDBC

    10.3.4 set基本参数设置
    配置缺省值说明
    name配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开。 如果没有配置,将会生成一个名字,格式是:“DataSource-”+System.identityHashCode(this).
    url连接数据库的url,不同的数据库不一样。例如:mysql:jdbc:mysql://10.20.***.**:3306/dbjavalearning oracle:jdbc:oracle:thin:@10.20.***.**:1521:dbjavalearning
    username连接数据库的用户名
    password连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。 详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
    driverClassName根据url自动识别这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下)
    initialSize0初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection
    maxActive8最大连接池数量
    maxIdle8已经不再使用,配置了也没效果
    minIdle最小连接池数量
    maxWait获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
    poolPreparedStatementsfalse是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
    maxOpenPreparedStatements-1要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
    validationQuery用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
    testOnBorrowtrue申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
    testOnReturnfalse归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
    testWhileIdlefalse建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
    timeBetweenEvictionRunsMillis有两个含义: 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
    numTestsPerEvictionRun不再使用,一个DruidDataSource只支持一个EvictionRun
    minEvictableIdleTimeMillis
    connectionInitSqls物理连接初始化的时候执行的sql
    exceptionSorter根据dbType自动识别当数据库抛出一些不可恢复的异常时,抛弃连接
    filters属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
    proxyFilters类型是List,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系
    10.3.5 可能报异常的情况
    package com.test.jdbc_Batch;
    
    import com.alibaba.druid.pool.DruidDataSource;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public class demo_3_Druid {
        public static void main(String[] args) throws SQLException {
    
            //准备url
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            //准备用户名
            String user = "root";
            //准备密码
            String pwd = "root";
    
    
            DruidDataSource dataSource = new DruidDataSource();
            //2.设置参数
            //(1)设置基本参数
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
            dataSource.setUrl(url);
            dataSource.setUsername(user);
            dataSource.setPassword(pwd);
    
            dataSource.setInitialSize(2);
            dataSource.setMaxActive(5);//最多5个连接
            dataSource.setMaxWait(5000);
    
            //需要运行10个,但最大只允许有5个
            //连接池不够,会出现超时
            for (int i = 0; i < 10; i++) {
                Connection connection = dataSource.getConnection();
                System.out.println("第"+i+"次 ---->"+connection);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    超时了!!!
    JDBC

    10.3.6 我的实例
    package com.test.jdbc_Batch;
    
    import com.alibaba.druid.pool.DruidDataSource;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public class demo_2_Druid {
        public static void main(String[] args) throws SQLException {
           //准备url
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            //准备用户名
            String user = "root";
            //准备密码
            String pwd = "root";
    
            DruidDataSource dataSource = new DruidDataSource();
            //2.设置参数
            //(1)设置基本参数
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
            dataSource.setUrl(url);
            dataSource.setUsername(user);
            dataSource.setPassword(pwd);
    
            //证明两点:
            //1. 被lose的连接对象并没有真正关闭,而是将状态重新设置为空闲状态,然后放回池子,这样下次获取连接对象,这个对象会被重复使用。
            //2. 没有被close的连接对象,会被一直占用,那么下次被获取连接对象,是不会获取到这个对象(Hashcode没有重复)
            for (int i = 0; i < 5; i++) {
                Connection connection = dataSource.getConnection();
                Connection connection2 = dataSource.getConnection();
    
                System.out.println(connection);
                System.out.println(connection2);
    
                if (i%3 == 0) {
                    connection.close();
                    connection2.close();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    先打印出connection:
    JDBC
    再次运行,发现结果相同了:
    JDBC
    此时connection不一样了:
    JDBC
    最终结果:
    JDBC

    10.3.7 创建 jdbc.properties 文件
    /**
     * 一般情况下,配置数据库连接的代码()不会写死在代码里,会需要比如`jdbc.properties`的文件统一管理
     */
    //准备url
    String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
    //准备用户名
    String user = "root";
    //准备密码
    String pwd = "root";
    DruidDataSource dataSource = new DruidDataSource();
    //设置参数
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl(url);
    dataSource.setUsername(user);
    dataSource.setPassword(pwd);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Properties 是一个map格式
    JDBC

    # jdbc 可以不加 jdbc可以让读代码的人更清楚
    jdbc.driverClassName=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false
    jdbc.username=root
    jdbc.password=root
    jdbc.initSize=2
    jdbc.maxActive=5
    jdbc.maxWait=5000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    添加配置文件之后

    package com.test.jdbc_Batch;
    
    import com.alibaba.druid.pool.DruidDataSource;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.Properties;
    
    //读取外部的配置文件设置连接池
    public class demo_4_Druid {
        public static void main(String[] args) throws SQLException,IOException {
            Properties properties = new Properties();
            InputStream is = demo_4_Druid.class.getClassLoader().getResourceAsStream("jdbc.properties");//.getResourceAsStream()指的是从src文件夹下开始读
            properties.load(is);//load 加载
    
            DruidDataSource dataSource = new DruidDataSource();
            //2.设置参数
            //(1)设置基本参数
            dataSource.setDriverClassName(properties.getProperty("jdbc.driverClassName"));
            dataSource.setUrl(properties.getProperty("jdbc.url"));
            dataSource.setUsername(properties.getProperty("jdbc.username"));
            dataSource.setPassword(properties.getProperty("jdbc.password"));
    
            dataSource.setInitialSize(Integer.parseInt(properties.getProperty("jdbc.initSize")));
            dataSource.setMaxActive(Integer.parseInt(properties.getProperty("jdbc.maxActive")));
            dataSource.setMaxWait(Integer.parseInt(properties.getProperty("jdbc.maxWait")));
    
    
            //证明两点:
            //1. 被lose的连接对象并没有真正关闭,而是将状态重新设置为空闲状态,然后放回池子,这样下次获取连接对象,这个对象会被重复使用。
            //2. 没有被close的连接对象,会被一直占用,那么下次被获取连接对象,是不会获取到这个对象(Hashcode没有重复)
            for (int i = 0; i < 10; i++) {
                Connection connection = dataSource.getConnection();
                System.out.println("第"+i+"次 ---->"+connection);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    JDBC

    10.3.8 标准格式
    # properties 标准格式
    driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false
    username=root
    password=root
    initialSize=2
    maxActive=5
    maxWait=5000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    package com.test.jdbc_Batch;
    
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.util.Properties;
    
    public class demo_5_Druid {
        public static void main(String[] args) throws Exception {
            Properties properties = new Properties();
            InputStream is = demo_4_Druid.class.getClassLoader().getResourceAsStream("jdbc2.properties");//.getResourceAsStream()指的是从src文件夹下开始读
            properties.load(is);//load 加载
    
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    
            //证明两点:
            //1. 被lose的连接对象并没有真正关闭,而是将状态重新设置为空闲状态,然后放回池子,这样下次获取连接对象,这个对象会被重复使用。
            //2. 没有被close的连接对象,会被一直占用,那么下次被获取连接对象,是不会获取到这个对象(Hashcode没有重复)
            for (int i = 0; i < 10; i++) {
                Connection connection = dataSource.getConnection();
                System.out.println("第"+i+"次 ---->"+connection);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    11. Statement - 存在注入式漏洞

      Statement - 存在注入式漏洞,因此我们才使用 PreparedStatement - 预处理命令对象,还有有一些有要求不允许java文件不写SQL语句,所有SQL语句需要封装成存储过程,使用 CallableStatement - 执行存储过程调用!

    package com.test.jdbc_Batch;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    
    public class demo_6_Druid {
        public static void main(String[] args) throws Exception {
            //1.加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
    
            //2,通过驱动管理获取连接对象  如果出现警告: Establishing SSL connection without server 请在后面加入: ?useSSL=false&
            //如果还需要处理中文乱码,?useUnicode=true&characterEncoding=utf8 &useSSL=false
            //url表示 统一资源定位符——和数据库通信地址
            //如果url需要带参数,则需要使用?进行连接
            //如果需要带多个参数,则从第二个参数开始使用&连接
            String url = "jdbc:mysql://localhost:3306/dbjavalearning?useUnicode=true&characterEncoding=utf8&useSSL=false";
            String user = "root";
            String pwd = "root";
            Connection connection = DriverManager.getConnection(url, user, pwd);
    
            //3.编写SQL语句
            // id , fname , price , fcount , remark
    
            String fname  = "西瓜";
            String sql = "select * from t_fruit where fname = '" + fname +"'";//注意需要拼接单引号
    
            System.out.println(sql);
    
    //        int fid  = 2;
    //        String sql = "select * from t_fruit where fid = " + fid;
    
            Statement stmt  = connection.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
    
            if (rs.next()){
                System.out.println(rs.getInt(1));
                System.out.println(rs.getString("fname"));
                System.out.println(rs.getInt(3));
                System.out.println(rs.getInt("fcount"));
                System.out.println(rs.getString("remark"));
            }
    
        }
    }
    
    /**
     * Statement - 存在注入式漏洞,一般情况下,不使用
     *   PreparedStatement - 预处理命令对象
     *     CallableStatement - 执行存储过程
     *     
     */ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    JDBC

  • 相关阅读:
    Qt 使用QtWebApp搭建Http服务器
    前端性能优化概述
    自动化测试框架Pytest(三)——自定义allure测试报告
    Linux 使用ss命令停止指定端口进程
    Slax Linux 获得增强的会话管理和启动参数选项
    代码随想录算法训练营第23期day19| 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
    ARM 账号注册报错 The claims exchange ‘Salesforce-UserWriteUsingEmail‘
    Flutter: Unsupported value: false/true
    基于web的照片数码冲印网站
    java Collection和Map接口的区别
  • 原文地址:https://blog.csdn.net/weixin_45048331/article/details/127711389