3. JDBC

3.1. JDBC基本概念

3.1.1. 概念
  • Java DataBase Connectivity:Java数据库连接,Java语言操作数据库
3.1.2. JDBC的本质
  • 其实是官方(SUN公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
3.2. 快速入门

3.2.1. 步骤
  • 导入驱动jar包

    1.复制mysql-connector-java-5.1.48-bin.jar到项目的libs目录下
    2.右键-->Add as Library
    
  • 注册驱动

    Class.forName("com.mysql.jdbc.Driver");
    
  • 获取数据库连接对象:Connection

    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名称", "用户名称", "用户密码");
    
  • 定义sql

    String sql = "UPDATE account SET balance = 500 WHERE id = 1";
    
  • 获取执行sql语句的对象:Statement

    Statement statement = connection.createStatement();
    
  • 执行sql,接收返回的结果

    int count = statement.executeUpdate(sql);
    
  • 处理结果

    System.out.println(count);
    
  • 释放资源

    statement.close();
    connection.close();
    
3.3. 对JDBC中各个接口和类详解

3.3.1. DriverManager
  • 驱动管理对象

  • 功能:

    • 注册驱动:告诉我们的程序该使用哪一个数据库驱动jar

      // Registers the given driver with the DriverManager.
      static void	registerDriver(Driver driver);
      // 写代码使用:Class.forName("com.mysql.jdbc.Driver");
      // 通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块:
      static {
          try {
              DriverManager.registerDriver(new Driver());
          } catch (SQLException var1) {
              throw new RuntimeException("Can't register driver!");
          }
      }
      // 注意:MySQL5之后的驱动jar包可以省略注册驱动的步骤
      
    • 获取数据库连接:

      // Attempts to establish a connection to the given database URL.
      static Connection getConnection(String url, String user, String password);
      // 参数
      /* url:指定连接的路径(语法:jdbc:mysql://ip地址(域名):端口号/数据库名称) 例子:jdbc:mysql://localhost:3306/db1 细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称 user:用户名 password:密码 */
      
3.3.2. Connection
  • 数据库连接对象

  • 功能:

    • 获取执行sql的对象:

      // Creates a Statement object for sending SQL statements to the database.
      Statement createStatement();
      
      // Creates a PreparedStatement object for sending parameterized SQL statements to the database.
      PreparedStatement prepareStatement(String sql);
      
    • 管理事务:

      // 开启事务
      // Sets this connection's auto-commit mode to the given state.
      // 调用该方法,设置参数为false,即开启事务
      void setAutoCommit(boolean autoCommit);
      
      // 提交事务
      // Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by this Connection object.
      void commit();
      
      // 回滚事务
      // Undoes all changes made in the current transaction and releases any database locks currently held by this Connection object.
      void rollback();
      
3.3.3. Statement
  • 执行sql的对象

  • 功能:

    • 执行sql

      // Executes the given SQL statement, which may return multiple results.
      // 可以执行任意的sql语句【了解】
      boolean	execute(String sql);
      
      // Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement.
      // 执行DML(insert、update、delete)语句、DDL(create、drop、alter)语句
      // 返回值:影响的行数,可以通过这个影响的行数判断DML是否执行成功:返回值>0的则执行成功,反之则失败
      int	executeUpdate(String sql);
      
      // Executes the given SQL statement, which returns a single ResultSet object.
      // 执行DQL(select)语句
      ResultSet executeQuery(String sql);
      
    • 练习

      • 添加一条记录

        public class JDBCInsert {
            public static void main(String[] args) {
                Statement statement = null;
                Connection connection = null;
                try {
                    // 1.注册驱动
                    Class.forName("com.mysql.jdbc.Driver");
                    // 2.定义sql
                    String sql = "INSERT INTO account VALUES(null, '王五', 3000)";
                    // 3.获取Connection对象
                    connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "xiaoer");
                    // 4.获取执行sql的对象:Statement
                    statement = connection.createStatement();
                    // 5.执行sql
                    // 返回结果为影响的行数
                    int count = statement.executeUpdate(sql);
                    // 6.处理结果
                    System.out.println(count);
                    if (count > 0) {
                        System.out.println("添加成功!");
                    } else {
                        System.out.println("添加失败!");
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    // statement.close();
                    // 7.释放资源
                    // 避免空指针异常
                    if (statement != null) {
                        try {
                            statement.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                    if (connection != null) {
                        try {
                            connection.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        
        
      • 修改记录

        public class JDBCUpdate {
            public static void main(String[] args) {
                Statement statement = null;
                Connection connection = null;
                try {
                    // 1.注册驱动
                    Class.forName("com.mysql.jdbc.Driver");
                    // 2.获取连接对象
                    connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "xiaoer");
                    // 3.定义sql
                    String sql = "UPDATE account SET balance = 1500 WHERE id = 3";
                    // 4.获取执行sql的对象
                    statement = connection.createStatement();
                    // 5.执行sql
                    int count = statement.executeUpdate(sql);
                    // 6.处理结果
                    System.out.println(count);
                    if (count > 0) {
                        System.out.println("修改成功!");
                    } else {
                        System.out.println("修改失败!");
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    // 7.释放资源
                    if (statement != null) {
                        try {
                            statement.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                    if (connection != null) {
                        try {
                            connection.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        
      • 删除一条记录

        public class JDBCDelete {
            public static void main(String[] args) {
                Statement statement = null;
                Connection connection = null;
                try {
                    // 1.注册驱动
                    Class.forName("com.mysql.jdbc.Driver");
                    // 2.获取连接对象
                    connection = DriverManager.getConnection("jdbc:mysql:///db1", "root", "xiaoer");
                    // 3.定义sql
                    String sql = "DELETE FROM account WHERE id = 3";
                    // 4.获取执行sql对象:Statement
                    statement = connection.createStatement();
                    // 5.执行sql
                    int count = statement.executeUpdate(sql);
                    // 6.结果处理
                    System.out.println(count);
                    if (count > 0) {
                        System.out.println("删除成功!");
                    } else {
                        System.out.println("删除失败!");
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    // 7.释放资源
                    if (statement != null) {
                        try {
                            statement.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                    if (connection != null) {
                        try {
                            connection.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        
3.3.4. ResultSet
  • 结果集对象,封装查询结果

    // Moves the cursor forward one row from its current position.
    // 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是则返回false,如果不是则返回true
    boolean	next();
    
    // 获取数据
    // Xxx代表数据类型
    // 参数:
    // int:代表列的编号,从1开始 如:getString(1);
    // String:代表列的名称 如:getString("balance");
    Xxx getXxx(参数);
    int getInt(参数);
    String getString(参数);
    
    使用步骤:
    1.游标向下移动一行
    2.判断是否有数据
    3.获取数据
    while (resultSet.next()) {
        // 获取数据
        int id = resultSet.getInt(1);
        String name = resultSet.getString("name");
        double balance = resultSet.getDouble(3);
        System.out.println(id + "---" + name + "---" + balance);
    }
    
  • 练习:

    • 定义一个方法,查询emp表的数据将其封装成对象,然后装载集合,返回。

      • 定义一个实体类:Emp
      • 定义一个方法:public Lish<类名> findAll(){}
      • 实现方法:SELECT * FROM 表名;
      import java.util.Date;
      
      /** * 封装emp表数据的JavaBean * * @author xiao儿 * @date 2019/10/9 13:01 */
      public class Emp {
          private int id;
          private String name;
          private String gender;
          private double salary;
          private Date join_date;
          private int dept_id;
      
          public int getId() {
              return id;
          }
      
          public void setId(int id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public String getGender() {
              return gender;
          }
      
          public void setGender(String gender) {
              this.gender = gender;
          }
      
          public double getSalary() {
              return salary;
          }
      
          public void setSalary(double salary) {
              this.salary = salary;
          }
      
          public Date getJoin_date() {
              return join_date;
          }
      
          public void setJoin_date(Date join_date) {
              this.join_date = join_date;
          }
      
          public int getDept_id() {
              return dept_id;
          }
      
          public void setDept_id(int dept_id) {
              this.dept_id = dept_id;
          }
      
          @Override
          public String toString() {
              return "Emp{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", gender=" + gender +
                      ", salary=" + salary +
                      ", join_date=" + join_date +
                      ", dept_id=" + dept_id +
                      '}';
          }
      }
      
      import java.sql.*;
      import java.util.ArrayList;
      import java.util.List;
      
      /** * 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。 * * @author xiao儿 * @date 2019/10/9 13:21 */
      public class JDBCDemo1 {
          public static void main(String[] args) {
              List<Emp> list = new JDBCDemo1().findAll();
              System.out.println(list);
              System.out.println(list.size());
          }
      
          /** * 查询所有Emp对象 * * @return */
          public List<Emp> findAll() {
              Connection connection = null;
              Statement statement = null;
              ResultSet resultSet = null;
              List<Emp> list = null;
              try {
                  // 1.注册驱动
                  Class.forName("com.mysql.jdbc.Driver");
                  // 2.获取连接
                  connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "xiaoer");
                  // 3.定义sql
                  String sql = "SELECT * FROM emp";
                  // 4.获取执行sql的对象
                  statement = connection.createStatement();
                  // 5.执行sql
                  resultSet = statement.executeQuery(sql);
                  // 6.遍历结果集,封装对象,装载集合
                  Emp emp = null;
                  list = new ArrayList();
                  while (resultSet.next()) {
                      // 获取数据
                      int id = resultSet.getInt(1);
                      String name = resultSet.getString(2);
                      String gender = resultSet.getString(3);
                      double salary = resultSet.getDouble("salary");
                      Date join_date = resultSet.getDate(5);
                      int dept_id = resultSet.getInt("dept_id");
                      // 创建emp对象,并赋值
                      emp = new Emp();
                      emp.setId(id);
                      emp.setName(name);
                      emp.setGender(gender);
                      emp.setSalary(salary);
                      emp.setJoin_date(join_date);
                      emp.setDept_id(dept_id);
                      // 装载集合
                      list.add(emp);
                  }
              } catch (ClassNotFoundException e) {
                  e.printStackTrace();
              } catch (SQLException e) {
                  e.printStackTrace();
              } finally {
                  // 7.释放资源
                  // if (resultSet != null) {
                  // try {
                  // resultSet.close();
                  // } catch (SQLException e) {
                  // e.printStackTrace();
                  // }
                  // }
                  // if (statement != null) {
                  // try {
                  // statement.close();
                  // } catch (SQLException e) {
                  // e.printStackTrace();
                  // }
                  // }
                  // if (connection != null) {
                  // try {
                  // connection.close();
                  // } catch (SQLException e) {
                  // e.printStackTrace();
                  // }
                  // }
                  try {
                      if (resultSet != null) {
                          resultSet.close();
                      }
                      if (statement != null) {
                          statement.close();
                      }
                      if (connection != null) {
                          connection.close();
                      }
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
              return list;
          }
      }
      
3.3.5. PreparedStatement
  • 执行sql的对象

  • SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全问题。

    • 输入用户名随便,输入密码:a' or 'a' = 'a
    • sql:SELECT * FROM user WHERE username = '随便的用户名' and password = 'a' or 'a' = 'a'
  • 解决SQL注入问题:使用PreparedStatement对象来解决

  • 预编译的SQL:参数使用?作为占位符

  • 步骤:

    • 导入驱动jar包

      1.复制mysql-connector-java-5.1.48-bin.jar到项目的libs目录下
      2.右键-->Add as Library
      
    • 注册驱动

      Class.forName("com.mysql.jdbc.Driver");
      
    • 获取数据库连接对象:Connection

      Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名称", "用户名称", "用户密码");
      
    • 定义sql:sql的参数的使用?作为占位符

      String sql = "UPDATE account SET balance = 500 WHERE id = ?";
      
    • 获取执行sql语句的对象:PreparedStatement

      PreparedStatement preparedStatement = connection.prepareStatement(sql);
      
    • 给?赋值

      preparedStatement.setXxx(参数1, 参数2);
      // 参数1:?的位置编号,从1开始
      // 餐宿2:?的值
      
    • 执行sql,接收返回的结果

      int count = preparedStatement.executeUpdate();
      
    • 处理结果

      System.out.println(count);
      
    • 释放资源

      statement.close();
      connection.close();
      
  • 注意:后期都会采用PreparedStatement来完成增删改查的所有操作

    • 可以防止SQL注入
    • 效率更高
3.4. 抽取JDBC工具类(JDBCUtils)
  • 目的:简化书写

  • 分析:

    • 注册驱动
    • 抽取一个方法获取连接对象
      • 需求:不想传递参数(麻烦),还需要保证工具类的通用性。
      • 解决:配置文件
    • 抽取一个方法释放资源
    import java.io.FileReader;
    import java.io.IOException;
    import java.net.URL;
    import java.sql.*;
    import java.util.Properties;
    
    /** * JDBC工具类 * * @author xiao儿 * @date 2019/10/9 16:22 */
    public class JDBCUtils {
        private static String url;
        private static String user;
        private static String password;
        private static String driver;
    
        /** * 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块 */
        static {
            // 读取资源文件,获取值
            try {
                // 1.Properties集合类
                Properties properties = new Properties();
                // 获取src路径下的文件的方式-->ClassLoader:类加载器
                ClassLoader classLoader = JDBCUtils.class.getClassLoader();
                URL resource = classLoader.getResource("jdbc.properties");
                String path = resource.getPath();
                // 2.加载文件
                properties.load(new FileReader(path));
                // 3.获取数据,赋值
                url = properties.getProperty("url");
                user = properties.getProperty("user");
                password = properties.getProperty("password");
                driver = properties.getProperty("driver");
                // 4.注册驱动
                Class.forName(driver);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        /** * 获取连接 * * @return 连接对象 */
        public static Connection getConnection() throws SQLException {
            return DriverManager.getConnection(url, user, password);
        }
    
        /** * 释放资源 * * @param statement * @param connection */
        public static void close(Statement statement, Connection connection) {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /** * 释放资源 * * @param resultSet * @param statement * @param connection */
        public static void close(ResultSet resultSet, Statement statement, Connection connection) {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
  • 练习:

    • 需求:

      • 通过键盘录入用户名和密码

      • 判断用户是否登录成功

        -- 如果这个sql有查询结果则成功,反之则失败
        SELECT * FROM user WHERE username = "" and password = "";
        
    • 步骤:

      • 创建数据库表:user

        CREATE TABLE user (
        	id INT PRIMARY KEY AUTO_INCREMENT,
        	username VARCHAR(32),
        	password VARCHAR(32)
        );
        
        INSERT INTO user VALUES(NULL,'zhangsan','123');
        INSERT INTO user VALUES(NULL,'lisi','234');
        
        SELECT * FROM user;
        
      • Java测试类

        public class JDBCDemo {
            public static void main(String[] args) {
                // 1.键盘录入,接收用户名和密码
                Scanner sc = new Scanner(System.in);
                System.out.println("请输入用户名:");
                String username = sc.nextLine();
                System.out.println("请输入密码:");
                String password = sc.nextLine();
                // 2.调用方法
                boolean flag = new JDBCDemo().login(username, password);
                // 3.判断结果,输出不同语句
                if (flag) {
                    System.out.println("登录成功!");
                } else {
                    System.out.println("用户名或密码错误!");
                }
            }
        
            /** * 登录方法 * * @param username 用户名 * @param password 密码 * @return 登录的结果 */
            public boolean login(String username, String password) {
                if (username == null || password == null) {
                    return false;
                }
                Connection connection = null;
                PreparedStatement preparedStatement = null;
                ResultSet resultSet = null;
                // 连接数据库来判断是否登录成功
                try {
                    // 1.获取连接
                    connection = JDBCUtils.getConnection();
                    // 2.定义sql
                    String sql = "SELECT * FROM user WHERE username = ? and password = ?";
                    // 3.获取执行sql的对象:PreparedStatement
                    preparedStatement = connection.prepareStatement(sql);
                    // 4.给?赋值
                    preparedStatement.setString(1, username);
                    preparedStatement.setString(2, password);
                    // 5.执行sql语句,不需要传递sql
                    resultSet = preparedStatement.executeQuery();
                    // 6.判断
                    /*if (resultSet.next()) {// 如果有下一行,则返回true return true; } else { return false; }*/
                    return resultSet.next();// 如果有下一行,则返回true
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    JDBCUtils.close(resultSet, preparedStatement, connection);
                }
                return false;
            }
        }
        
3.5. JDBC控制事务
3.5.1. 事务
  • 一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
3.5.2. 操作
  • 开启事务
  • 提交事务
  • 回滚事务
3.5.3. 使用Connection对象来管理实务
  • 开启事务:setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务。
    • 在执行sql之前开启事务
  • 提交事务:commit();
    • 当所有sql都执行完提交事务
  • 回滚事务:rollback();
    • 在catch中回滚事务
3.6. 数据库连接池
3.6.1. 概念
  • 其实就是一个容器(集合),存放数据库连接的容器。
    • 当系统初始化好之后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
3.6.2. 好处
  • 节约资源
  • 用户访问高效
3.6.3. 实现
  • 标准接口:DataSource–>javax.sql包下的

    • 方法:

      // 获取连接
      getConnection();
      
      // 归还连接,如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接。
      conn.close();
      
  • 一般我们不去实现它,有数据库厂商来实现

    • C3P0:数据库连接池技术
    • Druid:数据库连接池实现技术,由阿里巴巴提供的
3.6.4. C3P0
  • 步骤:

    • 导入jar包(两个):c3p0-0.9.5.2.jar;mchange-commons-java-0.2.11.jar
      • 不要忘记导入数据库驱动jar包
    • 定义配置文件:
      • 名称c3p0.properties 或者 c3p0-config.xml
      • 路径:直接将文件放在src目录下即可
    • 创建核心对象:数据库连接池对象:ComboPooledDataSource
    • 获取连接:getConnection()
    // 1.创建数据库连接池对象
    DataSource ds = new ComboPooledDataSource();
    // 2.获取连接对象
    Connection conn = ds.getConnection();
    // 3.打印
    System.out.println(conn);
    
3.6.5. Druid
  • 步骤:

    • 导入jar包:druid-1.0.15.jar

      • 不要忘记导入数据库驱动jar包
    • 定义配置文件:

      • 是properties形式的
      • 可以叫任意名称,可以放在任意目录下
    • 加载配置文件:

      Properties pro = new Properties();
              InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
              pro.load(is);
      
    • 获取数据库连接池对象:通过工厂类来获取:DruidDataSourceFactory

    • 获取连接:getConnection()

    // 1.导入jar包
    // 2.定义配置文件
    // 3.加载配置文件
    Properties pro = new Properties();
    InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
    pro.load(is);
    // 4.获取连接池对象
    DataSource ds = DruidDataSourceFactory.createDataSource(pro);
    // 5.获取连接
    Connection conn = ds.getConnection();
    System.out.println(conn);
    
  • 定义工具类

    • 定义一个类:JDBCUtils

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

    • 提供方法:

      • 获取连接方法:通过数据库连接池来获取连接
      • 释放资源
      • 获取连接池的方法
    /** * Druid连接池的工具类 * * @author xiao儿 * @date 2019/10/10 20:14 */
    public class JDBCUtils {
        // 1.定义一个成员变量
        private static DataSource ds;
    
        static {
            try {
                // 1.加载配置文件
                Properties pro = new Properties();
                pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
                // 2.获取DataSource
                ds = DruidDataSourceFactory.createDataSource(pro);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /** * 获取连接 * * @return Connection对象 * @throws SQLException */
        public static Connection getConnection() throws SQLException {
            return ds.getConnection();
        }
    
        /** * 释放资源 * * @param stmt Statement对象 * @param conn Connection对象 */
        public static void close(Statement stmt, Connection conn) {
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
    
            if (conn != null) {
                try {
                    conn.close();// 归还连接
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /** * 释放资源 * * @param rs ResultSet对象 * @param stmt Statement对象 * @param conn Connection对象 */
        public static void close(ResultSet rs, Statement stmt, Connection conn) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            //
            // if (stmt != null) {
            // try {
            // stmt.close();
            // } catch (SQLException e) {
            // e.printStackTrace();
            // }
            // }
            //
            // if (conn != null) {
            // try {
            // conn.close();// 归还连接
            // } catch (SQLException e) {
            // e.printStackTrace();
            // }
            // }
            close(stmt, conn);
        }
    
        /** * 获取连接池方法 * * @return DataSource对象 */
        public static DataSource  getDataSource() {
            return ds;
        }
    }
    
3.7. Spring JDBC(JDBC Template)
  • Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化了JDBC的开发

  • 步骤:

    • 导入jar包

    • 创建JDBCTemplate对象。依赖于数据源DataSource

      JDBCTemplate template = new JDBCTemplate(dataSource);
      
    • 调用JDBCTemplate方法来完成CRUD的操作

      // 指定DML语句,执行增、删、改语句
      update();
      // 查询结果将结果封装为map集合
      // 将列名作为key,将作为value,将这条记录封装成一个map集合,而且这个方法查询的结果集长度只能是1
      queryForMap();
      // 查询结果将结果封装为list集合
      // 将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
      queryForList();
      // 查询结果,将结果封装为JavaBean对象
      // query的参数:RowMapper
      // 一般使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
      // new BeanPropertyRowMapper<类型>(类型.class)
      query();
      // 查询结果,将结果封装为对象
      // 一般用于聚合函数的查询
      queryForObject();
      
    // 1.导入jar包
    // 2.创建JDBCTemplate对象
    JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
    // 3.调用方法
    String sql = "UPDATE account SET balance = 5000 WHERE id = ?";
    int count = template.update(sql, 3);
    System.out.println(count);
    
  • 练习:

    • 需求:

      // 1.获取JDBCTemplate对象
      private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
      
      • 修改1号数据的salary为10000

        /** * 1.修改1号数据的salary为10000 */
        @Test
        public void test1() {
            // 2.定义sql
            String sql = "UPDATE emp SET salary = 10000 WHERE id = 1";
            // 3.执行sql
            int count = template.update(sql);
            System.out.println(count);
        }
        
      • 添加一条记录

        /** * 2.添加一条记录 */
        @Test
        public void test2() {
            // 2.定义sql
            String sql = "INSERT INTO emp(id, name, dept_id) VALUES(?, ?, ?)";
            // 3.执行sql
            int count = template.update(sql, 1010, "郭靖", 3);
            System.out.println(count);
        }
        
      • 删除一条记录

        /** * 3.删除一条记录 */
        @Test
        public void test3() {
            // 2.定义sql
            String sql = "DELETE FROM emp WHERE id = ?";
            // 3.执行sql
            int count = template.update(sql, 1010);
            System.out.println(count);
        }
        
      • 查询id为1记录,将其封装为Map集合

        /** * 4.查询id为1的记录,将其封装为Map集合 * 注意:这个方法查询的结果集长度只能是1 */
        @Test
        public void test4() {
            // 2.定义sql
            String sql = "SELECT * FROM emp WHERE id = ?";
            // 3.执行sql
            Map<String, Object> map = template.queryForMap(sql, 1);
            System.out.println(map);
            // {id=1, name=孙悟空, gender=男, salary=10000.0, join_date=2013-02-24, dept_id=1}
        }
        
      • 查询所有的记录,将其封装为List集合

        /** * 5.查询所有的记录,将其封装为List集合 */
        @Test
        public void test5() {
            // 2.定义sql
            String sql = "SELECT * FROM emp";
            // 3.执行sql
            List<Map<String, Object>> list = template.queryForList(sql);
            for (Map<String, Object> stringObjectMap : list) {
                System.out.println(stringObjectMap);
            }
        }
        
      • 查询所有的记录,将其封装为Emp对象的List集合

        /** * 6.查询所有的记录,将其封装为Emp对象的List集合 */
        @Test
        public void test6() {
            // 2.定义sql
            String sql = "SELECT * FROM emp";
            // 3.执行sql
            List<Emp> list = template.query(sql, new RowMapper<Emp>() {
                @Override
                public Emp mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Emp emp = new Emp();
                    int id = rs.getInt("id");
                    String name = rs.getString("name");
                    String gender = rs.getString("gender");
                    double salary = rs.getDouble("salary");
                    Date join_date = rs.getDate(5);
                    int dept_id = rs.getInt(6);
                    emp.setId(id);
                    emp.setName(name);
                    emp.setGender(gender);
                    emp.setSalary(salary);
                    emp.setJoin_date(join_date);
                    emp.setDept_id(dept_id);
                    return emp;
                }
            });
            // 遍历list集合
            for (Emp emp : list) {
                System.out.println(emp);
            }
        }
        
        /** * 6.查询所有的记录,将其封装为Emp对象的List集合 */
        @Test
        public void test6() {
            // 2.定义sql
            String sql = "SELECT * FROM emp";
            // 3.执行sql
            List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
            for (Emp emp : list) {
                System.out.println(emp);
            }
        }
        
      • 查询中的记录数

        /** * 7.查询总记录数 */
        @Test
        public void test7() {
            // 2.定义sql
            String sql = "SELECT COUNT(id) FROM emp";
            // 3.执行sql
            Long total = template.queryForObject(sql, Long.class);
            System.out.println(total);
        }