JDBC和连接池

  • Post author:
  • Post category:其他



目录


一、JDBC概述


二、JDBC快速入门


·其余四种方式加载驱动


·ResultSet


·Statement


·PreparedStatement(预处理)


三、JDBC API


四、JDBC Utils


1.将数据库初始化,连接和资源关闭封装至工具类


2.使用JDBCUtils工具类完成dml和select


五、事务


六、批处理


·演示Java批处理


七、连接池


·传统获取Connection问题


·数据库连接池


​编辑·连接池种类


·C3PO两种连接方式


八、Apache-DBUtils


·DbUtils类


·使用Apache-DBUtils 工具类+C3P0完成对表的CRUD


·返回单行单列 :


·进行DML :

一、JDBC概述

1.JDBC为访问不同的数据库提供了统一的接口,为使用者屏蔽了细节问题                                      2.Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。                                                                                                                                       3.说明:JDBC是Java提供一套用于数据库操作的接口APl, Java程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口,提供不同实现。

二、JDBC快速入门

//前置工作:在项目下创建一个文件夹比如libs
//将 mysql.jar 拷贝到该目录下,点击add to project ..加入到项目中

//1。注册驱动
Driver driver = new DriverO;//创建driver对象

//2。得到连接
//(1) jdbc:mysql:// 规定好表示协议,通过jdbc的方式连接mysql
//(2)localhost主机,可以是ip地址
//(3)3306表示mysql监听的端口
//(4) hsp_db02连接到mysql dbms 的哪个数据库
//(5)mysql的连接本质就是前面学过的socket连接
String url = "jdbc:mysql://localhost:3306/book_db";
//将用户名和密码放入到Properties对象
Properties properties = new Properties();
//说明user和 password 是规定好,后面的值根据实际况写
properties.setProperty( "user" , "root");//用户
properties.setProperty("password" ,"123456");//密码

//3。执行sql
String sql = "insert into actor values(null,'刘德华','男','1970-11-11','110')";
//statement用于执行静态SQL语句并返回其生成的结果的对象
Statement statement = connect.createStatement();
int rows = statement.executeUpdate(sql);// 如果是 dml语句,返回的就是影响行数

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

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


·其余四种方式加载驱动



·ResultSet

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

//加载驱动
Class.forName(driver);
//建立连接
Connection connection = DriverManager.getConnection(url, user, password);
//得到statement
Statement statement = connection.createStatement();
//组织SQL语句
String sql = "select id,name,sex,borndate from actor";
//executeQuery:执行给定的SQL语句,该语句返回单个ResultSet对象
ResultSet resultSet = statement.executeQuery(sql);
//使用while取出数据
while (resultSet.next()){//next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false
            int id = resultSet.getInt(1);//获取该行第一列
            String name = resultSet.getString(2);//获取该行第2列
            String sex = resultSet.getString(3);
            Date brondate = resultSet.getDate(4);
            System.out.println(id+"\t"+name+"\t"+sex+"\t"+brondate);
        }

·Statement

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

·PreparedStatement(预处理)

//接受输入的值
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入账户名");
        String name = sc.nextLine();
        System.out.println("请输入密码");
        String password = sc.nextLine();
        //配置文件接受反射,获取相关值
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\jdbc.properites"));
        String user = properties.getProperty("user");
        String password1 = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //加载驱动,连接数据库
        Class.forName(driver);
        Connection connection = DriverManager.getConnection(url, user, password1);

        //创建SQL语句,“ ? ” 相当于占位符
        String sql = "select user_id,password from admin where user_id=? and password=?";
        //创建PreparedStatement,进行预处理
        //preparedStatement 对象实现了 PreparedStatement接口的实现类的对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //给“?”赋值
        preparedStatement.setString(1,name);
        preparedStatement.setString(2,password);

        //  执行 select 语句,使用executeQuery
        //  执行的是dml(update,insert,delete) ,使用executeUpdate()
        /*
          这里执行PreparedStatement ,executeQuery()里不需要填入sql
          1.因为前面的SQL语句中使用 ? 占位,要使用preparedStatement的setString方法给                        
            user_id赋值
            executeQuery()里不需要填入sql
          2.若executeQuery()填入sql,SQL语句中需要给定值,如:
            String sql = "select user_id,password from admin where user_id='tom' and 
            password='123' ";
         */
        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()){
            System.out.println("恭喜登录成功");
        }else {
            System.out.println("sorry,登录失败");
        }
        resultSet.close();
        preparedStatement.close();
        connection.close();

1. PreparedStatement 执行的SQL语句中的参数用问号(?)来表示,调用PreparedStatement对象的setXxx()方法来设置这些参数. setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值                                                             2.调用executeQuery(),返回ResultSet 对象                                                                                     3.调用executeUpdate():执行更新,包括增、删、修改


优点:1.不再使用`+`拼接SQL语句,减少语法错误。2.有效解决SQL注入问题。3.大大减少编译次数,效率较高

三、JDBC API

JDBC API是一系列的接口,它统一和规范了应用程序与数据库的连接、执行SQL语句,并到得到返回结果等各类操作,相关类和接口在java.sql与javax.sql包中

四、JDBC Utils

1.将数据库初始化,连接和资源关闭封装至工具类

private static String name;
    private static String password;
    private static String url;
    private static String driver;

    //在static静态代码块中初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\jdbc.properties"));
            String name = properties.getProperty("user");
            String password = properties.getProperty("password");
            String url = properties.getProperty("url");
            String driver = properties.getProperty("driver");

            Class.forName(driver);
        } catch (Exception e) {
            //将编译异常转成运行异常
            //这里调用者,可以选择捕获该异常,也可以默认处理该异常,比较方便
            throw new RuntimeException(e);
        }

    }
    //获取数据库连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,name,password);
    }

    /*
        关闭相关资源
        ResultSet结果集
        Statement和PreparedStatement
        Connection
     */
    public static void close(ResultSet resultSet, Statement statement, Connection connection) throws SQLException {
        if (resultSet != null){
            resultSet.close();
        }
        if (statement != null){
            statement.close();
        }
        if (connection != null){
            connection.close();
        }
    }

2.使用JDBCUtils工具类完成dml和select

@Test
    public void testDML() throws SQLException {
        //创建连接
        Connection connection = JDBCUtils.getConnection();
        //SQL语句
        String sql = "update actor set name=? where id=?";
        //创建PreparedStatement,赋值
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1,"IKUN");
        preparedStatement.setInt(2,1);

        int i = preparedStatement.executeUpdate();

        //关闭资源
        JDBCUtils.close(null,preparedStatement,connection);
    }

