1、简单认识一下JDBC

  • 1)、JDBC是什么?
    • java database connection       java数据库连接
    • 作用:就是为了java连接mysql数据库嘛
    • 要详细的,就面向百度编程吧
  • 2)、JDBC是一种驱动,那么它位于哪个地方?


  • 3)、JDBC的实现  ———— 五步骤

    • 加载驱动
    • 获取连接   driverManager
    • 获取执行sql的对象  statement / PreparedStatement
    • 获取结果集  resultSet
    • 释放资源
        • 再来数据库创建一个数据库 和 表

          • CREATE DATABASE IF NOT EXISTS jdbc;
            
            USE jdbc;
            
            CREATE TABLE IF NOT EXISTS person(
            id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
            `name` VARCHAR(20) NOT NULL,
            sex CHAR(2) NOT NULL,
            age INT NOT NULL
            )ENGINE = INNODB DEFAULT CHARSET = utf8; INSERT INTO person
            VALUES( NULL , '紫邪情' , '女' , '18' ),
            ( NULL , '君莫邪' , '男' , '19' ),
            ( NULL , '张雪' , '女' , '19' ),
            ( NULL , '韩非' , '男' , '19' );
        • 然后把下载的JDBC弄到java项目中去 

          •  标记文件类型

            •  标记成功之后jar包前面有一个 > 符号

      • (2)、利用五步骤。开始测试

        • package cn.xieGongZi.test;
          
          import java.sql.*;
          
          public class PlayJDBC {
          
              public static void main(String[] args) throws ClassNotFoundException, SQLException {
          
                  // 1、加载驱动 利用了反射
          Class.forName("com.mysql.jdbc.Driver"); // 这个是死的 这里为了看逻辑,所以把异常抛出 /*
          * jdbc:mysql: 是指协议 这是固定写法
          * localhost 是主机地址 这里使用127.0.0.1也可以,要是想连接别人电脑上的数据库,这里把ip地址换了就可以了
          * 3306 指:sql的端口号
          * jdbc 就是要链接的数据库
          * ? 表示要跟参数 即:? 后面的就是参数
          * characterEncoding 指:设置字符编码 其他的参数都可以少,这个最好别少
          * useUnicode 使用Unicode编码格式
          * useSSL 使用安全套接层协议 即:安全连接
          *
          * 因此:这个url的写法就出来了:
          * 协议 : // 主机地址 : 端口号 / 数据库名 ? 参数
          * */
          String url = "jdbc:mysql://localhost:3306/jdbc? characterEncoding = utf-8 && useUnicode = true && useSSL = true";
          String username = "root"; // 这是数据库的用户名
          String password = "072413"; // 这是数据库的密码 要操作数据库肯定要登进去涩,所以:路径是什么?用户名和密码时什么肯定需要告知嘛 // 2、获取连接 使用DriverManager 这是java.sql包下的
          Connection con = DriverManager.getConnection(url, username, password);
          // 发现这个getConnection需要三个参数 url 、 username 、 password,所以建一下,需要处理异常,为了好看逻辑,照样跑出去 // 3、通过链接对象 去 获取执行sql的对象
          Statement st = con.createStatement(); String sql = "select * from person"; // 在这个地方有些人可能会出现 表名 识别不了 那就用 库名.表名 如:jdbc.person
          // 这里进行查询操作 注:在java中, 增删改 是executeUpdate( String sql )方法 查询是executeQuery( String sql )方法
          // 4、执行sql,获取结果集
          ResultSet rs = st.executeQuery(sql); // 发现这个方法需要一个sql , 那么编写一句 // sql语句弄好了,结果集resultSet也得到了,但是看名字就知道ResultSet肯定是一个容器嘛,所以得把结果拿出来涩
          // 使用一个方法 next() 这是看下一行是否有数据 怎么理解呢?
          // 就是去读写数据时,有一个指针,这个指针是指向数据库表的表头的,即:列字段哪一行 什么name、age、sex....这一行
          // 所以:去一行一行读写时,是看下一行是否有数据
          while ( rs.next() ){ // 当然:要是数据只有一行的话 用个if就可以了
          System.out.print( rs.getInt("id") + " " );
          System.out.print( rs.getString("name") + " " );
          System.out.print( rs.getString("sex") + " " );
          System.out.println( rs.getInt("age") + " " );
          } // 5、释放资源 ———— 倒着关闭
          if ( rs != null ){ // 在这里这个if不要都行,为了后续代码的健壮性,严谨,所以这里加了一个判断罢了
          rs.close();
          } if ( st != null ){
          st.close();
          } if ( con != null ){
          con.close();
          } }
          }

