JDBC(MYSQL-5.7)

IDEA 搭建JDBC 环境

JDBC环境搭建

  • 依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!--   mysql -->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
    </dependency>
    <!-- druid 连接池 -->
    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
    </dependency>
    <dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.7</version>
    </dependency>

JDBC 开发步骤

  1. 注册驱动Class.forName
  2. 获取连接对象connection
  3. 获取执行SQL 语句的对象 statement | prepareStatement
  4. 执行SQL 语句,接受结果 resultSet
  5. 处理结果 输出 | 执行其他处理方式
  6. 释放资源 resultset、statement | prepareStatement 、connection 进行close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.coderitl;


import java.sql.Connection;
import java.sql.DriverManager;

public class JDBCTest {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
// jdbc:mysql://localhost:3306/myemployees?autoReconnect=true&useSSL=false
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myemployees?autoReconnect=true&useSSL=false", "root", "root");
if (connection != null) {
System.out.println("数据库连接成功");
} else {
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
package jdbc;

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

public class TestJDBC {
public static void main(String[] args) {
try {
/*
* mysql8.0 区别于 mysql5.0注册方式:
* mysql8.0: Class.forName("com.mysql.cj.jdbc.Driver");
* mysql5.0: Class.forName("com.mysql.jdbc.Driver");
* */
// 5xxx版本以后也可以省略注册驱动,将与之前连接方式无异,至于后序参数,是由于运行时需要配置时区
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/coderitl?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8", "root", "root");
if (connection != null) {
System.out.println("数据库连接成功");
} else {
System.out.println("数据库连接失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
...
}
}

  • 原因注意: jar包中Driver位置

    sql版本之间的区别

  • 配置其他参数

    配置其他参数

  • 连接成功输出

    连接成功

1
2
3
4
5
6
7
8
9
10
修改连接 url:
mysql5.7:
# useUnicode=true&characterEncoding=utf8 解决数据库字符显示乱码问题
String url = "jdbc:mysql://localhost:3306/myemployees?autoReconnect=true&useSSL=false&characterEncoding=utf-8";
String user = "root";
String passWord = "root";
Connection connection = DriverManager.getConnection(url, user, passWord);
mysql8.0:
完善 url: jdbc:mysql://localhost:3306/coderitl?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
url分析: jdbc:mysql://localhost:3306【ip:端口号】/数据库名?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8

问题解决,修改url参数

JDBC-增删改查操作

  • 查询数据

    • 数据准备

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      表结构: 
      mysql> desc loginInfo;
      +----------+-------------+------+-----+---------+-------+
      | Field | Type | Null | Key | Default | Extra |
      +----------+-------------+------+-----+---------+-------+
      | username | varchar(20) | YES | | NULL | |
      | password | varchar(20) | YES | | NULL | |
      +----------+-------------+------+-----+---------+-------+
      2 rows in set (0.00 sec)

      添加数据:
      mysql> insert into loginInfo values('coderitl','root');
    • jdbc mysql8.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
      package com.coderitl.jdbc;

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

      /**
      * @author coder-itl
      */
      public class JDBCLoginUser {
      public static void main(String[] args) throws Exception {
      // 注册驱动
      Class.forName("com.mysql.cj.jdbc.Driver");
      // 获取 conn
      String url = "jdbc:mysql://localhost:3306/JDBC?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8";
      Connection connection = DriverManager.getConnection(url, "root", "root");
      if (connection != null) {
      System.out.println("数据库连接成功");
      } else {
      System.out.println("数据库连接失败");
      }
      Scanner scanner = new Scanner(System.in);
      System.out.print("请输入用户名: ");
      String username = scanner.next();
      System.out.print("请输入密码: ");
      String password = scanner.next();

      // sql 注意拼接 ''
      String sql = "select * from loginInfo where username='" + username + "' and password='" + password + "'";
      System.out.println(sql);
      Statement statement = connection.createStatement();
      ResultSet resultSet = statement.executeQuery(sql);
      while (resultSet != null) {
      System.out.println("用户成功登录");
      return;
      }
      // 关闭资源
      resultSet.close();
      statement.close();
      connection.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
    package com.coderitl;


    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;

    public class JDBCTest {
    public static void main(String[] args) throws Exception {
    // 1. 注册驱动 加载驱动
    Class.forName("com.mysql.jdbc.Driver");
    // 2. 获得连接
    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/myemployees?autoReconnect=true&useSSL=false", "root", "root");
    if (connection != null) {
    System.out.println("数据库连接成功");
    } else {
    System.out.println("数据库连接失败");
    }

    // 3. 获得执行 SQL 语句的对象
    Statement statement = connection.createStatement();
    // 4. 编写 SQL 语句,执行 SQL 语句
    String sql = "select * from employees";

    ResultSet resultSet = statement.executeQuery(sql);

    // 5. 处理结果 增删改 int ,查询 resultset
    // 查询需要遍历数据 如果为 true 就是有数据
    while (resultSet.next()) {
    // 对当前每列数据进行获取,根据列的编号
    int employee_id = resultSet.getInt(1);
    String first_name = resultSet.getString(2);
    String last_name = resultSet.getString(3);
    String email = resultSet.getString(4);
    System.out.println(employee_id + "\t" + first_name + "\t" + last_name + "\t" + email);
    }
    // 6. 关闭资源 先开后关原则
    resultSet.close();
    statement.close();
    connection.close();

    }
    }

    注意: 需要对应表的数据类型

    1
    2
    3
    # 表中为 int 类型   
    String employee_id = resultSet.getString("employee_id");

    1
    2
    3
    4
    5
    6
    7
    8
    // SQL 语句
    String insertSql = "insert into test values(1002,'test01')";
    // 5. 处理结果
    int result = statement.executeUpdate(insertSql);
    if (result == 1) {
    System.out.println("数据插入成功");
    }

    1
    2
    3
    4
    5
    6
    7
    // SQL 语句
    String delete = "delete from test where id='1001'";
    // 5. 处理结果
    int result = statement.executeUpdate(delete);
    if (result == 1) {
    System.out.println("数据删除成功");
    }
    1
    2
    3
    4
    5
    6
    7
    // SQL 语句
    String update = "update test set testname='nameTest' where id=1002";
    // 5. 处理结果
    int result = statement.executeUpdate(update);
    if (result == 1) {
    System.out.println("数据更新成功");
    }

避免SQL注入问题

  • 问题复现

    • 什么是SQL 注入

      用户输入的数据中有SQL 关键字或语法并且参与了SQL 语句编译,导致SQL 语句编译后的条件含义为true,一直得到正确的结果。这种现象称为SQL 注入

    • 控制台输入,进行SQL 注入测试

      SQL注入测试
    • 实际执行的SQL 语句

      实际执行的SQL
    • 如何避免SQL 注入

      由于编写的SQL 语句是在用户数数据,整合后再进行编译,所以为了避免SQL 注入的问题,我们要使用SQL 语句再用户输入数据前就已经编译完整的SQL 语句,再进行填充数据

    • PreparedStatement 继承了statement 接口,所以两者执行SQL 语句的方法无异
    • 动态设置值,下标从1 开始,使用? 作为占位符
    • PreparedStatement 的作用
      1. 预编译SQL 语句,效率高
      2. 安全,避免SQL 注入
      3. 可以动态的填充数据,执行多个同构的SQL 语句
    • 使用PrepareedStatement

      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
      package com.coderitl;

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


      public class PreJDBCLogin {
      public static void main(String[] args) throws Exception {
      Class.forName("com.mysql.jdbc.Driver"); //
      Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false", "root", "root");
      if (connection != null) {
      System.out.println("数据库连接成功");
      } else {
      System.out.println("数据库连接失败");
      }
      // prepareStatement
      Scanner scan = new Scanner(System.in);
      System.out.println("请输入用户名: ");
      String inputUsername = scan.next();
      System.out.println("请输入密码: ");
      String inputPassword = scan.next();
      // 使用 ? 作为占位符
      PreparedStatement preparedStatement = connection.prepareStatement("select username,password from userinfo where username=? and password=?");
      // 下标从 1 开始,中文内容不能正确解析,除非在连接参数中添加 characterEncoding=utf-8
      // 解决方案: jdbc:mysql://101.34.1.228:3306/test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
      preparedStatement.setString(1, inputUsername);
      preparedStatement.setString(2, inputPassword);
      // 执行sql
      ResultSet resultSet = preparedStatement.executeQuery();
      if (resultSet.next()) {
      System.out.println("登录成功");
      } else {
      System.out.println("登录失败");
      }
      resultSet.close();
      connection.close();

      }
      }

    • 如何避免SQL 注入的?

      SQL预编译

封装工具类

  • src 目录下新建db.properties

    db.properties
    1
    2
    3
    4
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://101.34.1.228:3306/test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
    user=root
    password=root
  • 封装

    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
    package com.coderitl.java;


    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;

    public class Utils {
    // 定义一个静态私有的常量 作用: 存储文件的 map 集合
    private static final Properties PROPERTIES = new Properties();

    static {
    // 流
    InputStream is = Utils.class.getResourceAsStream("/db.properties");
    try {
    PROPERTIES.load(is); // 通过流 将配置文件内容加载到 properties 集合
    Class.forName(PROPERTIES.getProperty("driver"));
    } catch (IOException e) {
    e.printStackTrace();
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }
    }

    // Connection 方法
    public static Connection getConnection() {
    Connection connection = null;
    try {
    connection = DriverManager.getConnection(PROPERTIES.getProperty("url"), PROPERTIES.getProperty("user"), PROPERTIES.getProperty("password"));

    } catch (SQLException e) {
    e.printStackTrace();
    }
    return connection;
    }

    // 关闭资源
    public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
    try {
    if (resultSet != null) {
    resultSet.close();
    }

    if (statement != null) {
    statement.close();
    }

    if (connection != null) {
    connection.close();
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }

DAO数据访问对象(Data Access Object)

  • DAO 实现了业务逻辑与数据库访问相分离

    • 对同一张表的所有封装在XxxDaoImpl 对象中
    • 根据增删改查的不同功能实现具体的方法(insert,update,select,selectAll)
  • 练习增删改查

    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
    package com.coderitl.java;

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

    /*
    * 增
    * 删
    * 改
    * 查单个
    * 查 all
    * */
    public class PersonDaoImpl {


    public int insert(Person person) {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
    connection = Utils.getConnection();
    preparedStatement = connection.prepareStatement("insert into Person(name,age,bornDate,email,address) values(?,?,?,?,?)");

    preparedStatement.setString(1, person.getName());
    preparedStatement.setInt(2, person.getAge());
    preparedStatement.setDate(3, null);
    preparedStatement.setString(4, person.getEmail());
    preparedStatement.setString(5, person.getAddress());
    int result = preparedStatement.executeUpdate();
    return result;
    } catch (SQLException e) {
    e.printStackTrace();
    } finally {
    Utils.closeAll(connection, preparedStatement, null);
    }


    return 0;
    }

    public int update(Person person) {
    return 0;
    }

    public int delete(int id) {
    return 0;
    }

    public Person select() {
    return null;
    }

    public List<Person> selectAll() {
    return null;
    }
    }

    ---------------------------------------------------------------------------------
    package com.coderitl.java;


    public class TestInsert {
    public static void main(String[] args) {
    PersonDaoImpl personDao = new PersonDaoImpl();
    Person person = new Person("张三", 19, null, "zhangsan@163.com", "我爱学Java");
    int insertResult = personDao.insert(person);
    if (insertResult == 1) {
    System.out.println("数据添加成功");
    } else {
    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
    public int update(Person person) {
    Connection connection = null;
    PreparedStatement preparedStatement = null;

    try {
    connection = Utils.getConnection();
    preparedStatement = connection.prepareStatement("update Person set name=?,age=?,bornDate=?,email=?,address=? where id=?");
    preparedStatement.setString(1, person.getName());
    preparedStatement.setInt(2, person.getAge());
    preparedStatement.setDate(3, null);
    preparedStatement.setString(4, person.getEmail());
    preparedStatement.setString(5, person.getAddress());
    preparedStatement.setInt(6, person.getId());
    int updateResult = preparedStatement.executeUpdate();
    return updateResult;
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    Utils.closeAll(connection, preparedStatement, null);
    }
    return 0;
    }

    ---------------------------------------------------------------------------------
    package com.coderitl.java;

    public class TestUpdate {
    public static void main(String[] args) {
    PersonDaoImpl personDao = new PersonDaoImpl();
    Person person = new Person(1, "测试1", 12, null, "ceshi@qq.com", "测试地址");
    int updateResult = personDao.update(person);
    if (updateResult == 1) {
    System.out.println("数据已经更新");
    } else {
    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
    public int delete(int id) {
    Connection connection = null;
    PreparedStatement preparedStatement = null;

    try {
    connection = Utils.getConnection();
    preparedStatement = connection.prepareStatement("delete from Person where id=?");
    preparedStatement.setInt(1, id);
    int deleteResult = preparedStatement.executeUpdate();
    return deleteResult;
    } catch (SQLException e) {
    e.printStackTrace();
    } finally {
    Utils.closeAll(connection, preparedStatement, null);
    }
    return 0;
    }
    ---------------------------------------------------------------------------------
    package com.coderitl.java;


    public class TestDelte {
    public static void main(String[] args) {
    PersonDaoImpl personDao = new PersonDaoImpl();
    int deleteResult = personDao.delete(1);
    if (deleteResult == 1) {
    System.out.println("数据已经成功删除");
    } else {
    System.out.println("数据操作失败");
    }
    }
    }

Date 工具类

java.util.Date

  • Java 语言常规用用层面的日期类型,可以通过字符串创建对应的时间对象
  • 无法直接通过JDBC 插入数据库

java.sql.Date

  • 不可以通过字符串创建对应的事件对象,只能通过毫秒值创建对象(1970至今的毫秒值)
  • 可以直接通过JDBC 插入数据库

SimpleDateFormat

  • 格式化和解析日期的具体类,允许进行格式化(日期 - > 文本),解析(文本 - > 日期)和规范化
  • 分析

    字符串工具类
  • 实现

    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
    package login;

    import java.text.SimpleDateFormat;
    import java.util.Date;

    public class TestDate {
    public static void main(String[] args) throws Exception {
    // Java层面: java.util.Date
    Date date = new Date();
    System.out.println(date); // Wed Jan 05 17:45:42 CST 2022

    // 字符串日期
    String strDate = "2022-01-05";

    // 如何将字符串日期转换为 java.util.Date => 借助 SimpleDateFormat
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    // parse 方法将字符串日期转换为 java.util.Date 类型
    java.util.Date javaUtilDate = sdf.parse(strDate);
    System.out.print("检测javaUtilDate是否是(java.util.Date)类型: ");
    System.out.println(javaUtilDate instanceof java.util.Date);
    System.out.println(javaUtilDate);

    // 将 java.util.Date 转换为 字符串类型
    String javaUtilDateToStr = sdf.format(date);
    System.out.print("检测javaUtilDateToStr是否是(String)类型: ");
    System.out.println(javaUtilDateToStr instanceof String);
    System.out.println(javaUtilDateToStr);

    // sql.Date 不支持字符串转换 只支持毫秒值创建
    // 通过 util.Date 拿到指定日期的毫秒值 => 转换为 sql.Date
    java.sql.Date sqlDate = new java.sql.Date(javaUtilDate.getTime());
    System.out.println(sqlDate);
    System.out.print("检测sqlDate是否是(java.sql.Date)类型: ");
    System.out.println(sqlDate instanceof java.sql.Date);

    // 目标: 数据库Date: java.sql.Date

    }
    }

  • 写入数据库的最终执行流程

    写入数据库的最终执行流程
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
package com.coderitl.testdate;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtils {
public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

// 字符串转换为 util.Date
public static java.util.Date strToUtil(String str) {
try {
Date date = sdf.parse(str);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}

// util.Date 转换为 sql.Date
public static java.sql.Date TutiloSql(java.util.Date date) {
return new java.sql.Date(date.getTime());
}

// Util.Date 转换为字符串形式
public static String utilToStr(java.util.Date date) {
return sdf.format(date);
}
}

  • 使用

    使用分析

Service业务逻辑层

  • 什么是业务?

    代表用户完成的一个业务功能,可以由一个或多个DAO 的调用组成的(软件所提供的一个功能都叫业务)

  • 表结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    use test;
    create table account
    (
    cardNo varchar(20) primary key comment '银行卡号',
    password varchar(20) not null comment '密码',
    username varchar(20) not null comment '用户名',
    balance double not null comment '余额'
    ) default character set "utf8";


    insert into account

    values ('1002', '1002pwd', 'US1002', 9999);

    select * from account;

三层架构

  • 表示层

    • 命名: xxxView
    • 职责: 收集用户的数据和需求,展示数据
  • 业务逻辑层

    • 命名: xxxServiceImpl
    • 职责: 数据加功处理,调用DAO 完成业务实现,控制事务
  • 数据访问层

    • 命名: xxxDaoImpl
    • 职责: 向业务层提供数据,将业务层加工后的数据同步到数据库

三层架构项目搭建

  • 接口 \ 接口实现类

    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
    E:.
    │ .gitignore
    │ PersonProj.iml
    │ README.md
    ├─libs
    │ mysql-connector-java-5.1.47.jar

    └─src
    │ db.properties

    └─com
    └─coderitl
    ├─advanced
    │ │ RowMapper.java
    │ │
    │ └─impl
    │ PersonRowMapperImpl.java

    ├─dao
    │ │ PersonDao.java
    │ │
    │ └─impl
    │ PersonDaoImpl.java

    ├─entity
    │ Person.java

    ├─service
    │ │ PersonService.java
    │ │
    │ └─impl
    │ PersonServiceImpl.java

    ├─utils
    │ DaoUtils.java
    │ DateUtils.java
    │ Utils.java

    └─view
    TestPerson.java

连接池

Druid 连接池

  • 描述

    在初始化时,预先创建指定数量的数据库连接对象存储在池中,当需要连接数据库时,从连接池中取出现有连接,使用完毕后,也不会进行关闭,而是放回池中,实现复用,节省资源

ApacheDBUtils 使用

  • 基础使用

    • DBUtils 简介

      • DBUtils java 编程中数据库操作实用的小工具,小巧,简单,实用
        • 对于数据表的查询操作,可以把结果转换为List,Array,Set 等集合,偏于操作
        • 对于数据表DML 操作,也变得简单(只需要写SQL语句)
    • DBUtils 主要包含

      • ResultSetHandler 接口: 转换类型接口
        • BeanHandler 类: 实现类,把一条记录转换成对象
        • BeanListHandler 类,把多条记录转换成List 集合
        • ScalarHandler 类:实现类,适合获取一行一列的数据
      • QueryRunner:执行sql 语句的类
        • 增、删、改:update()
        • 查询: query()
    • 导入jar | maven依赖
      • mysql 连接驱动jar | maven 坐标
      • druid jar| maven 坐标
      • database.properties 配置文件
      • commons-dbutils jar | maven 坐标
    • 连接池使用

      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
      package com.coderitl.utils;

      import com.alibaba.druid.pool.DruidDataSource;
      import com.alibaba.druid.pool.DruidDataSourceFactory;

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

      public class DBUtils {

      // 声明连接池对象
      private static DruidDataSource ds;

      static {
      Properties properties = new Properties();
      // 创建流
      InputStream is = DBUtils.class.getResourceAsStream("/database.properties");
      // 加载
      try {
      properties.load(is);
      //
      ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
      } catch (IOException e) {
      e.printStackTrace();
      } catch (Exception e) {
      e.printStackTrace();
      }
      }

      public static Connection getConnection() {
      try {
      // 通过连接池获得连接对象
      return ds.getConnection();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      return null;
      }

      public static DataSource getDataSource() {
      return ds;
      }


      public static void begin() {
      try {
      Connection connection = getConnection();
      connection.setAutoCommit(false);
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }

      public static void commit() {
      try {
      Connection connection = getConnection();
      connection.commit();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }

      public static void rollback() {
      Connection connection = null;
      try {
      connection = getConnection();
      connection.rollback();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }

      }

    • maven 依赖

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.22</version>
      </dependency>

      <dependency>
      <groupId>commons-dbutils</groupId>
      <artifactId>commons-dbutils</artifactId>
      <version>1.7</version>
      </dependency>
    • 数据准备

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      mysql> desc userinfo;
      +----------+-------------+------+-----+---------+----------------+
      | Field | Type | Null | Key | Default | Extra |
      +----------+-------------+------+-----+---------+----------------+
      | id | int(11) | NO | PRI | NULL | auto_increment |
      | username | varchar(10) | NO | | NULL | |
      | password | varchar(18) | NO | | NULL | |
      +----------+-------------+------+-----+---------+----------------+
      3 rows in set (0.07 sec)

      mysql>
    • 查询时实体类必须提供无参构造

      未提供无参构造 解决后
      未提供无参构造 解决后
    • 数据库连接池配置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      driverClassName=com.mysql.jdbc.Driver
      url=jdbc:mysql://localhost:3306/bookshop?characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&useSSL=false

      username=root

      password=root

      # 连接池配置
      initialSize=10
      # 最大连接数
      maxActive=30
      # 最小空闲连接数
      minIdle=5
      # 超时等待时间以毫秒为单位 60000/1000=60s
      maxWait=5000
    • 添加maven 相关依赖

    • 创建DbUtils

    • 使用Dbutis(dao/impl)

      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
      package com.example.book.dao.impl;

      import com.example.book.dao.BookInfoDao;
      import com.example.book.entity.BookInfo;
      import com.example.book.utils.DbUtils;
      import org.apache.commons.dbutils.QueryRunner;
      import org.apache.commons.dbutils.handlers.BeanHandler;
      import org.apache.commons.dbutils.handlers.BeanListHandler;

      import java.sql.SQLException;
      import java.util.List;

      public class BookInfoDaoImpl implements BookInfoDao {
      // 使用 DbUtils 内部会自动调用 Connect
      private QueryRunner queryRunner = new QueryRunner(DbUtils.getDataSource());

      @Override
      public BookInfo selectBookByName(String bookName) {
      try {
      // 查询单个 BeanHandler 接口
      BookInfo bookInfo = queryRunner.query("select * from bookinfo where bookName =?", new BeanHandler<BookInfo>(BookInfo.class), bookName);
      return bookInfo;
      } catch (Exception e) {
      e.printStackTrace();
      }
      return null;
      }

      @Override
      public List<BookInfo> selectAllBook() {
      try {
      // 查询多个
      List<BookInfo> listBookInfo = queryRunner.query("select * from bookinfo", new BeanListHandler<BookInfo>(BookInfo.class));
      return listBookInfo;
      } 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
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      package com.example.dao.impl;

      import com.example.dao.UserDao;
      import com.example.domain.User;
      import com.example.utils.DBUtils;
      import org.apache.commons.dbutils.QueryRunner;
      import org.apache.commons.dbutils.handlers.BeanHandler;

      import java.sql.SQLException;

      public class UserDaoImpl implements UserDao {
      // 使用 DbUtils 内部会自动调用 Connect
      private QueryRunner queryRunner = new QueryRunner(DBUtils.getDataSource());

      @Override
      public User selectUserByName(String username) {
      if (username != null) {
      try {
      User user = queryRunner.query("select * from user where username=?", new BeanHandler<User>(User.class), username);
      return user;
      } catch (SQLException e) {
      throw new RuntimeException(e);
      }
      }
      return null;
      }

      @Override
      public boolean addUser(User user) {
      Object[] params = {
      user.getId(),
      user.getUsername(),
      user.getPassword(),
      user.getEmail(),
      user.getBirthday()
      };
      try {
      int update = queryRunner.update("insert into user values(?,?,?,?,?)", params);
      return update > 0;
      } catch (SQLException e) {
      throw new RuntimeException(e);
      }
      }

      @Override
      public boolean updateUser(User user) {
      Object[] params = {user.getUsername(), user.getId()};
      try {
      int update = queryRunner.update("update user set username=? where id=?", params);
      return update > 0;
      } catch (SQLException e) {
      throw new RuntimeException(e);
      }
      }

      @Override
      public boolean deleteUser(Integer id) {
      try {
      int update = queryRunner.update("delete from user where id=?", id);
      return update > 0;
      } catch (SQLException e) {
      throw new RuntimeException(e);
      }
      }
      }

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      // 测试
      package com.example;

      import com.example.dao.UserDao;
      import com.example.dao.impl.UserDaoImpl;
      import com.example.domain.User;

      public class JdbcUser {
      public static void main(String[] args) {
      UserDao userDao = new UserDaoImpl();
      User user = new User(1003, "coderitl2", "123456", "123456@qq.com", "2022-04-06");
      boolean addUser = userDao.addUser(user);
      if (addUser) {
      System.out.println("添加成功");
      User userInfo = userDao.selectUserByName("coderitl");
      if (userInfo != null) {
      System.out.println(userInfo);
      }
      }
      }
      }

      输出
      测试
      演示
      演示

MVC-传递分析

  • 三层架构的使用

    • 传递分析

      MVC-传递分析
    • dao => 只与数据库交互
    • service => 调用dao
    • controller => 调用service,环环相扣,又与之分离