当前位置首页 > Apache知识

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,

阅读次数:295 次  来源:admin  发布时间:

一、JDBC的概述

1.JDBC为访问不同的数据薛是供了统一的接口,为使用者屏蔽了细节问题。

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

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

二。JDBC带来的好处

java程序可以直接对数据库进行调用,但是没有很好的移植性(对用于不同的数据库),所以不推荐

JDBC带来的好处:JDBC是java提供一套用于数据库操作的接口API,Java程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口,提供不同实现。

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

JDBC API:JDBC API 是一系列的接口,它统一和规范了应用程序与数据库的连接,执行SQL语句,并得到返回结果等各类操作;

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

JDBC程序编写步骤

1、注册驱动 --- 加载Driver类

2、获取连接 --- 得到Connectio

3、执行增删改查 --- 发送Sql给mysql执行

4、释放资源 --- 关闭相关连接

获取数据库连接的5种方式:

方式1:使用(com.mysql.jdbc.Driver)com.mysql.cj.jdbc.Driver,属于静态加载,灵活性差,依赖性强

方式2:使用反射机制,属于静态加载

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

方式3:使用DriverManager替代driver进行统一管理

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

方式4:使用Class.forName自动完成注册驱动,简化代码

这种方式连接是使用得最多的(推荐使用)

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

在底层会完成注册:

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

提示:

(1)mysql驱动5.1.6可以无需Class.forName(“com.mysql.jdbc.Driver”);

(2)从jdk1.5以后使用了jdbc4,不再需要显示调用class.forName()注册驱动而是自动调用驱动jar包下META-INF\servicesljava .sql.Driver文本中的类名称去注册

(3)建议加上Class.forName(“com.mysql.jdbc.driver”),能够更加明确的感受到程序流程,利于掌握;

方式5:利用properties文件配置数据库需要的相关的配置

更加的灵活,可以直接通过properties配置文件修改数据库连接相关的数据

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

对方式5的实例:

//properties配置文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC
user=root
password=123456
//连接数据库的相关操作
import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class jdbc02 {
    public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
        //创建一个properties对象
        Properties properties = new Properties();
        //加载和获取创建的properties的相关数据
        properties.load(new FileInputStream("src\\db.properties"));
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");

        String sql = "insert into actor values (null,'王五','男','1975-11-23','110')";

        //driver驱动,也可以不加,但是加上更容易读懂流程
        Class.forName(driver);
        //连接和执行操作
        Connection connection = DriverManager.getConnection(url, user, password);
        Statement statement = connection.createStatement();
        statement.executeUpdate(sql);
        //关闭连接
        System.out.println("连接"+connection);
        statement.close();
        connection.close();


    }
}

三、RestSet【结果集】

基本介绍:

1.表示数据库结果集的数据表,通常通过执行查询数据库的语句生成

2. ResultSet对象保持一个光标指向其当前的数据行。最初,光标位于第一行之前

3. next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回

false,因此可以在while循环中使用循环来遍历结果集

简单测试:

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

四、Statement:

基本介绍:

1.Statement对象用于执行静态SQL语句并返回其生成的结果的对象

2.在连接建立后,需要对数据库进行访问,执行命名或是SQL语句,可以通过

Statement【存在SQL注入】

PreparedStatement【预处理】

CallableStatement【存储过程】

3. Statement对象执行SQL语句,存在SQL注入风险

4.SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库。

5.要防范SQL注入,只要用 PreparedStatement(从Statement扩展而来)取

代 Statement就可以了

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

public class jdbc02 {
    public static void main(String[] args) throws ClassNotFoundException, IOException, SQLException {
        //创建一个properties对象
        Properties properties = new Properties();
        //加载和获取创建的properties的相关数据
        properties.load(new FileInputStream("src\\db.properties"));
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");

        String sql = "insert into actor values (null,'三毛','男','1975-11-23','110')";
        String sql1 = "select id,name from actor";

        //driver驱动,也可以不加,但是加上更容易读懂流程
        Class.forName(driver);
        //连接和执行操作
        Connection connection = DriverManager.getConnection(url, user, password);
        Statement statement = connection.createStatement();
//        statement.executeUpdate(sql);

//        String sql1 = "select id,name from actor";
        ResultSet resultSet = statement.executeQuery(sql1);
        while (resultSet.next()) {
            int i = resultSet.getInt(1);
            String string1 = resultSet.getString(2);
            System.out.println(i+"=="+string1);
        }
        //关闭连接
        resultSet.close();
        System.out.println("连接"+connection);
        statement.close();
        connection.close();


    }
}

PrepareStatement:

1. PreparedStatement 执行的SQL语句中的参数用问号(?)来表示,调用

PreparedStatement对象的setXxx()方法来设置这些参数. setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值

2.调用executeQuery),返回ResultSet 对象

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

预处理的好处:

1.不再使用+拼接sql语句,减少语法错误

2.有效的解决了sql注入问题!

3.大大减少了编译次数,效率较高

对preparestatement的测试代码,配置文件还是上面的配置文件

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

public class PrepareStatement {
    public static void main(String[] args) throws Exception {

        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\db.properties"));
        String drive = properties.getProperty("driver");
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");

        //更新操作
//        String sql = "update actor set phone = ? where name = ?";
        //删除操作
//        String sql = "delete from actor where name = ?";
//        添加操作
//        String sql = "insert into actor values(null,?,?,?,?)";
//查询操作
        String sql = "select * from actor";

        Class.forName(drive);

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

        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //更改操作
//        preparedStatement.setString(1, "123456");
//        preparedStatement.setString(2, "三毛");
//删除操作
//        preparedStatement.setString(1, "二狗");
//添加操作
//        preparedStatement.setString(1, "张三");
//        preparedStatement.setString(2, "男");
//        preparedStatement.setString(3, "1975-11-23 00:00:00");
//        preparedStatement.setString(4,"456789");
//        int i = preparedStatement.executeUpdate();
//        System.out.println(i >0 ? "成功" : "失败");

//查询操作
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
            System.out.println(resultSet.getString(2));
        }

        preparedStatement.close();
        connection.close();


    }
}

总结:

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

五、事务:将多行代码当做SQL事务来处理,主要流程需要的关键代码:

connection.setAutoCommit(false);//取消自动提交的操作,取消之后,会在提及之后完成事务

connection.commit();提交事务

connection.rollback();//用于回退事务

批处理:

基本介绍:

1、当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允

许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。

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

addBatch():添加需要批量处理的SQL语句或参数executeBatch(:执行批量处理语句

clearBatch():清空批处理包的语句

3、 JDBC连接MySQL时,如果要使用批处理功能,请再url中加参

数?rewriteBatchedStatements=true

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

过程:

(1)将sql语句加入到批处理包中

preparedStatement.addBatch();

reparedStatement.addBatch(sql)

(2)执行sql和清空sql

//批量执行sql语句

reparedStatement.executeBatch()

//清除批量的sql语句

reparedStatement.clearBatch()

将 SQL加入到批处理包中源码所做的事情:

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

六、数据库连接池

传统connection问题分析:

1.传统的JDBC数据库连接使用 DriverManager来获取,每次向数据库建立

连接的时候都要将Connection 加载到内存中,再验证IP地址,用户名和密码(0.05s~1s时间)。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器崩溃。2每一次数据库连接,使用完后都得断开,如果程序出现异常面未能关闭,将

导致数据库内存泄漏,最终将导致重启数据库。

3.传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致

内存泄漏,MySQL崩溃。

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

(connection pool).

数据库连接池基本介绍:

1.预先在缓冲池中放入一定数量的连接,,当需

要建立数据库连接时,只需从“缓冲池”中取出一个,,使用完毕之后再放回去。

2.数据库连接池负责分配、管理和释放数据库

连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。

3.当应用程序向连接池请求的连接数超过最大

连接数量时,这些请求将被加入到等待队列中

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

数据库连接池示意图:

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

数据库连接池种类:

1.JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource

只是一个接口,该接口通常由第三方提供实现

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

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

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

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

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

优点于身的数据库连接池

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

测试:C3P0连接池的连接(需要导入第三方库:c3p0的jar包)

第一个C3P0连接的配置文件还是上面的配置文件内容

第二个C3P0的连接需要有一个xml配置文件

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class ConDatasource {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\db.properties"));
        String driver = properties.getProperty("driver");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");

        //建立comboPooledDataSource管理连接池
        ComboPooledDataSource comboPooledDataSource = new 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("1连接成功");
        connection.close();

    }

    @Test
    public  void ConDatasource02() throws SQLException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("test_C3P0");

        long start = System.currentTimeMillis();
        System.out.println("测试连接5000次需要的时间");
        for (int i = 0; i < 5000; i++) {
        Connection connection = comboPooledDataSource.getConnection();
//        System.out.println("2连接成功");
        connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("花费时长:"+(end-start));
    }
}
//第二种方式的xml文件
<c3p0-config>

  <named-config name="test_C3P0">
<!-- 驱动类 -->
  <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
  <!-- url-->
      <property name="jdbcUrl">jdbc:mysql://localhost:3306/test_db?useSSL=false&amp;characterEncoding=utf8&amp;serverTimezone=UTC</property>
  <!-- 用户名 -->
          <property name="user">root</property>
          <!-- 密码 -->
      <property name="password">123456</property>
      <!-- 每次增长的连接数-->
    <property name="acquireIncrement">5</property>
    <!-- 初始的连接数 -->
    <property name="initialPoolSize">10</property>
    <!-- 最小连接数 -->
    <property name="minPoolSize">5</property>
   <!-- 最大连接数 -->
    <property name="maxPoolSize">10</property>

    <!-- 可连接的最多的命令对象数 -->
    <property name="maxStatements">5</property> 
    
    <!-- 每个连接对象可连接的最多的命令对象数 -->
    <property name="maxStatementsPerConnection">2</property>
  </named-config>
</c3p0-config>

测试:Druid连接池的连接(需要第三方库druid的jar包)

package com.zjl.jdbc;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.util.Properties;

public class Druidsource {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));//如下定义的配置文件

        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        long start = System.currentTimeMillis();
        for (int i = 0;i < 500000;i++ ) {
            Connection connection = dataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("Druid连接5000 次需要的时间:" + (end - start));//Druid连接500000 次需要的时间:625
    }
}

//连接中需要的一个配置文件

druid.properties:放在src目录下

#key=value

driverClassName=com.mysql.cj.jdbc.Driver

url=jdbc:mysql://localhost:3306/test_db?useSSL=false&characterEncoding=utf8&serverTimezone=UTC

#url=jdbc:mysql://localhost:3306/girl

username=root

assword=123456

#initial connection Size初始连接数

initialSize=10

#min idle connecton size最小等待连接数

minIdle=5

#max active connection size最大连接数

maxActive=20

#max wait time (5000 mil seconds)

# 最大等待时间,时间超过就结束这次连接等待下一次的连接

maxWait=5000

注意:对于c3p0和Druid他们的close()是按照第三方库的连接方式,仅仅是将从连接池引用的数据库连接断开(放弃引用)

重新将连接放回到连接池中,和原生 的jdbc连接中的close方法断开连接不同;

用Druid创建一个连接和断开的工具类

package com.zjl.jdbc;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtilsByDruid {
    static DataSource ds;
    static {
        Properties properties = new Properties();

        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
        //编写获取Connection的方法
    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);
        }
    }
}

七、Apache-DBUtil

1、问题引出:在使用Druid连接数据库,返回结果集之后,如果断开连接,结果集就不能够再使用。解决方法如图,将返回的结果集保存到一个泛型列表中,那么当数据库连接断开后,还是可以使用返回的结果集。

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

2、对Apache-DBUtils的基本介绍

1).commons-dbutils 是 Apache组织提供的一个开源 JDBC工具类库,它是对JDBC的封装,

使用dbutils能极大简化jdbc编码的工作量[真的]。

DbUtils类

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

(2).使用QueryRunner类实现查询

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

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

对该DBUtils进行测试:需要对应的jar包(commons-dbutils-1.7.jar)可以去:http://commons.apache.org/下载

相应的JDBCUtilsByDruid类是上面的测试类:

package com.zjl.jdbc;

import com.zjl.bean.Actor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

public class TestDBUtils {
    public static void main(String[] args) throws Exception {
        String sql = "select * from `actor`";
        //从Druid中获取一个连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        //引入DBUtils的jar包,并获得一个QueryRunner对象
        QueryRunner queryRunner = new QueryRunner();

        //利用QueryRunner对象就可以直接查询数据库,执行SQl语句,返回结果封装到ArrayList集合中
        // connection是一个连接,sql是一个执行语句
        //new BeanListHandler<>(Actor.class):在将resultSet中的结果以Actor对象方式封装到ArrayList
        //底层使用反射机制,获取Actor类的属性,然后进行封装
        //1就是给sql 语句中的?赋值,可以有多个值,因为是可变参数0bject... params
//        List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
        //如果要返回单个查询数据就使用BeanHandler<>(Actor.class),返回结果就会是单个对象或者为空
        List<Actor> list = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class));
        //在底层会得到resultSet并在query中关闭,也会在底层使用preparedStatement并关闭
//        JDBCUtilsByDruid.close(null, null, connection);
        Iterator<Actor> iterator = list.iterator();
        while (iterator.hasNext()) {
            Actor next = iterator.next();
            System.out.println(next);
        }
        //进行更新操作
        String updateSql = "update `actor` set name = ? where id = ?";
        int update = queryRunner.update(connection, updateSql, "王无无", 8);
        System.out.println((update > 0) ? "更新成功" : "更新失败");
        //进行删除操作
        String delSql = "delete from `actor` where id = ?";
        int update1 = queryRunner.update(connection, delSql, 10);
        System.out.println((update > 0) ? "删除成功" : "删除失败");

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

}

八、BasicDao--DAO和增删改查通用方法(DAO:data access object 数据访问对象)

基本说明:

1)、 DAO:data access object数据访问对象

2)、这样的通用类,称为 BasicDao,是专门和数据库交互的,即完成对数据库(表)的crud操作。

3)、在BaiscDao的基础上,实现一张表对应一个Dao,更好的完成功能;

关系图如下:

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

java_JDBC,连接数据库方式,RestSet结果集,Statement,PreparedStatement,事务,批处理,数据库连接池(c3p0和Druid)、Apache-DBUtils、

上一篇:[转载]安装ubuntu之后修复windows7的启动项
下一篇:nginx日志自动切割