JDBC总结

JDBC

1.概念


1、JDBC为访问不同的数据库提供了统一的接口,为使用屏蔽了细节问题。

2、Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。

2.原理示意图


image-20220224190752817

3.JDBC程序编写步骤


  • 注册驱动 -加载Driver类
  • 获得连接 -得到Connection
  • 执行增删改查 -发送SQL给MySQL执行
  • 释放资源 -关闭相关连接

4.获取数据库连接的方式


public class JdbcConn {
    
    /**
     * 方式一
     */
    @Test
    public void connect01() throws SQLException {
        //依赖注入 maven就完事了
        //1.注册驱动
        Driver driver = new Driver();

        //2.得到连接
        String url = "jdbc:mysql://localhost:3306/ljt_db01?serverTimezone=GMT%2B8";
        //将 用户名和密码放入到Properties对象
        Properties properties = new Properties();
        //user 和 password 是规定好的
        properties.setProperty("user", "root");// 用户
        properties.setProperty("password", "root");//密码
        Connection connect = driver.connect(url, properties);

        //3.执行sql
        // String sql = "insert into mes values(null,'福建新闻','2022-1-5')";
        String sql = "update mes set content='厦门新闻' where id = 3";
        Statement statement = connect.createStatement();
        int rows = statement.executeUpdate(sql);//如果是dml语句,返回的就是影响行数

        System.out.println(rows > 0 ? "成功" : "失败");

        //4.关闭连接资源
        statement.close();
        connect.close();

    }
    
    
	/**
     * 方式二
     */
    @Test
    public void connect02() throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        //使用反射加载Drive类
        Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();

        //2.得到连接
        String url = "jdbc:mysql://localhost:3306/ljt_db01?serverTimezone=GMT%2B8";
        //将 用户名和密码放入到Properties对象
        Properties properties = new Properties();
        //user 和 password 是规定好的
        properties.setProperty("user", "root");// 用户
        properties.setProperty("password", "root");//密码
        Connection connect = driver.connect(url, properties);

        //3.执行sql
        String sql = "insert into mes values(null,'泉州新闻','2022-1-5')";
        // String sql = "update mes set content='厦门新闻' where id = 3";
        Statement statement = connect.createStatement();
        int rows = statement.executeUpdate(sql);//如果是dml语句,返回的就是影响行数

        System.out.println(rows > 0 ? "成功" : "失败");

        //4.关闭连接资源
        statement.close();
        connect.close();

    }

    /**
     * 方式三
     */
    @Test
    public void connect03() throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        //使用反射加载Drive类
        Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();

        //2.得到连接
        String url = "jdbc:mysql://localhost:3306/ljt_db01?serverTimezone=GMT%2B8";
        String user = "root";
        String password = "root";

        DriverManager.registerDriver(driver);

        Connection connect = DriverManager.getConnection(url, user, password);

        //3.执行sql
        String sql = "insert into mes values(null,'芜湖新闻','2022-1-5')";
        Statement statement = connect.createStatement();
        // dml语句 数据的增删改操作
        int rows = statement.executeUpdate(sql);//如果是dml语句,返回的就是影响行数

        System.out.println(rows > 0 ? "成功" : "失败");

        //4.关闭连接资源
        statement.close();
        connect.close();

    }


    /**
     * 方式四
     */
    @Test
    public void connect04() throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException {

        //2.得到连接
        String url = "jdbc:mysql://localhost:3306/ljt_db01?serverTimezone=GMT%2B8";
        String user = "root";
        String password = "root";
        Connection connect = DriverManager.getConnection(url, user, password);

        //3.执行sql
        String sql = "insert into mes values(null,'广汉新闻','2022-1-5')";
        Statement statement = connect.createStatement();
        // dml语句 数据的增删改操作
        int rows = statement.executeUpdate(sql);//如果是dml语句,返回的就是影响行数

        System.out.println(rows > 0 ? "成功" : "失败");

        //4.关闭连接资源
        statement.close();
        connect.close();

    }

    /**
     * 方式五
     */
    @Test
    public void connect05() throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException, IOException {

        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\main\\resources\\druid.properties"));

        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");

        // String driver = properties.getProperty("driver");
        //

        // 建议加上
        // Class.forName("com.mysql.cj.jdbc.Driver");


        Connection connect = DriverManager.getConnection(url, user, password);

        //3.执行sql
        String sql = "insert into mes values(null,'新疆新闻','2022-1-5')";
        Statement statement = connect.createStatement();
        // dml语句 数据的增删改操作
        int rows = statement.executeUpdate(sql);//如果是dml语句,返回的就是影响行数

        System.out.println(rows > 0 ? "成功" : "失败");

        //4.关闭连接资源
        statement.close();
        connect.close();

    }

}

mysql.properties

user=root
password=root
url=jdbc:mysql://localhost:3306/ljt_db01?serverTimezone=GMT%2B8&rewriteBatchedStatements=true
driver=com.mysql.cj.jdbc.Driver

5.ResultSet结果集合


  • 基本介绍

    1. 表示数据库结果集得数据表,通常通过执行查询数据库的语句生成
    2. ResultSet对象保持一个光标指向当前的数据行。最初,光标位于第一行之前
    3. next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false,因此可以在while循环中使用循环来遍历结果集
  • 应用实例

    /**
     * 演示select 语句返回 ResultSet ,并取出结果
     */
    @SuppressWarnings({"all"})
    public class ResultSet_ {
        public static void main(String[] args) throws Exception {
            //通过Properties对象获取配置文件的信息
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\main\\resources\\druid.properties"));
            //获取相关的值
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            //1. 注册驱动
            Class.forName(driver);//建议写上
            //2. 得到连接
            Connection connection = DriverManager.getConnection(url, user, password);
            //3. 得到Statement
            Statement statement = connection.createStatement();
            //4. 组织SqL
            String sql = "select id, name , sex, borndate from actor";
            //执行给定的SQL语句,该语句返回单个 ResultSet对象
            /*
            +----+-----------+-----+---------------------+
            | id | name      | sex | borndate            |
            +----+-----------+-----+---------------------+
            |  4 | 刘德华    | 男  | 1970-12-12 00:00:00 |
            |  5 | jack      | 男  | 1990-11-11 00:00:00 |
            +----+-----------+-----+---------------------+
             */
            /*
                老韩阅读debug 代码 resultSet 对象的结构
             */
            ResultSet resultSet = statement.executeQuery(sql);
            //5. 使用while取出数据
            while (resultSet.next()) { // 让光标向后移动,如果没有更多行,则返回false
                int id  = resultSet.getInt(1); //获取该行的第1列
                //int id1 = resultSet.getInt("id"); 通过列名来获取值, 推荐
                String name = resultSet.getString(2);//获取该行的第2列
                String sex = resultSet.getString(3);
                Date date = resultSet.getDate(4);
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + date);
            }
            //6. 关闭连接
            resultSet.close();
            statement.close();
            connection.close();
        }
    }
    
    

6.Statement


  • 基本介绍

    1. Statement对象用于执行静态SQL语句并返回其生成的结果的对象
    2. 在连接建立后,需要对数据库进行访问,执行命名或是SQL语句,可以通过Statemt
      • Statement[存在SQL注入]
      • PreparedStatement[预处理]
      • CallableStatement[存储过程]
    3. Statement对象执行SQL语句,存在SQL注入风险
    4. SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库
    5. 要防范SQL注入,只要用PreparedStatement(从Statement扩展而来)取代Statement即可
  • 演示sql注入

    image-20220224194722327

    -- 演示sql 注入
    -- 创建一张表
    CREATE TABLE  admin ( -- 管理员表
    NAME VARCHAR(32) NOT NULL UNIQUE,
    pwd VARCHAR(32) NOT NULL DEFAULT '') CHARACTER SET utf8;
    -- 添加数据
    INSERT INTO admin VALUES('tom', '123');
    -- 查找某个管理是否存在
    SELECT * 
    	FROM admin
    	WHERE NAME = 'tom' AND pwd = '123'
    -- SQL 
    -- 输入用户名 为  1' or 
    -- 输入万能密码 为 or '1'= '1 
    SELECT * 
    	FROM admin
    	WHERE NAME = '1' OR' AND pwd = 'OR '1'= '1'
    SELECT * FROM admin
    
    
    public class Statement_ {
        public static void main(String[] args) throws Exception {
            Scanner scanner = new Scanner(System.in);
            //让用户输入管理员名和密码
            System.out.print("请输入管理员的名字: ");  //next(): 当接收到 空格或者 '就是表示结束
            String admin_name = scanner.nextLine(); // 老师说明,如果希望看到SQL注入,这里需要用nextLine
            System.out.print("请输入管理员的密码: ");
            String admin_pwd = scanner.nextLine();
            //通过Properties对象获取配置文件的信息
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\main\\resources\\druid.properties"));
            //获取相关的值
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            //1. 注册驱动
            Class.forName(driver);//建议写上
            //2. 得到连接
            Connection connection = DriverManager.getConnection(url, user, password);
            //3. 得到Statement
            Statement statement = connection.createStatement();
            //4. 组织SqL
            String sql = "select name , pwd  from admin where name ='"
                    + admin_name + "' and pwd = '" + admin_pwd + "'";
            ResultSet resultSet = statement.executeQuery(sql);
            if (resultSet.next()) { //如果查询到一条记录,则说明该管理存在
                System.out.println("恭喜, 登录成功");
            } else {
                System.out.println("对不起,登录失败");
            }
            //关闭连接
            resultSet.close();
            statement.close();
            connection.close();
        }
    }
    

7.PreparedStatement


  • 基本介绍

    1. PreparedStatement执行的SQL语句中的参数用问好(?)来表示,调用PreparedStatement对象的setXxx()方法来设置这些参数。setXxx()方法有两个参数,第一个是参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值

    2. 调用excuteQuery(),返回ResultSet对象

    3. 调用excuteUpdate:执行更新,包括增、删、修改

  • 预处理好处

    1. 不在使用 + 拼接SQL语句,减少语法错误
    2. 有效的解决了sql注入问题
    3. 大大减少了编译次数,效率较高
  • 应用案例

    /**
     * 演示PreparedStatement使用
     */
    @SuppressWarnings({"all"})
    public class PreparedStatement_ {
        public static void main(String[] args) throws Exception {
            //看 PreparedStatement类图
            Scanner scanner = new Scanner(System.in);
            //让用户输入管理员名和密码
            System.out.print("请输入管理员的名字: ");  //next(): 当接收到 空格或者 '就是表示结束
            String admin_name = scanner.nextLine(); // 老师说明,如果希望看到SQL注入,这里需要用nextLine
            System.out.print("请输入管理员的密码: ");
            String admin_pwd = scanner.nextLine();
            //通过Properties对象获取配置文件的信息
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\main\\resources\\druid.properties"));
            //获取相关的值
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            //1. 注册驱动
            Class.forName(driver);//建议写上
            //2. 得到连接
            Connection connection = DriverManager.getConnection(url, user, password);
            //3. 得到PreparedStatement
            //3.1 组织SqL , Sql 语句的 ? 就相当于占位符
            String sql = "select name , pwd  from admin where name =? and pwd = ?";
            //3.2 preparedStatement 对象实现了 PreparedStatement 接口的实现类的对象
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            //3.3 给 ? 赋值
            preparedStatement.setString(1, admin_name);
            preparedStatement.setString(2, admin_pwd);
            //4. 执行 select 语句使用  executeQuery
            //   如果执行的是 dml(update, insert ,delete) executeUpdate()
            //   这里执行 executeQuery ,不要再写 sql
            ResultSet resultSet = preparedStatement.executeQuery(sql);
            if (resultSet.next()) { //如果查询到一条记录,则说明该管理存在
                System.out.println("恭喜, 登录成功");
            } else {
                System.out.println("对不起,登录失败");
            }
            //关闭连接
            resultSet.close();
            preparedStatement.close();
            connection.close();
        }
    }
    
    /**
     * 演示PreparedStatement使用 dml语句
     */
    @SuppressWarnings({"all"})
    public class PreparedStatementDML_ {
        public static void main(String[] args) throws Exception {
            //看 PreparedStatement类图
            Scanner scanner = new Scanner(System.in);
            //让用户输入管理员名和密码
            System.out.print("请输删除管理员的名字: ");  //next(): 当接收到 空格或者 '就是表示结束
            String admin_name = scanner.nextLine(); // 老师说明,如果希望看到SQL注入,这里需要用nextLine
    //        System.out.print("请输入管理员的新密码: ");
    //        String admin_pwd = scanner.nextLine();
            //通过Properties对象获取配置文件的信息
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\main\\resources\\druid.properties"));
            //获取相关的值
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            //1. 注册驱动
            Class.forName(driver);//建议写上
            //2. 得到连接
            Connection connection = DriverManager.getConnection(url, user, password);
            //3. 得到PreparedStatement
            //3.1 组织SqL , Sql 语句的 ? 就相当于占位符
            //添加记录
            //String sql = "insert into admin values(?, ?)";
            //String sql = "update admin set pwd = ? where name = ?";
            String sql = "delete from  admin where name = ?";
            //3.2 preparedStatement 对象实现了 PreparedStatement 接口的实现类的对象
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            //3.3 给 ? 赋值
            preparedStatement.setString(1, admin_name);
            //preparedStatement.setString(2, admin_name);
            //4. 执行 dml 语句使用  executeUpdate
            int rows = preparedStatement.executeUpdate();
            System.out.println(rows > 0 ? "执行成功" : "执行失败");
            //关闭连接
            preparedStatement.close();
            connection.close();
        }
    }
    

8.封装JDBC


JDBCUtils

/**
 * 这是一个工具类,完成 mysql的连接和关闭资源
 */
public class JDBCUtils {
    //定义相关的属性(4个), 因为只需要一份,因此,我们做出static
    private static String user; //用户名
    private static String password; //密码
    private static String url; //url
    private static String driver; //驱动名
    //在static代码块去初始化
    static {
        try {
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\main\\resources\\druid.properties"));
            //读取相关的属性值
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driver = properties.getProperty("driver");
        } catch (IOException e) {
            //在实际开发中,我们可以这样处理
            //1. 将编译异常转成 运行异常
            //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
            throw new RuntimeException(e);
        }
    }
    //连接数据库, 返回Connection
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            //1. 将编译异常转成 运行异常
            //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
            throw new RuntimeException(e);
        }
    }
    //关闭相关资源
    /*
        1. ResultSet 结果集
        2. Statement 或者 PreparedStatement
        3. Connection
        4. 如果需要关闭资源,就传入对象,否则传入 null
     */
    public static void close(ResultSet set, Statement statement, Connection connection) {
        //判断是否为null
        try {
            if (set != null) {
                set.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            //将编译异常转成运行异常抛出
            throw new RuntimeException(e);
        }
    }
}

JDBCUtils_Use

/**
 * 该类演示如何使用JDBCUtils工具类,完成dml 和 select
 */
public class JDBCUtils_Use {
    @Test
    public void testSelect() {
        //1. 得到连接
        Connection connection = null;
        //2. 组织一个sql
        String sql = "select * from actor where id = ?";
        PreparedStatement preparedStatement = null;
        ResultSet set = null;
        //3. 创建PreparedStatement 对象
        try {
            connection = JDBCUtils.getConnection();
            System.out.println(connection.getClass()); //com.mysql.jdbc.JDBC4Connection
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 5);//给?号赋值
            //执行, 得到结果集
            set = preparedStatement.executeQuery();
            //遍历该结果集
            while (set.next()) {
                int id = set.getInt("id");
                String name = set.getString("name");
                String sex = set.getString("sex");
                Date borndate = set.getDate("borndate");
                String phone = set.getString("phone");
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(set, preparedStatement, connection);
        }
    }
    @Test
    public void testDML() {//insert , update, delete
        //1. 得到连接
        Connection connection = null;
        //2. 组织一个sql
        String sql = "update actor set name = ? where id = ?";
        // 测试 delete 和 insert ,自己玩.
        PreparedStatement preparedStatement = null;
        //3. 创建PreparedStatement 对象
        try {
            connection = JDBCUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            //给占位符赋值
            preparedStatement.setString(1, "周星驰");
            preparedStatement.setInt(2, 4);
            //执行
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }
}

9.事务


  • 基本介绍

    1. JDBC程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
    2. JDBC程序中为了让多个SQL语句作为一个整体执行,需要使用事务
    3. 调用Connection的setAutoCommit(false)可以取消自动提交事务
    4. 在所有的SQL语句都成功执行后,调用Connection的commit();方法提交事务
    5. 在其中某个操作失败或出现异常时,调用Connection的rollback();方法回滚事务
  • 应用实例
    请添加图片描述

    /** * 演示jdbc 中如何使用事务 */public class Transaction_ {    //没有使用事务.    @Test    public void noTransaction() {        //操作转账的业务        //1. 得到连接        Connection connection = null;        //2. 组织一个sql        String sql = "update account set balance = balance - 100 where id = 1";        String sql2 = "update account set balance = balance + 100 where id = 2";        PreparedStatement preparedStatement = null;        //3. 创建PreparedStatement 对象        try {            connection = JDBCUtils.getConnection(); // 在默认情况下,connection是默认自动提交            preparedStatement = connection.prepareStatement(sql);            preparedStatement.executeUpdate(); // 执行第1条sql            int i = 1 / 0; //抛出异常            preparedStatement = connection.prepareStatement(sql2);            preparedStatement.executeUpdate(); // 执行第3条sql        } catch (SQLException e) {            e.printStackTrace();        } finally {            //关闭资源            JDBCUtils.close(null, preparedStatement, connection);        }    }    //事务来解决    @Test    public void useTransaction() {        //操作转账的业务        //1. 得到连接        Connection connection = null;        //2. 组织一个sql        String sql = "update account set balance = balance - 100 where id = 1";        String sql2 = "update account set balance = balance + 100 where id = 2";        PreparedStatement preparedStatement = null;        //3. 创建PreparedStatement 对象        try {            connection = JDBCUtils.getConnection(); // 在默认情况下,connection是默认自动提交            //将 connection 设置为不自动提交            connection.setAutoCommit(false); //开启了事务            preparedStatement = connection.prepareStatement(sql);            preparedStatement.executeUpdate(); // 执行第1条sql            int i = 1 / 0; //抛出异常            preparedStatement = connection.prepareStatement(sql2);            preparedStatement.executeUpdate(); // 执行第2条sql            //这里提交事务            connection.commit();        } catch (SQLException e) {            //这里我们可以进行回滚,即撤销执行的SQL            //默认回滚到事务开始的状态.            System.out.println("执行发生了异常,撤销执行的sql");            try {                connection.rollback();            } catch (SQLException throwables) {                throwables.printStackTrace();            }            e.printStackTrace();        } finally {            //关闭资源            JDBCUtils.close(null, preparedStatement, connection);        }    }}
    

10.批处理


  • 基本介绍

    1. 当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。

    2. JDBC的批量处理语句包括下面方法:

      • addBatch(): 添加需要批量处理的SQL语句或参数
      • excuteBath(): 执行批量处理语句
      • clearBatch(): 清空批处理包的语句
    3. JDBC连接MySQL时,如果要使用批批处理功能,要在url中加参数rewriteBatchedStatements=true

    4. 批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高

  • 操作实例
    请添加图片描述

  /**
   * 演示jdbc 中如何使用事务
   */
  public class Transaction_ {
      //没有使用事务.
      @Test
      public void noTransaction() {
          //操作转账的业务
          //1. 得到连接
          Connection connection = null;
          //2. 组织一个sql
          String sql = "update account set balance = balance - 100 where id = 1";
          String sql2 = "update account set balance = balance + 100 where id = 2";
          PreparedStatement preparedStatement = null;
          //3. 创建PreparedStatement 对象
          try {
              connection = JDBCUtils.getConnection(); // 在默认情况下,connection是默认自动提交
              preparedStatement = connection.prepareStatement(sql);
              preparedStatement.executeUpdate(); // 执行第1条sql
              int i = 1 / 0; //抛出异常
              preparedStatement = connection.prepareStatement(sql2);
              preparedStatement.executeUpdate(); // 执行第3条sql
          } catch (SQLException e) {
              e.printStackTrace();
          } finally {
              //关闭资源
              JDBCUtils.close(null, preparedStatement, connection);
          }
      }
      //事务来解决
      @Test
      public void useTransaction() {
          //操作转账的业务
          //1. 得到连接
          Connection connection = null;
          //2. 组织一个sql
          String sql = "update account set balance = balance - 100 where id = 1";
          String sql2 = "update account set balance = balance + 100 where id = 2";
          PreparedStatement preparedStatement = null;
          //3. 创建PreparedStatement 对象
          try {
              connection = JDBCUtils.getConnection(); // 在默认情况下,connection是默认自动提交
              //将 connection 设置为不自动提交
              connection.setAutoCommit(false); //开启了事务
              preparedStatement = connection.prepareStatement(sql);
              preparedStatement.executeUpdate(); // 执行第1条sql
              int i = 1 / 0; //抛出异常
              preparedStatement = connection.prepareStatement(sql2);
              preparedStatement.executeUpdate(); // 执行第2条sql
              //这里提交事务
              connection.commit();
          } catch (SQLException e) {
              //这里我们可以进行回滚,即撤销执行的SQL
              //默认回滚到事务开始的状态.
              System.out.println("执行发生了异常,撤销执行的sql");
              try {
                  connection.rollback();
              } catch (SQLException throwables) {
                  throwables.printStackTrace();
              }
              e.printStackTrace();
          } finally {
              //关闭资源
              JDBCUtils.close(null, preparedStatement, connection);
          }
      }
  }
  

11.数据库连接池


  • 传统获取Connection问题分析

    1. 传统的JDBC数据库连接使用DriverManager来获取,每次像数据库建立连接的时候都要将Connection加载到内存中,再验证

      IP地址用户名密码(0.05~1s时间)。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据连接操作将占用很多的

      系统资源,容易造成服务器崩溃。

    2. 每一次数据库连接,使用完后都得断开,如果程序出现异常而未能关闭,将导致数据库内存泄漏,最终将导致重启数据库。

    3. 传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致内存泄漏,MySQL崩溃。

    4. 解决传统开发中的数据库连接问题,可以采用数据库连接池技术(connection pool)

  • 数据库连接池基本介绍

    1. 预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。

    2. 数据库连接池负责分配,管理和释放数据库连接,他允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。

    3. 当应用程序像连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

  • 数据库连接池种类

    1. JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方提供实现。

    2. C3P0数据库连接池,速度相对较慢,稳定性不错

    3. DBCP数据库连接池,速度相对C3P0较快,但不稳定

    4. Proxool数据库连接池,有监控连接池状态的功能,稳定性较C3P0差一点

    5. BoneCP数据库连接池,速度快

    6. Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3P0、Proxool优点于一身的数据库连接池

  • 德鲁伊连接池

    • 工具类
    public class JDBCUtilsByDruid {
    
        private static DataSource ds;
    
        //在静态代码块完成 ds初始化
        static {
            Properties properties = new Properties();
            try {
                properties.load(new FileInputStream("src\\main\\resources\\druid.properties"));
                ds = DruidDataSourceFactory.createDataSource(properties);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //编写getConnection方法
        public static Connection getConnection() throws SQLException {
            return ds.getConnection();
        }
    
        //关闭连接
        public static void close(ResultSet resultSet, Statement statement,Connection connection){
    
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                //编译异常转成运行异常抛出
                throw new RuntimeException(e);
            }
        }
    }
    
    • properties配置文件
    driverClassName=com.mysql.cj.jdbc.Driver
    #URL连接数据库的URL,其中travel(以下面例子来说)为连接的数据库,后面的参数可不改但不删
    url=jdbc:mysql://localhost:3306/ljt_db01?serverTimezone=GMT%2B8
    characterEncoding=utf-8
    #安装mysql时候设置的用户与密码
    username=root
    password=root
    #初始化物理连接的个数
    initialSize=5
    #最大连接池数量
    maxActive=10
    #获取连接时最大等待时间
    maxWait=3000
    #用来检测连接是否有效的sql
    validationQuery=SELECT 1
    #保证安全性!
    testWhileIdle=true
    

12.Apache-DBUtils


  • 基本介绍

    commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的封装使用dbutils能极大简化jdbc编码的工作量。

  • DbUtils类

    1. QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理

    2. 使用QueryRunner类实现查询

    3. ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式。

      API作用
      ArrayHandler把结果集中的第一行数据库转换成对象数据
      ArrayListHandler把结果集中的每一行数据都转成一个数据,再存放到List中
      BeanHandler将结果集中的第一行数据封装到一个对应的JavaBean实例中
      BeanListHandler将结果集中的每一行数据都封装到一个对相应的JavaBean实例中,存放到List里
      ColumnListHandler将结果集中某一列的数据存放到List中
      KeyedHandler(name)将结果集合中的每行数据都封装到Map,再把这些map再存到一个map里,其key为指定的key
      MapHandler将结果集中的第一行数据风爪给你到一个Map里,key是列名,value就是对应的值
      MapListHandler将结果集中的每一行数据都封装到一个Map里,然后再存放到List
  • 引入依赖

    <dependency>
       <groupId>commons-dbutils</groupId>
       <artifactId>commons-dbutils</artifactId>
       <version>1.7</version>
    </dependency>
    
  • 编写工具类

    public class JDBCUtilsByDruid {
    
        private static DataSource ds;
    
        //在静态代码块完成 ds初始化
        static {
            Properties properties = new Properties();
            try {
                properties.load(new FileInputStream("src\\main\\resources\\druid.properties"));
                ds = DruidDataSourceFactory.createDataSource(properties);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //编写getConnection方法
        public static Connection getConnection() throws SQLException {
            return ds.getConnection();
        }
    
        //关闭连接
        public static void close(ResultSet resultSet, Statement statement,Connection connection){
    
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                //编译异常转成运行异常抛出
                throw new RuntimeException(e);
            }
        }
    }
    

13.DAO和增删改查通用方法-BasicDao


public class BasicDao<T> {

    /**
     *
     */
    private QueryRunner qr = new QueryRunner();

    //开发通用的dml方法,针对任意的表
    public int update(String sql, Object... parameters) {

        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            int update = qr.update(connection, sql, parameters);
            return update;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }

    }

    //返回多个对象<即查询的结果是多行>,针对任意表
    public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters) {
        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            List<T> query = qr.query(connection, sql, new BeanListHandler<T>(clazz), parameters);
            return query;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }

    //查询单行结果 的通用方法
    public T querySingle(String sql, Class<T> clazz, Object... parameters) {
        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            T query = qr.query(connection, sql, new BeanHandler<T>(clazz), parameters);
            return query;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }

    // 查询单个结果
    public Object queryScalar(String sql, Object... parameters) {
        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection, sql, new ScalarHandler(), parameters);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J.T.L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值