五、事务

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

 @Test
    public void useTransAction() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        String sql1 = "update count set salry=salry-100 where id=1";
        String sql2 = "update count set salry=salry+100 where id=2";
        try {
            connection = JDBCUtils.getConnection();//在默认情况下connection是默认自动提交
            //将connection设置为不自动提交
            connection.setAutoCommit(false);//开启了事务

            preparedStatement = connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();//执行第一条SQL语句
            //int i = 1/0;
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();//执行第二条SQL语句

            //这里提交事务
            connection.commit();
        } catch (Exception e) {
            //这里进行回滚,撤销SQL语句
            //默认回滚到事物的开始阶段
            System.out.println("发生异常,撤销SQL语句");
            try {
                connection.rollback();
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }

            throw new RuntimeException(e);
        } finally {
            try {
                JDBCUtils.close(null,preparedStatement,connection);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

六、批处理

1.当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。                                                    2. JDBC的批量处理语句包括下面方法:                                                                                          addBatch():添加需要批量处理的SQL语句或参数                                                                          executeBatch():执行批量处理语句;                                                                                            clearBatch():清空批处理包的语句                                                                                              3. JDBC连接MySQL时,如果要使用批处理功能,请再url中加参数

rewriteBatchedStatements=true

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

·演示Java批处理

@Test
    //批处理先将:url中加参数rewriteBatchedStatements=true
    //即:url="jdbc:mysql://localhost:3306/db_lianxi01?rewriteBatchedStatements=true";
    public void noBatch() throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into admin2 values (null,?,?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        System.out.println("处理开始");
        long start = System.currentTimeMillis();
        for (int i = 1;i<=5000;i++){
            preparedStatement.setString(1,"jj"+i);
            preparedStatement.setString(2,"333");
            //preparedStatement.executeUpdate(); 等批处理结束在添加如数据库
            //将SQL语句加入批处理包中
            preparedStatement.addBatch();
            //当有1000条记录时,再进行批处理,添加至数据库
            if (i%1000 == 0){
                preparedStatement.executeUpdate();
                //清空,进行下一次批处理
                preparedStatement.clearBatch();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("处理结束,耗时:"+(end-start));//未使用批处理11235,使用批处理45
    }

七、连接池

·传统获取Connection问题

1.传统的JDBC数据库连接使用DriverManager来获取,每次向数据库建立连接的时候都要将Connection 加载到内存中,冉监功P地址,.用口科密码(0.05s ~1s时间)。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器崩溃。

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

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

·数据库连接池

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

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

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


·连接池种类

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

2.


C3PO


数据库连接池,速度相对较慢,稳定性不错(hibernate, spring)

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

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

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

6.


Druid


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

·C3PO两种连接方式

//方法一:相关参数,在程序中指定user,URL,password等
    public void testC3P0_01() throws IOException, PropertyVetoException, SQLException {
        //创建一个数据源对象
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        //通过配置文件jdbc.properties 获取相关连接信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\jdbc.properties"));
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //给数据源comboPooledDataSource 设置相关参数
        //注意:连接管理是由 comboPooledDataSource 来管理
        comboPooledDataSource.setDriverClass(driver);
        comboPooledDataSource.setJdbcUrl(url);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);

        //设置初始化连接数
        comboPooledDataSource.setInitialPoolSize(10);
        //设置最大连接数
        comboPooledDataSource.setMaxPoolSize(50);
        //从DataSource 接口实现
        Connection connection = comboPooledDataSource.getConnection();
        System.out.println("连接成功 ");

        connection.close();
    }

    //方式二,使用c3p0-config.xml配置文本来完成
    @Test
    public void testC3P0_02() throws SQLException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("xss-007");
        //测试5000次连接数据库时间
        long start = System.currentTimeMillis();
        for (int i = 1;i<=5000;i++) {
            Connection connection = comboPooledDataSource.getConnection();
            //System.out.println("连接成功");
            connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));
    }



注:c3p0-config.xml的配置

<c3p0-config>
    <!-- 数据源名称代表连接池-->
    <named-config name="xss-007">
        <!--用户名)-->
        <property name="user">root</property>
        <!--数据库的连接密码-->
        <property name="password">123456</property>
        <!--URL-->
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/db_lianxi01</property>
        <!--连接MySQL数据库的配置文件 注:等号前后不要有空格-->
        <!--驱动名-->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <!--连接池每次增长时候连接数-->
        <property name="acquireIncreasement">10</property>
        <!--连接池初始化的时候连接数-->
        <property name="initialPoolSize">10</property>
        <!--连接池中连接的最大个数-->
        <property name="maxPoolSize">100</property>
        <!--连接池中连接的最小个数-->
        <property name="minPoolSize">10</property>
        <!--可连接的最多的命令对象数-->
        <property name="maxStatements">10</property>
        <!--每个连接对象可连接的最多的命令对象数-->
        <property name="maxStatementsPerConnection">2</property>
    </named-config>
</c3p0-config>

八、Apache-DBUtils

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

·DbUtils类

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

2使用QueryRunner类实现查询

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

·使用Apache-DBUtils 工具类+C3P0完成对表的CRUD

//使用Apache-DBUtils 工具类+C3P0完成对表的CRUD
    @Test
    public void testApDBUtils() throws SQLException {
        //得到C3P0的连接
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("xss-007");
        Connection connection = comboPooledDataSource.getConnection();
       // Connection connection = JDBCUtils.getConnection();
        //创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //执行相关方法,返回ArrayList结果集
        String sql = "select * from actor where id = ?";
        /**
         * 1.query 方法就是执行SQL语句,得到resultset---封装到--->ArrayList集合中
         * 2.返回集合
         * 3.connection:连接
         * 4.SQL:执行SQL语句
         * 5.new BeanListHandler<>(Actor.class):在将resultset -> Actor对象->封装到
         *      ArrayList底层使用反射机制去获取Actor类的属性,然后进行封装
         * 6.1就是给 sql语句中的?赋值,可以有多个值,因为是可变参数Object... params
         * 7.底层得到的resultset ,会在query 关闭,关闭PreparedStatment
         */
        List<actor> query = queryRunner.query(connection, sql, new BeanListHandler<>(actor.class),1);

        System.out.println("输出结果集合");
        for (actor actor1:query
             ) {
            System.out.println(actor1);
        }
        //释放资源
        connection.close();
    }

·返回单行单列 :

//:因为返回的是一个对象,使用的handler 就是


ScalarHandler


0bject obj = queryRunner.query(connection,sql, new ScalarHandler(),48);

·进行DML :

//(1)执行dml操作是 queryRunner.update()         //(2)返回的值是受影响的行数                                  int affectedRow = queryRunner.update(connection,sql,”张三丰”,4);

九、BasicDao




版权声明:本文为qq_62701314原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。