效果如下( 成功从数据库中拿到数据了 ):

  • 对JDBC的总结和补充

    • JDBC的步骤

      • 加载驱动   Class.forName("com.mysql.jdbc.Driver");
      • 获取连接   Connection con = DriverManager.getConnection( String url , String username , String password );
      • 获取执行sql的对象   Statement st = con.CreateStatement();
      • 获取结果集 / 获取受影响的行数( 这个是增删改的时候的结果 )    ResultSet rs = st.executeQuery( String sql );    增删改就是executeUpdate( String sql )
      • 释放资源     close()
    • 对一些方法的补充:

      • Connection中常用的方法

        • 这就是一个连接对象嘛,它代表的就是数据库。所以它可以设置数据库中的任何东西

          • rollback   回滚
          • autocommit   自动提交
          • commit          提交事务
          • createStatement     创建执行sql的对象     —— 提前讲一下:这个对象不安全
          • preparedStatement    这个也是创建执行sql的对象           ———— 这个更安全,后续会说明
          • close                         关闭连接
          • 其他的方法      直接通过 Connection.  之后就可以看到它所有的方法了
      • Statement中常用方法

        • executeQuery          执行sql查询语句         返回的是一个结果集 ResultSet
        • executeUpdate        执行sql增 / 删 / 改 语句     返回的是受影响的行数
        • execute                    执行任何的sql语句
        • close                        关闭资源
      • ResultSet中常用方法

        • getObject                在不知道数据库中字段的类型时采用,获取任意类型嘛
        • 获取对应类型
          • getString
          • getInt
          • getDouble
          • ........
        • 移动指针
          • beforeFirst     移动到最前面   即:表头的位置
          • afterLast         移动到最后面   即:数据的最后一行
          • next                 移动到下一行数据
          • previous         移动到前一行数据
          • absolute( int row )      移动到指定行
        • 关闭资源
          • close
  • 4)、JDBC的封装

    • 为什么需要封装?

      • 前面那个JDBC五步骤是固定的,那么每有一个类需要进行操作数据库时不得都要写一次吗,那里面有很多共同的代码,只有个别不同而已,所以:不就可以提取成一个工具类吗
    • (1)、自己进行的封装

      • ①、简单封装

        • 加入实体类 —— 即:sql中的一张表对应java中的一个实体类    实体类的包名为 pojo / vo / entity 都可以


        • package cn.xieGongZi.pojo;
          
          // 加入对应数据库中的列字段 成为 属性
          // 加入get 和 set 方法
          // 加入toString方法 public class Person { private int id;
          private String name;
          private String sex;
          private int age; @Override
          public String toString() {
          return "Person{" +
          "id=" + id +
          ", name='" + name + '\'' +
          ", sex='" + sex + '\'' +
          ", age=" + age +
          '}';
          } public Person() {
          } public Person(int id, String name, String sex, int age) {
          this.id = id;
          this.name = name;
          this.sex = sex;
          this.age = age;
          } 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 getSex() {
          return sex;
          } public void setSex(String sex) {
          this.sex = sex;
          } public int getAge() {
          return age;
          } public void setAge(int age) {
          this.age = age;
          } }

          实体类完毕!

        • 封装JDBC

          • 建一个utils包


          • 开始封装JDBC

            • package cn.xieGongZi.utils;
              
              import java.sql.*;
              
              public class JDBCUtils {
              
                  private static String url;
              private static String username;
              private static String password; static { try {
              // 加载驱动
              Class.forName("com.mysql.jdbc.Driver"); // 编写url、username、password
              url = "jdbc:mysql://localhost:3306/jdbc?characterEncoding = utf-8 && useUnicode = true && useSSL = true ";
              username = "root";
              password = "072413";
              } catch (ClassNotFoundException e) {
              e.printStackTrace();
              } } // 1、设置获取链接方法
              public static Connection getConnection() throws SQLException {
              return DriverManager.getConnection( url , username , password );
              } // 2、封装释放资源方法
              public static void release(Connection con , Statement st , ResultSet rs ){
              if ( rs != null ){
              try {
              rs.close();
              } catch (SQLException e) {
              e.printStackTrace();
              }
              } if ( st != null ){
              try {
              st.close();
              } catch (SQLException e) {
              e.printStackTrace();
              }
              } if ( con != null ){
              try {
              con.close();
              } catch (SQLException e) {
              e.printStackTrace();
              }
              }
              } // 3、在这里 再把增删改 和 查询方法封装起来也行 目前不演示了
              }
          • 通过加入实体类,测试封装的JDBC

            • 编写数据操作层

              • package cn.xieGongZi.dao;
                
                import cn.xieGongZi.pojo.Person;
                import cn.xieGongZi.utils.JDBCUtils; import java.sql.Connection;
                import java.sql.ResultSet;
                import java.sql.SQLException;
                import java.sql.Statement;
                import java.util.ArrayList;
                import java.util.List; public class PersonDao { public List<Person> getAllPerson(){ // 创建一个集合 用来装查询的结果 从情况来看:ArrayList集合更适合 因为:有可能查出来的数据有重复的、而且最好有序
                ArrayList<Person> list = new ArrayList<>(); // 1、加载驱动、获取链接已经在工具类中封装了 所以:直接拿来用
                Connection con = null; // 提示作用域 因为:放在try里面的话,在后面释放资源哪里拿不到这三个参数
                Statement st = null;
                ResultSet rs = null;
                try {
                con = JDBCUtils.getConnection(); // 2、获取操作执行sql的对象
                st = con.createStatement(); // 编写sql语句
                String sql = "select id , `name` , sex , age from person"; // 3、执行sql语句 , 获得结果集
                rs = st.executeQuery(sql); // 加入了实体类 所以:需要把结果集中的数据 弄到 实体类中去
                // 所以:还得有个实体类诶
                Person people = new Person();
                while ( rs.next() ){ // 遍历结果集 准备把数据 放到 实体类中
                people.setId( rs.getInt("id") );
                people.setName( rs.getString("name") );
                people.setSex( rs.getString("sex") );
                people.setAge( rs.getInt("age") ); // 最后:把people 装到 list集合中去 一开始玩这一步不要都行
                // 只是:这里是为了给后面的三层架构打基础
                list.add( people );
                } } catch (SQLException e) {
                e.printStackTrace();
                }finally{
                JDBCUtils.release( con , st , rs ); // 释放资源 有null的,在JDBCUtils中会自行判断
                } return list; // 这里返回,然后在其他地方也就可以拿到这个结果了
                }
                }
            • 测试一下:

          • ②、上面的封装还是麻烦,不太满意,那就再来封装

            • 一样的,先建好对应的包 写好对应的东西:实体类  当然:不用我这么建也可以,根据自己想法来

            • 在玩javaSE的集合时,不是弄过一个hashtable的儿子 —— Properties吗,来用一下它

            • 继续封装JDBC 

              • package cn.xieGongZi.utils;
                
                import java.io.IOException;
                import java.io.InputStream;
                import java.sql.*;
                import java.util.Properties; public class JDBCUtil { // 把driver、url、username、password放到了properties中了,那么就加载出来
                private static String driver;
                private static String url;
                private static String username;
                private static String password; static {
                // 通过类加载器加载出db.properties —— 输入流嘛
                InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/db.properties"); // 创建一个properties对象
                Properties ppt = new Properties(); // 把流管道中的东西加载到properties中来
                try {
                ppt.load(in); // 把装到properties中的东西 获取出来
                driver = ppt.getProperty("driver");
                url = ppt.getProperty("url");
                username = ppt.getProperty("username");
                password = ppt.getProperty("password"); // 顺便做一件事情:加载驱动
                Class.forName( driver );
                } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
                }
                } // 1、封装获取数据库链接对象的方法 这样别人只需要用我提供的其他方法即可
                private static Connection getConnection() throws SQLException {
                return DriverManager.getConnection( url , username , password );
                } // 2、提供释放资源的方法
                public static void release(Connection con , Statement st , ResultSet rs ){
                if ( rs != null ){
                try {
                rs.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                } if ( st != null ){
                try {
                st.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                } if ( con != null ){
                try {
                con.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                }
                } // 3、把增删改的方法也封装了
                public static int update( String sql ) throws SQLException { // 原生的JDBC在增删改语句执行之前做了什么? // 1、加载驱动 —— 前面已经做了 // 2、获取数据库链接对象 —— 前面封装了 所以直接拿来用
                Connection con = getConnection();// 异常抛出去 // 3、通过数据库链接对象 获取 执行sql的对象
                Statement st = con.createStatement(); // 4、执行sql 得到受影响的行数
                int rowCounts = st.executeUpdate(sql); return rowCounts; // 这里可以一步到位:return st.executeUpdate( sql ) ;
                } // 4、继续封装 把查询方法也封装了
                public static ResultSet query( String sql ) throws SQLException { // 前面都是一样的涩 复制过来
                // 原生的JDBC在增删改语句执行之前做了什么? // 1、加载驱动 —— 前面已经做了 // 2、获取数据库链接对象 —— 前面封装了 所以直接拿来用
                Connection con = getConnection();// 异常抛出去 // 3、通过数据库链接对象 获取 执行sql的对象
                Statement st = con.createStatement(); // 4、执行sql 返回结果集
                return st.executeQuery(sql); } }
            • 封装好了,那来测试一下

              • 编写数据操作层 即:dao层

                • package cn.xieGongZi.dao;
                  
                  import cn.xieGongZi.pojo.Person;
                  import cn.xieGongZi.utils.JDBCUtil; import java.sql.Connection;
                  import java.sql.ResultSet;
                  import java.sql.SQLException;
                  import java.sql.Statement;
                  import java.util.ArrayList;
                  import java.util.List; public class Persondao { public List<Person> getAllPerson() { ArrayList<Person> list = new ArrayList<>(); // 原生JDBC前面做了什么? // 1、加载驱动 —— 在JDBC工具类中已经封装了 // 2、获取数据库链接对象 ———— 还是在JDBC中封装了 这里可用可不用 —— 看封装增删查改方法的过程
                  // 我在增删查改中是直接调用了 getConnection() 不是当参数传进去了,所以:这里直接不用调,因为:增删改查中调用了 // 编写sql语句
                  String sql = " select id , `name` , sex , age from person";
                  // 3、获取执行sql的对象 返回结果集 —— 封装了 直接调用
                  ResultSet rs = null;
                  Statement st = null;
                  Connection con = null;
                  try {
                  rs = JDBCUtil.query(sql); // 拿到结果集了 那么把结果集中的数据放到list集合中
                  // 还是需要一个Person实体类对象
                  Person person = new Person();
                  while ( rs.next() ){
                  person.setId( rs.getInt("id") );
                  person.setName( rs.getString("name") );
                  person.setSex( rs.getString("sex") );
                  person.setAge( rs.getInt("age") ); // 把person放到list中 这样就可以在其他地方也拿到了
                  list.add( person );
                  }
                  } catch (SQLException e) {
                  e.printStackTrace();
                  }finally {
                  // 最后释放资源
                  JDBCUtil.release( con , st , rs ); // 发现这里拿不到ResultSet 那么提升作用域
                  // 发现需要Connection 、 Statement对象,那就创建一下,让它等于null 这样在JDBCUtil中会自行判断
                  } return list;
                  }
                  }
                • 效果如下:

                • 最后:这你妹嘞个巴子滴,和前面的封装不是一样的吗?

                  • 不一样,这种是建议用的一种( 是抛开后面用的连接池啊 ),因为这种速度更快一点,以及分工更明确一点( 更像编程思维嘛 )
          • ③、前面都是用的Statement这个执行sql的对象,但是:一开始我便提过一点 这个对象不安全,因为:它不能防止SQL注入

            • SQL注入是什么意思?

              • 简单理解就是:这是SQL的一个漏洞,别人在攻击数据库时,可以通过逻辑正确,但非法的方式进入到数据库中,从而导致:数据泄露
            • 来体验一下

              • 一样的,把对应的包创建好

              • 简单模仿一下登录业务流程

                • 建一下表、并插入数据

                  • CREATE TABLE IF NOT EXISTS `user`(
                    username VARCHAR(20) NOT NULL,
                    `password` VARCHAR(10) NOT NULL
                    )ENGINE = INNODB DEFAULT CHARSET = utf8; INSERT INTO `user` VALUES( '紫邪情' , '072413' ),
                    ( '君莫邪' , '123456' ),
                    ( '韩非' , '774931' ) 

                                               

                • package cn.xieGongZi.test;
                  
                  import cn.xieGongZi.utils.JDBCUtil;
                  
                  import java.sql.Connection;
                  import java.sql.ResultSet;
                  import java.sql.SQLException;
                  import java.sql.Statement; public class Demo { public static void login( String username , String password ){ // 编写sql
                  String sql = " select * from `user` where username = ' "+username+" ' and password = ' "+password+" ' ";
                  // 因为转义字符的关系 所以:这里的' "+usernmae+" ' 在外面加了一个 `` 飘字符 // 执行sql 获得结果集
                  Connection con = null; // 提升作用域
                  Statement st = null;
                  ResultSet rs = null;
                  try {
                  rs = JDBCUtil.query(sql); while ( rs.next() ){ System.out.println( rs.getString("username") );
                  System.out.println( rs.getString("password") );
                  }
                  } catch (SQLException e) {
                  e.printStackTrace();
                  }finally {
                  JDBCUtil.release( con , st , rs );
                  }
                  } // 测试一下
                  public static void main(String[] args) { // 模仿一下登录业务流程
                  // 前面第二种封装就是使用的Statement对象
                  login( " 'or' 1=1 " , " 'or' 1=1 "); // 这里使用逻辑正确,但是:违法的技巧
                  }
                  }
                • 效果如下:

                  • 成功达到目的,因此:Statement不建议使用,不安全,最好使用我接下来要说明的这个对象 PreparedStatement。
                  • 当然:要是有人整 —— 我前面用的db.properties中有数据库用户名 和 密码,所以可以做到,那就别扯了,这是两码事儿。
                  • 因此:要是有人说用statement这个执行sql语句的对象的话,那他就是个草包,听都别听他鬼扯。
            • PreparedStatement对象  —— 预编译对象

              • 前面的流程都一样 使用 添加实体类 、 db.properties  所以不演示了,主要从封装JDBC开始,把Statement对象换了
              • JDBC的封装
              • package cn.xieGongZi.utils;
                
                import java.io.IOException;
                import java.io.InputStream;
                import java.sql.*;
                import java.util.Properties; public class JDBCUtil { private static String driver;
                private static String url;
                private static String username;
                private static String password; static { InputStream ins = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/db.properties"); Properties ppt = new Properties();
                try {
                ppt.load( ins ); driver = ppt.getProperty("driver");
                url = ppt.getProperty("url");
                username = ppt.getProperty("username");
                password = ppt.getProperty("password"); Class.forName(driver);
                } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
                }
                } // 封装获取数据库链接对象
                public static Connection getConnection() throws SQLException {
                return DriverManager.getConnection(url, username, password);
                } // 提供释放资源的方法
                public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象 if ( rs != null ){
                try {
                rs.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                } if ( ps != null ){
                try {
                ps.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                } if ( con != null ){
                try {
                con.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                }
                } }
            • 数据操作层
              • package cn.xieGongZi.dao;
                
                import cn.xieGongZi.pojo.Person;
                import cn.xieGongZi.utils.JDBCUtil; import java.sql.Connection;
                import java.sql.PreparedStatement;
                import java.sql.ResultSet;
                import java.sql.SQLException;
                import java.util.ArrayList;
                import java.util.List; public class PersonDao { public List<Person> getAllPerson() { ArrayList<Person> list = new ArrayList<>(); // 提升作用域
                Connection con = null;
                PreparedStatement ps = null; // 使用preparedStatement对象
                ResultSet rs = null; // 还是一样 获取链接
                try {
                con = JDBCUtil.getConnection(); // 编写sql语句
                // 因为:使用的是preparedStatement对象,所以这里有点区别
                String sql = " select * from person where `name` = ? "; // 使用占位符 ? 来代替要赋的值 在后面再给它赋值 // 执行sql
                ps = con.prepareStatement(sql);
                // 对占位符进行赋值
                ps.setString(1,"紫邪情"); // 这表示给第一个参数( 即:? ),有多个的话,数值依次往后,跟着赋值即可
                // 现在再开始执行sql 得到结果集
                rs = ps.executeQuery(); Person people = new Person(); while ( rs.next() ){
                people.setId( rs.getInt("id"));
                people.setName( rs.getString("name"));
                people.setSex( rs.getString("sex"));
                people.setAge( rs.getInt("age")); list.add( people );
                } } catch (SQLException e) {
                e.printStackTrace();
                }finally{
                JDBCUtil.release( rs , ps , con );
                } return list;
                }
                }

                效果如下:

    • (2)、使用别人封装好的  ———— 连接池

      • ①、什么是连接池?

        • 在javaSE的多线程中说过一个线程池,对照起来看

          • 池,就是池化技术嘛,一个容器咯,而这个容器的作用就是:控制连接数据库的个数、设置url、username、password、连接数量不够进行扩容之类的容器嘛
          • 数据库连接 -------> 执行完毕 ---------> 释放资源       整个过程是很消耗资源的。因此:连接池的真正作用就是  预先准备一些资源,这样一过来就可以进行连接操作了
        • 怎么编写连接池?

          • 很简单,只需要实现一个类就可以了  DataSource  去看一下这个类的源码( 是java.sql包下的 )

            •  但是啊:有别人写好的东西,我们不用手写,因此:拿别人写好的东西来用一下咯

      • ②、别人写好的连接池有哪些?

        • 最流行的就是:c3p0 、 dbcp 、 阿里巴巴的druid
        • 简单聊一下这三个的理论知识

          • druid 是淘宝 和 支付宝的必用数据库连接池  这玩意儿主要就是可以做到监控的功能,详细点就是如下:

            • 对Oracle 和 MySQL做了特别的优化 如:Oracle 的 PS Cache 内存占用优化,MySql 的 ping 检测优化
            • 使得分析 SQL 的抽象语法树很方便
            • 简单 SQL 语句用时 10 微秒以内,复杂 SQL 用时 30 微秒
            • 通过 Druid 提供的 Parser 可以在 JDBC 层拦截 SQL 做相应处理 ( 比如:分库分表,审计等 )
            • 上面这些更细的知识点不懂没关系,只需要知道主要是搞监控机制的就行

 

          • DBCP

            • 是一个依赖 jakarta commons-pool 对象池机制的数据库连接池,DBCP,也是 Tomcat 使用的连接池组件
          • c3p0

            • 是一个开放源代码的 JDBC 连接池,它在 lib 目录中与 Hibernate 一起发布,,包括了实现 jdbc3 和 jdbc2 扩展规范说明的 Connection 和 Statement 池的 DataSources 对象
            • 多说一嘴:DBCP和c3p0的区别

              • ①、dbcp 没有自动回收空闲连接功能,c3p0 有自动回收空闲连接功能
                ②、两者对数据连接处理方式不同:c3p0 提供最大空闲时间,dbcp 提供最大连接数
                ③、c3p0 连接超过最大连接时间时,当前连接会断掉。dbcp 当连接数数超过最大连接数时,所有连接都会被断开
                ④、dbcp 它的原理是维护多个连接对象 Connection。在 web 项目要连接数据库时直接使用它维护对象进行连接,省去每次都要创建对象的麻烦,提高平效率和减少内存使用
                ⑤、c3p0 可以自动回收连接,dbcp 需要自己手动释放资源返回,不过 dbcp 效率比较高
          • 壹、一法通、万法通,先来玩一下DBCP

            • ①、需要两个jar包

              • 一个commons-dbcp  一个 commons-pool    想要什么版本自己去找,我的版本如下:
                • commons-dbcp-1.4
                • commons-pool-1.6
              • 老规矩:把对应的jar包放到项目中去

 

            • ②、需要设置配置文件

              • 玩儿DBCP需要使用Properties进行编写配置

                • # 连接设置
                  # 注意:这个driverClassName必须用这个名字,别用什么driver就完了 因为:底层中找的就是这个名字
                  driverClassName = com.mysql.jdbc.Driver
                  url = jdbc:mysql://localhost:3306/jdbc?characterEncoding = utf-8 & userUnicode = true & useSSL = true
                  username = root
                  password = 072413 # 初始化连接数量
                  initialSize = 10 # 最大连接数量
                  maxActive = 50 # 最大空闲连接数
                  maxIdle = 20 # 最小空闲连接数
                  minIdle = 5 # 超时等待时间 , 以毫秒为单位
                  maxWait = 60000 # 下面的设置要不要都无所谓 ## JDBC驱动建立连接时附带的连接属性的格式必须为这样 ———— 属性名 = property
                  ## 另外:user 和 password两个属性会被明确地传递,因此:这里不需要包含他们
                  #connectionProperties = useUnicode = true ; characterEncoding = utf-8
                  #
                  ## 指定有连接池所创建的连接的自动提交 auto-commit状态
                  #defaultAutoCommit = true
                  #
                  ## driver default 指定由连接池所创建的连接的只读 read-only状态
                  ## 但是:如果没有设置该值,则:setReadOnly方法不被调用
                  ## 另外:某些驱动并不支持只读模式 如:informix
                  ## 因此:这个不设置也行
                  ## defaultReadOnly = ......
                  #
                  ## driver default 指定有连接池所创建的连接的事务级别 transactionIsolation
                  ## 可用值为下列之一:
                  ## NONE , READ_UNCOMMITTED , READ_COMMITTED , REPEATABLE_READ
                  #defalutTransactionIsolation = READ_UNCOMMITTED
                  #
                  #
                  ## 有需要的配置,没需要的就不配置这中间的东西,我嫌麻烦,不配置了,直接注释掉

                  配置好了,那得用一下咯

              • 实体类还是用的person、util 和 dao需要做一下调整

                • 封装DBCP工具类

                  • package cn.xieGongZi.utils;
                    
                    import org.apache.commons.dbcp.BasicDataSourceFactory;
                    
                    import javax.sql.DataSource;
                    import java.io.InputStream;
                    import java.sql.*;
                    import java.util.Properties; public class JDBCUtil { // private static String driver; // 相应的这些也不要了
                    // private static String url;
                    // private static String username;
                    // private static String password; private static DataSource dataSource = null; // 提升作用域 为了获取链接嘛 static { // 这里就是去加载 DBCP_pool.properties 了
                    InputStream ins = JDBCUtil.class.getClassLoader().getResourceAsStream("cn/xieGongZi/resources/DBCP_pool.properties"); Properties ppt = new Properties();
                    try {
                    ppt.load( ins ); // driver = ppt.getProperty("driver"); // 这一部分就不需要了,因为:在配置文件中配置了
                    // url = ppt.getProperty("url");
                    // username = ppt.getProperty("username");
                    // password = ppt.getProperty("password"); // Class.forName(driver); // 这里需要借助一个类来获取数据源 这是一个工厂模式 这个是用来创建对象的 它需要一个Properties对象,所以直接扔给它
                    dataSource = BasicDataSourceFactory.createDataSource(ppt);// 处理异常 这个东西获取的是一个Datasource数据源
                    } catch (Exception e) {
                    e.printStackTrace();
                    }
                    } // 封装获取数据库链接对象
                    public static Connection getConnection() throws SQLException {
                    // return DriverManager.getConnection(url, username, password); // 前面看源码不是看过datasource中自带获取连接吗,所以:这里直接通过DataSource获取连接
                    return dataSource.getConnection(); // 这样就把DBCP的工具类封装好了
                    } // 释放资源方法还是一样需要
                    // 提供释放资源的方法
                    public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象 if ( rs != null ){
                    try {
                    rs.close();
                    } catch (SQLException e) {
                    e.printStackTrace();
                    }
                    } if ( ps != null ){
                    try {
                    ps.close();
                    } catch (SQLException e) {
                    e.printStackTrace();
                    }
                    } if ( con != null ){
                    try {
                    con.close();
                    } catch (SQLException e) {
                    e.printStackTrace();
                    }
                    }
                    } }

                    延伸一下:不是有一个BasicDataSourceFactory吗,看一下它的源码:

                • 修改dao层  其实就改两个地方 使用工具类调用那里

                • 测试:

          • 贰、再来玩一下C3P0  其实玩法都一样,就是jar包不一样,然后获取数据源哪里不一样而已

            • ①、需要的两个jar包

              • c3p0         我的是:c3p0-0.9.5.2
              • mchange-commons-java        我的是:mchange-commons-java-0.2.15
            • 老规矩  —— 编写实体类、放jar包

            • ②、编写配置文件   C3P0使用的是xml配置

              • <?xml version="1.0" encoding="UTF-8"?>
                <c3p0-config>

                <!-- 数据库连接池 -->
                <named-config name="mysql"> <!-- 这个named-config名字很重要,后面获取数据源需要它 -->

                <property name="driverClass">com.mysql.jdbc.Driver</property>
                <property name="jdbcUrl">jdbc:mysql://localhost:3306/blog</property>
                <property name="user">root</property>
                <property name="password">072413</property>
                <!--当数据连接池不够的时候,每次增长的个数-->
                <property name="acquireIncrement">5</property>
                <!--初始的连接池个数-->
                <property name="initialPoolSize">10</property>
                <property name="minPoolSize">5</property>
                <property name="maxPoolSize">15</property>
                <!--后面这两个可要可不要-->
                <!--jdbc的标准参数 用于控制数据源里面的preparedStatement的数量-->
                <property name="maxStatements">0</property>
                <!--连接池内单个链接所拥有的最大的缓存statement数-->
                <property name="maxStatementsPerConnoection">5</property>

                </named-config>

                </c3p0-config>

            • ③、编写工具类、获取数据源

              • package cn.xieGongZi.utils;
                
                import com.mchange.v2.c3p0.ComboPooledDataSource;
                
                import java.sql.Connection;
                import java.sql.PreparedStatement;
                import java.sql.ResultSet;
                import java.sql.SQLException; public class JDBCUtil { // 这里需要一个东西 ComboPooledDataSource 后面要通过这个去获取数据源
                private static ComboPooledDataSource dataSource = null; static { // 获取数据源
                dataSource = new ComboPooledDataSource("mysql"); // 这里的参数名字就是前面配置文件中提到的named-config名字
                } // 只需要改以上部分就完了 // 这里和DBCP一样的
                // 封装获取数据库链接对象
                public static Connection getConnection() throws SQLException {
                return dataSource.getConnection();
                } // 释放资源方法还也是一样
                // 提供释放资源的方法
                public static void release(ResultSet rs , PreparedStatement ps , Connection con ) { // 注意:这里是用的PreparedStatement对象 if ( rs != null ){
                try {
                rs.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                } if ( ps != null ){
                try {
                ps.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                } if ( con != null ){
                try {
                con.close();
                } catch (SQLException e) {
                e.printStackTrace();
                }
                }
                } }

                结果就不展示了

至此:JDBC的相关知识完毕,还有深层次的封装,就是使用preparedStatement对象时

将 增删改 和 释放资源 及 查 都进行封装了( 注:完美的查可以使用两种方法:一是接口回调、二是反射 )

另外一个就是ThreadLocal这个小东西,这个没什么好说的,就是一个看源码就懂的东西

附:ThreadLocal就是为了处理事务的( ThreadLocal支持泛型 ),所以就是为了保证Connection对象是同一个

这个ThreadLocal的核心方法就三个:get()、set()、remove()

另外:

IDEA连接数据库( 即:集成过去 )在右上角Database中
这样集成过去之后,就不用把IDEA和数据库来回切换了

感兴趣的自行去摸索一下

数据库之JDBC的更多相关文章

  1. 转!!各种数据库的jdbc驱动下载及连接方式

    各种数据库驱动 数据库名称 下载地址 说明 Mysql http://www.mysql.com/products/connector/j/ Shipped. But need to download ...

  2. 各种数据库使用JDBC连接的方式

    Java数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成.JDBC 为工具/数据库开发人员提供了一个标准的 API,使他们能够用纯Java API 来编写数据库应用程序.然而各个开 ...

  3. JAVA数据库编程(JDBC技术)-入门笔记

    本菜鸟才介入Java,我现在不急着去看那些基本的语法或者一些Java里面的版本的特征或者是一些晋级的知识,因为有一点.Net的OOP编程思想,所以对于Java的这些语法以及什么的在用到的时候在去发现学 ...

  4. Java基础之MySQL数据库与JDBC

    一.数据库 DBMS         数据库管理系统 是由多个程序构成的专门用来管理大量数据的计算机系统 Server       提供数据存储.检索.计算等服务的网络程序+系统服务 Notifier ...

  5. 数据库使用JDBC连接的方式

    下面罗列了各种数据库使用JDBC连接的方式,可以作为一个手册使用. 1.Oracle8/8i/9i/10g/11g数据库(thin模式) Class.forName("oracle.jdbc ...

  6. Java操作数据库——在JDBC里使用事务

    Java操作数据库——在JDBC里使用事务 摘要:本文主要学习了如何在JDBC里使用事务. 使用Connection的事务控制方法 当JDBC程序向数据库获得一个Connection对象时,默认情况下 ...

  7. Java操作数据库——使用JDBC连接数据库

    Java操作数据库——使用JDBC连接数据库 摘要:本文主要学习了如何使用JDBC连接数据库. 背景 数据持久化 数据持久化就是把数据保存到可掉电式存储设备中以供之后使用.大多数情况下,特别是企业级应 ...

  8. 数据库持久化+JDBC数据库连接

    数据持久化 数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称.数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型.XML.二进制流等. 瞬时状态 保 ...

  9. Java数据库编程(JDBC)

    一.使用Java对数据库的操作步骤: 1.根据应用程序的数据库类型,加载相应的驱动: 2.连接到数据库,得到Connection对象: 3.通过Connection创建Statement对象: 4.使 ...

  10. 数据库 MySQL Jdbc JDBC的六个固定步骤

    *0 案例:    a)在JavaScript中使用正则表达式,在JS中正则表达式的定界符是://     var regexp = /^[0-9]+$/;     if(regexp.test(nu ...

随机推荐

  1. 零基础入门必备的Linux命令和C语言基础

    文件和目录(底部有视频资料) cd /home 进入 '/ home' 目录' cd - 返回上一级目录 cd -/- 返回上两级目录 cd 进入个人的主目录 cd ~user1 进入个人的主目录 c ...

  2. Python网络爬虫实战入门

    一.网络爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序. 爬虫的基本流程: 发起请求: 通过HTTP库向目标站点发起请求,也就是发送一个Request ...

  3. shell调用另一个脚本的三种方式fork/exec/source

    exec和source都属于bash内部命令(builtins commands),在bash下输入man exec或man source可以查看所有的内部命令信息. bash shell的命令分为两 ...

  4. hdu 1160 FatMouse's Speed(最长不下降子序列+输出路径)

    题意: FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to ...

  5. 使用google zxing生成二维码图片

    生成二维码工具类: 1 import java.awt.geom.AffineTransform; 2 import java.awt.image.AffineTransformOp; 3 impor ...

  6. python环境搭建、pycharm安装

    一.      实验目标 (1)  Python环境搭建 (2)  会pycharm安装和使用 (3)  了解python程序设计流程 二.      实验内容 1.勾选Add Python 3.7 ...

  7. Oracle的主要组件和基本概念

    oracle 简介 oracle(甲骨文)公司 1977年,三人合伙创办(Software Development Laboratories,SDL) 1979年,更名为Relational Soft ...

  8. elementUI下拉框select组件change事件用法

    <el-select-custom clearable collapse-tags v-model="searchForm.cardTypeList" @change=&qu ...

  9. RabbitMQ保证消息的顺序性

    当我们的系统中引入了MQ之后,不得不考虑的一个问题是如何保证消息的顺序性,这是一个至关重要的事情,如果顺序错乱了,就会导致数据的不一致.       比如:业务场景是这样的:我们需要根据mysql的b ...

  10. 在同级路径下,SpringBoot两种类型的配置文件(.properties/.yml)同时存在时,配置优先级如何处理?

    两类配置文件如果同时存在,若 key 相同则 properties 优先级高,若key不同则合并加载: