学习JDBC——仅此一篇就够!?!

目录

emm可能一篇0不够,别当真......

引言

JDBC的作用(看不懂就往下,下面学完自然就懂了)

JDBC的历史和发展(内容来自chat GPT)(了解)

1、JDBC概述

定义(最好自己学完自己总结:什么是JDBC?)

2、JDBC体系结构

JDBC API

jdbc 驱动(知道什么在JDBC中驱动是什么就行)

3、JDBC连接数据库

Driver接口介绍(了解)

PreparedStatement vs Statement

JDBC API 使用路线

入门案例:

案例1: 

案例2:  

案例三

4、使用连接池管理连接

为什么使用连接池?

连接池基本思想

使用连接池的优点:

注意事项:

 总结

目录

emm可能一篇0不够,别当真......

引言

JDBC的作用(看不懂就往下,下面学完自然就懂了)

JDBC的历史和发展(内容来自chat GPT)(了解)

1、JDBC概述

定义(最好自己学完自己总结:什么是JDBC?)

2、JDBC体系结构

JDBC API

jdbc 驱动(知道什么在JDBC中驱动是什么就行)

3、JDBC连接数据库

Driver接口介绍(了解)

PreparedStatement vs Statement

JDBC API 使用路线

入门案例:

案例1: 

案例2:  

案例三

4、使用连接池管理连接

为什么使用连接池?

连接池基本思想(可以尝试自己写一个连接池)

使用连接池的优点:

Druid(德鲁伊)数据库连接池

Apache-DBUtils实现CRUD操作

工具类DbUtils

 QueryRunner 类

ResultSetHandler接口及实现类

注意事项:

 总结


emm可能一篇不够,别当真......^v^

还差点案例肝不动了,我先往后学

引言

JDBC的作用(看不懂就往下,下面学完自然就懂了)

  1. 数据库连接:JDBC允许Java应用程序与数据库建立连接。通过使用JDBC技术我们可以建立与关系型数据库(如MySQL、Oracle、SQL Server等)或非关系型数据库(如MongoDB)的连接。
  2. SQL语句执行:JDBC提供了执行SQL语句的能力。
  3. 事务管理:JDBC支持事务的处理。我们可以使用JDBC开启、提交或回滚事务,

  4. 数据库元数据访问:通过JDBC,我们可以获取数据库的元数据信息(表、列、索引、约束等)。

  5. 结果集处理:JDBC允许我们检索和处理查询结果集。

  6. 预编译和存储过程:JDBC支持预编译SQL语句和执行数据库存储过程。

  7. 异常处理和错误检查:JDBC提供异常处理机制,允许捕获和处理与数据库交互过程中可能发生的错误和异常。

简单讲就是:Java开发人员可以从应用程序中使用Java代码直接连接到数据库,并执行各种数据库操作。

JDBC的历史和发展(内容来自chat GPT)(了解)

下面是JDBC的历史和发展的简要解释:

  1. 早期数据库连接:在Java出现之前,访问数据库的主要方式是使用各种数据库厂商提供的特定数据库API。这导致了编写和维护针对不同数据库的代码的复杂性,缺乏统一性。

  2. JDBC的诞生:为了解决数据库访问的标准化问题,Sun Microsystems(当时的Java的维护者)在1997年推出了JDBC 1.0版本。JDBC(Java数据库连接)提供了一个统一的接口,使得Java应用程序可以通过相同的API与不同的数据库进行交互,无论是关系型数据库还是非关系型数据库。

  3. JDBC的发展:随着Java的发展和数据库技术的进步,JDBC也经历了一系列的版本迭代和改进。每个JDBC版本都带来了新的功能和改进,以提高性能、简化开发,并支持新的数据库功能。

  4. JDBC 2.0:在1998年发布,引入了一些重要的功能,如批量更新、行集、Scrollable ResultSet等。

  5. JDBC 3.0:在2001年发布,提供了更多的数据类型支持、保存点(Savepoints)、数据库元数据访问等功能。

  6. JDBC 4.0:在2006年随Java SE 6发布,主要的改进是自动加载驱动程序、更简化的连接管理、更好的异常处理等。

  7. JDBC 4.1和4.2:在2011年和2013年发布,带来了一些小的增强和改进,如基于新日期和时间API的支持、更好的LOB(Large Object)支持等。

  8. JDBC 4.3:在2017年发布,引入了对Java 8之后的新特性的支持,如流式处理、日期/时间API的增强等。

  9. JDBC的生态系统:除了JDBC API本身,还有许多第三方库和框架,如连接池、ORM(对象关系映射)工具等,以帮助简化JDBC的使用和提高性能。

总的来说,JDBC从其推出以来,为Java开发人员提供了一种方便、灵活和标准的方式来连接和操作各种数据库。随着时间的推移,JDBC不断改进和丰富,适应了不断发展的数据库技术和Java平台的变化。

1、JDBC概述

定义(最好自己学完自己总结:什么是JDBC?)

JDBC(Java DataBase Connectivity) :Java数据库连接技术:具体讲就是通过Java连接广泛的数据库,并对表中数据执行增、删、改、查等操作的技术。

比较高级的定义为:

JDBC是Java与数据库之间的桥梁。它提供了一种标准的方式来连接和操作数据库,使应用程序能够执行SQL查询、更新数据库、管理事务以及处理结果集等操作。

2、JDBC体系结构

  1. JDBC API

JDBC API是整个架构的核心,它定义了与数据库交互的标准接口和操作方法。

  • 面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。

  • 面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。

jdbc 驱动(知道什么在JDBC中驱动是什么就行)

JDBC是由java官方为连接不同数据库提供的统一的接口(规范),但官方并没有提供各大数据库的实现类,而是不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动

总结驱动:JDBC 驱动程序是实现JDBC API的具体类或jar文件,它们提供了特定数据库的驱动程序代码。

为什么JDBC只有接口,没有提供实现?

不同数据库的底层技术不同,不少数据库是闭源的,源代码不公开的。Sun公司无力为所有数据库提供具体实现,只能提供接口而由数据库厂商提供具体实现,Sun公司只是制定JDBC标准,各个厂商准守标准提供具体的实现。JDBC和数据库实现的关系就好比List接口和ArrayList、LinkedList之间的关系。
原文链接:https://blog.csdn.net/weixin_40055163/article/details/120762277

jdbc 驱动程序共有四种类型:

  • JDBC网路协议的纯Java驱动程序: 使用最多的类型
  • JDBC-ODBC 桥
  • 部分本地API,部分Java的驱动程序
  • 本地协议的纯java驱动程序

3、JDBC连接数据库

数据库的连接步骤:
1、导入jar包
2、注册驱动
3、获取连接
4、获取执行者对象
5、执行sql语句,并接收返回结果
6、处理结果
7、释放资源

 如何下载和导入jar包请移步:JDBC—jar包的下载与导入

JDBC技术相关接口和工具类:

接口 作用
Driver   驱动接口,定义建立链接的方式(接口)
DriverManager工具类,用于管理驱动,可以获取数据库的链接
Connection 表示Java与数据库建立的连接对象(接口)
PreparedStatemen 发送SQL语句的工具(接口)
ResultSet结果集,用于获取查询语句的结果(接口)

Driver接口介绍(了解)

  • java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。

  • 在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。

    • Oracle的驱动:oracle.jdbc.driver.OracleDriver

    • mySql的驱动: com.mysql.jdbc.Driver

1、DriverManager:DriverManager是JDBC的入口点,它负责加载适当的数据库驱动程序,并提供创建数据库连接的功能。可以通过调用getConnection方法来获取数据库连接。该类主要进行如下功能:

  • 注册驱动(告诉程序该使用哪一个数据库驱动)  static void registerDriver(Driver driver) (DriverManager的方法)
static void registerDriver(Driver driver) 
  • 获取数据库连接(获取到数据库的连接并返回连接对象)
static Connection getConnection(String url, String user, String password)
//1、注册驱动/加载驱动
DriverManager.registerDriver(new Driver());

//2、获取连接connection
Connection connection = DriverManager.getConnection("jdbc:mysql//127.0.0.1:3306/girls", "root", "root");

2、Connection:表示应用程序与数据库之间的通信通道。通过JDBC连接,应用程序可以向数据库发送SQL语句,并接收和处理数据库返回的结果。

  • 获取执行的对象(Statement/PreparedStatement):

获取普通执行对象:Statement createStatement();

获取预编译执行对象:PreparedStatement prepareStatement(String sql);

  • 管理事务:
  1. 开启事务:setAutoCommit(boolean autoCommit); 参数为false,则开启事务。
  2. 提交事务:commit();
  3. 回滚事务:rollback();
  • 释放资源:

立即将数据库连接对象释放:void close();

3、Statement(知道怎么用就行了):用于执行SQL语句。Statement对象可以执行查询语句(ResultSet),也可以执行更新语句(如插入、更新和删除)。

  • 执行DML语句:

参数sql:可以执行insert、update、delete语句。

int executeUpdate(String sql);

int executeInsert(String sql);

int executeDelete(String sql);

返回值int:返回影响的行数。

  • 执行DQL语句:

ResultSet executeQuery(String sql);
返回值ResultSet:封装查询的结果。
参数sql:可以执行select语句。

  • 释放资源

void close(); 

PreparedStatemen(重点掌握)

是Statement接口下的子接口,它代表一条预编译过的子接口,允许事先编译SQL语句,然后在多次执行时进行参数替换。这可以提高执行效率,并防止SQL注入攻击。在具有动态参数的地方可以用?代替。

SetXXX(int index, XXX xxx)来设置?替代的参数

PreparedStatement vs Statement

  • PreparedStatement能最大可能的提高性能

        数据库服务会对预编译的语句提供性能优化。因为预编译的语句可能被重复调用,所以语句在被编译器编译后的执行代码缓存下来,下次调用只要是相同预编译语句就不需要在编译,只需要将参数直接传入编译过的语句中就会得到执行。
    statement语句中,即使是相同的操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义

  • PreparedStatement可以防止SQL注入

Sql注入xiu案例:

假设有一个网站,用户可以通过用户名和密码登录。网站使用以下SQL语句来验证用户的凭据:

SELECT * FROM users WHERE username='[输入的用户名]' AND password='[输入的密码]'

攻击者通过在用户名输入框中输入恶意的SQL代码来实施注入攻击。例如,他们在用户名输入框(密码框中也行)中输入 ' OR 1= 1 '--(注意OR前的),则会修改SQL语句为

//(看出原因没username =  ' '  OR  '1'='1' --')
SELECT * FROM users WHERE username=  ''  OR '1'='1' --' AND password='[输入的密码]'

在这种情况下,' 1= 1 '始终为真,条件变为真,绕过了密码验证部分的检查,从而成功登录到了系统。攻击者可以使用各种技术和恶意代码来执行未经授权的操作,例如查询、修改或删除数据库中的数据,甚至获取管理员权限。

利用PreparedStatement 我们就可以防止这样的事情发生,因为预编译 会将要用户输入的部分的sql用?代替,如:

SELECT * FROM users WHERE username=  ? AND password= ?

它已经预编译过了(就是告诉程序我长上面那样),只需要将?替换为用户输入的内容,而现在程序也知道了用户输入的哪部分了,无法在玩文字游戏了 。

4、ResultSet

  • ResultSet:用于表示查询返回的数据集

判断结果集中是否还有数据:boolean next();
有数据返回true,并将索引向下移动一行
没有数据返回false

  • 获取结果集中的数据:XXX getXxx(“列名”);

XXX代表数据类型(要获取某列数据,这一列的数据类型)
例如:String getString(“name”); int getInt(“age”);

  • 释放资源

void close();

5、ResultSetMetaData
  • 可用于获取关于 ResultSet 对象中列的类型和属性信息的对象

  • ResultSetMetaData meta = rs.getMetaData();

    • getColumnName(int column):获取指定列的名称

    • getColumnLabel(int column):获取指定列的别名

    • getColumnCount():返回当前 ResultSet 对象中的列数。

    • getColumnTypeName(int column):检索指定列的数据库特定的类型名称。

    • getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。

    • isNullable(int column):指示指定列中的值是否可以为 null。

    • isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。

Java与SQL对应数据类型转换表
Java类型SQL类型
booleanBIT
byteTINYINT
shortSMALLINT
intINTEGER
longBIGINT
StringCHAR,VARCHAR,LONGVARCHAR
byte arrayBINARY , VAR BINARY
java.sql.DateDATE
java.sql.TimeTIME
java.sql.TimestampTIMESTAMP

JDBC API 使用路线

  • 静态SQL路线(没有动态值的语句)

        DriverManager   ->Connection -> Statement ->ResultSet


  • 预编译SQL路线(有动态值的语句)常用

        DriverManager   ->Connection -> PreparedStatement->ResultSet


  • 执行标准存储过程SQL路线

        DriverManager   ->Collection -> CallableStatement->Result


入门案例:

说明:JDBC的连接方式有很多,在开发中也主要掌握一种,避免白雪,前面的案例主要是帮助后面的理解

准备数据库


DROP TABLE IF EXISTS `beauty`;

CREATE TABLE `beauty` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `sex` char(1) DEFAULT '女',
  `borndate` datetime DEFAULT '1987-01-01 00:00:00',
  `phone` varchar(11) NOT NULL,
  `photo` blob,
  `boyfriend_id` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb3;

/*Data for the table `beauty` */

insert  into `beauty` values (1,'柳岩','女','1988-02-03 00:00:00','18209876577',NULL,8),(2,'苍老师','女','1987-12-30 00:00:00','18219876577',NULL,9),(3,'Angelababy','女','1989-02-03 00:00:00','18209876567',NULL,3),(4,'热巴','女','1993-02-03 00:00:00','18209876579',NULL,2),(5,'周冬雨','女','1992-02-03 00:00:00','18209179577',NULL,9),(6,'周芷若','女','1988-02-03 00:00:00','18209876577',NULL,1),(7,'岳灵珊','女','1987-12-30 00:00:00','18219876577',NULL,9),(8,'小昭','女','1989-02-03 00:00:00','18209876567',NULL,1),(9,'双儿','女','1993-02-03 00:00:00','18209876579',NULL,9),(10,'王语嫣','女','1992-02-03 00:00:00','18209179577',NULL,4),(11,'夏雪','女','1993-02-03 00:00:00','18209876579',NULL,9),(12,'赵敏','女','1992-02-03 00:00:00','18209179577',NULL,1);

案例1: 

public class testConnection1 {
    public static void main(String[] args) throws SQLException {
        //1、注册驱动/加载驱动

        Class clazz = Class.forName("com.mysql.cj.jdbc.Driver");
        Driver driver = (Driver) clazz.newInstance();
        DriverManager.registerDriver(driver);//此句可以被注释掉

        //2、获取连接connection
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/girls", "root", "root");
        //3、获取执行者 statement
        Statement statement = connection.createStatement();
        //4、执行sql,获取结果集
        String sql = "select * from beauty";
        ResultSet resultSet = statement.executeQuery(sql);
        //5、操作数据
        while (resultSet.next())
        {
            System.out.println(resultSet.getInt("id") + "" + resultSet.getString("name"));
        }
        connection.close();
        statement.close();
        resultSet.close();
    }
}

案例2:  

public class testConnection2{
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //加上导入jar包则为七个步骤
        //1、加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2、获取连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/girls", "root", "root");
        //3、获取执行对象
        Statement statement = connection.createStatement();
        //4.执行sql语句,获取结果集
        String sql = "Select * from beauty";
        ResultSet resultSet = statement.executeQuery(sql);

        //5、处理结果
        while (resultSet.next()) {
            System.out.println(resultSet.getInt("id") +"\t"+ resultSet.getString("name"));
        }
        //6、释放资源
        connection.close();
        statement.close();
    }
}

我们在第二个的入门案例中并没有注册驱动,也成功了,为什么呢????
因为我们使用了Class.forName:Class.forName(“com.mysql.jdbc.Driver”)   我们通过了给forName指定了是mysql的驱动,它会帮助我们注册驱动

在com.mysql.jdbc.Driver类中存在静态代码块(通过查看源码发现)
//这是com.mysql.jdbc.Driver的静态代码块,只要使用这个类,就会执行这段代码
//而Class.forName("com.mysql.jdbc.Driver")就正好使用到了这个类
static {
    try {
        java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
        throw new RuntimeException("Can't register driver!");
    }
}

注意:我们不需要通过DriverManager调用静态方法registerDriver(),因为只要Driver类被使用,则会执行其静态代码块完成注册驱动mysql5之后可以省略注册驱动的步骤。在jar包中,存在一个java.sql.Driver配置文件,文件中指定了com.mysql.jdbc.Driver

所以后边我们其实可以省略注册驱动的步骤(可以注释掉上个案例的注册驱动的步骤,也可以查询到数据)


案例三

提取工具类,将来我们可能会多次进行数据库的连接操作,而上述的连接操作都是重复多的,作为程序员只要有重复的代码就要减少它(虽然头发也可能随着emmmm.....)

下面的案例利用了配置文件,我们在更改数据库或者密码时就不需要在代码中找了,直接在配置文件中进行修改就行

配置文件

driverClass = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/girls
username = root
password = root

编写工具类

public class JDBCUtils {
    public JDBCUtils() {
    }

    private static String driverClass;
    private static String url;
    private static String username ;
    private static String password ;
    private static Connection conn;

    static {

        try {

            //两种写法
            /*InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("JDBCUtils.properties");*/
            InputStream is = ClassLoader.getSystemResourceAsStream("girlDatabase.properties");

            Properties properties = new Properties();
            properties.load(is);

            driverClass = properties.getProperty("driverClass");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            Class.forName(driverClass);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

    }
    //获取连接的方法
    public static Connection getConnection(){
        try {
            conn = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
    //5.释放资源的方法
    public static void close(Connection conn, Statement stat, ResultSet rs) {
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(stat != null) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

进行测试:

在整个测试中,使用PreparedStatement

public class jdbcTest {
    public static void main(String[] args) throws SQLException {

        //1、获取连接
        Connection connection = JDBCUtils.getConnection();

        //2、获取执行对象,执行sql语句
        String sql = " SELECT name, borndate , phone FROM beauty WHERE name = ? ";
        PreparedStatement pre = connection.prepareStatement(sql);

        //获取用户输入
        System.out.println("请输入你的女神的姓名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.next();

        //给?更改为用户的输入
        pre.setString(1, name);

        //获取结果集
        ResultSet re = pre.executeQuery();

        System.out.println("信息为:");
        //操作结果集中的内容
        while (re.next()) {
            System.out.println(re.getString("name") + "  " + re.getDate("borndate") + "  " + re.getString("phone"));
        }
        //利用 JDBCUtils关闭资源
        JDBCUtils.close(connection,pre,re);
    }
}

4、使用连接池管理连接

为什么使用连接池?

1、传统的JDBC连接的步骤:建立连接、执行sql语句、关闭连接。每一次数据库连接都需要建立和关闭连接,这样的方式会消耗大量的资源和时间。数据库的连接资源并没有得到很好的重发利用

2、数据库连接建立之后都需要关闭,如果在执行操作期间出现异常未能关闭,将会导致数据库系统的内存泄露(数据库内存泄露:数据库进程占用内存不会被释放,导致内存持续增长,最终导致系统性能下降甚至崩溃)
3、不能控制被创建的连接对象数,系统资源会被毫无顾忌的分配出去,连接过多也可能导致内存泄露,服务器崩溃

连接池基本思想(可以尝试自己写一个连接池)


    数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
    数据库连接池在初始化时创建由最小数据库连接数决定的连接对象,无论是否被使用,连接池都保证至少拥有这么多连接对象的数量
    最大数据库连接数量规定连接池最多能由多少连接数,如果申请超过最大连接池数,则这些请求将被加入到等待队列中。

使用连接池的优点:

  1. 提高性能和效率:数据库连接的创建和销毁是一项开销较大的操作。连接池会在系统启动时创建一定数量的连接对象,并在需要时重复利用这些连接,避免了频繁地创建和销毁连接的开销,从而提高了数据库访问的性能和效率。

  2. 提升并发处理能力:数据库连接池可以管理一定数量的连接对象,并使其可供并发的应用程序使用。当有多个并发请求时,连接池可以提供空闲的连接对象,避免了请求之间的等待,从而提升了系统的并发处理能力。

  3. 资源利用率提高:通过连接池,可以限制系统中连接的数量。这样可以避免过多的连接请求导致数据库资源的过度占用。连接对象的复用也可以减少系统资源的浪费,提高了资源利用率。

  4. 连接管理和监控:数据库连接池可以提供连接的管理和监控功能。它可以检查连接的可用性,避免使用已断开或失效的连接。连接池还可以记录连接的使用情况和状态,方便跟踪和排查连接问题,提高系统的可靠性和稳定性。

  5. 容错和恢复能力:在使用连接池的情况下,如果一个连接发生异常或超时,连接池可以关闭该连接,并创建一个新的连接对象来代替。这可以提高系统的容错和恢复能力,确保数据库访问的连续性。

多种开源的数据库连接池介绍

  • JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource 只是一个接口,该接口通常由服务器(Weblogic, WebSphere, Tomcat)提供实现,也有一些开源组织提供实现:

    • DBCP 是Apache提供的数据库连接池。tomcat 服务器自带dbcp数据库连接池。速度相对c3p0较快,但因自身存在BUG,Hibernate3已不再提供支持。

    • C3P0 是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以。hibernate官方推荐使用

    • Proxool 是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点

    • BoneCP 是一个开源组织提供的数据库连接池,速度快

    • Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,但是速度不确定是否有BoneCP快

  • DataSource 通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把 DataSource 称为连接池

  • DataSource用来取代DriverManager来获取Connection,获取速度快,同时可以大幅度提高数据库访问速度。

  • 特别注意:

    • 数据源和数据库连接不同,数据源无需创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可。

    • 当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close(); 但conn.close()并没有关闭数据库的物理连接,它仅仅把数据库连接释放,归还给了数据库连接池。

这里我们主要介绍我们的国之光!!!

Druid(德鲁伊)数据库连接池

吹一下它

Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、Proxool等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,可以说是目前最好的连接池之一。

案例四(第一版)

使用的第一步就是先将它的jar包导入

创建一个lib文件夹(将下载的jar包导入)

 

 添加成功后会出现一个小箭头>

 创建一个druid.properties(如果properties放在同一个包下会无法找到,可以尝试新建一个resource文件和src在同一目录下)

点击idea左上角的File:

 

druid.properties的内容:

driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://127.0.0.1:3306/girls
username = root
password = root

 和之前创建工具类类似,建立DuidUtils工具类(当然你可以用其他命名)


public class DruidUtils {
    //连接池对象
    private static DataSource dataSource = null ;

    //初始化连接池对象
    static{
        //首先获取输入流
        InputStream is = ClassLoader.getSystemResourceAsStream("druid.properties");
        Properties pro = new Properties();
        //读取配置文件
        try {
            pro.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取dataSource
        try {
             dataSource = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    //提供对外连接的方法
    public static Connection getConnection() throws SQLException {
        //熟悉的步骤:获取连接(connection)
        Connection connection = dataSource.getConnection();
        return connection ;
    }

    //提供回收的方法
    public static void freeConnection(Connection connection, Statement stat, ResultSet rs) {
        if(connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(stat != null) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

利用上面的工具类连接数据库

public class TestDruid01 {

    public static void main(String[] args) throws SQLException {
        Connection conn = DruidUtils.getConnection();
        String sql = "select id , name from beauty where name = ?";

        PreparedStatement ps = conn.prepareStatement(sql);

        System.out.println("请输入你的姓名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.next();

        ps.setString(1 , name);
        ResultSet re = ps.executeQuery();
        System.out.println("信息为:");

        while (re.next())
        {
            System.out.println(re.getInt("id") +"\t"+ re.getString("name") );
        }
        DruidUtils.freeConnection(conn , ps , re);
    }
}

 案例四(第一版)结束

案例四(第二版,线程版本...让我在理解理解,后序补上)

在我们利用三层架构设计时,

三层架构是一种常用的软件设计架构模式,它将软件系统划分为表示层(Presentation Layer)、业务逻辑层(Business Logic Layer)和数据访问层(Data Access Layer)三个独立的层次。

5、Apache-DBUtils实现CRUD操作

CRUD是啥不知道了吧,哈哈^v^

CRUD代表创建(Create)、读取(Read)、更新(Update)和删除(Delete)

Apache DBUtils 是 Apache 组织提供的一个开源项目,它是一个用于简化 JDBC 编程的工具库。DBUtils 封装了一系列的 JDBC 操作,提供了简洁易用的 API,使得开发者可以更轻松地进行数据库访问和操作。

DBUtils 的主要特点如下:

  1. 简化的 API:DBUtils 提供了一组简化的 API,摒弃了繁琐的 JDBC 编程,使得数据库的访问和操作更加简洁和易于理解。

  2. 基本 CRUD 操作支持:DBUtils 提供了常见的增删改查操作的封装,开发者只需通过简单的 API 调用就能完成对数据库的操作。

  3. 集成了连接池:DBUtils 默认集成了 DBCP 连接池,可以轻松实现数据库连接的池化管理,提高了数据库访问的性能和效率。

  4. 支持 Bean 和 Map 的映射:DBUtils 提供了灵活的结果集映射机制,可以将数据库查询结果映射为 Java 对象(Bean)或者 Map 数据结构。

  5. 支持事务处理:DBUtils 提供了事务管理的支持,允许开发者通过 API 控制事务的提交和回滚,保证数据的一致性和完整性。

使用 DBUtils 可以大大简化 JDBC 编程的复杂度,减少了重复的代码编写,并提供了连接池和事务处理等功能,同时性能表现优异。


  • API介绍:

    • org.apache.commons.dbutils.QueryRunner

    • org.apache.commons.dbutils.ResultSetHandler

    • 工具类:org.apache.commons.dbutils.DbUtils

工具类DbUtils

提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:

  • public static void close(…) throws java.sql.SQLException: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。

  • public static void closeQuietly(…): 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。

  • public static void commitAndClose(Connection conn)throws SQLException: 用来提交连接的事务,然后关闭连接

  • public static void commitAndCloseQuietly(Connection conn): 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。

  • public static void rollback(Connection conn)throws SQLException:允许conn为null,因为方法内部做了判断

  • public static void rollbackAndClose(Connection conn)throws SQLException

  • rollbackAndCloseQuietly(Connection)

  • public static boolean loadDriver(java.lang.String driverClassName):这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。

 QueryRunner 类

该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。

  • QueryRunner类提供了两个构造器:

    • 默认的构造器

    • 需要一个 javax.sql.DataSource 来作参数的构造器

  • QueryRunner类的常用的方法:

    • 更新

      • public int update(Connection conn, String sql, Object... params) throws SQLException:用来执行一个更新(插入、更新或删除)操作。

    • 插入

      • public <T> T insert(Connection conn,String sql,ResultSetHandler<T> rsh, Object... params) throws SQLException:只支持INSERT语句,其中 rsh - The handler used to create the result object from the ResultSet of auto-generated keys. 返回值: An object generated by the handler.即自动生成的键值

    • 批处理

      • public int[] batch(Connection conn,String sql,Object params)throws SQLException: INSERT, UPDATE, or DELETE语句

      • public <T> T insertBatch(Connection conn,String sql,ResultSetHandler<T> rsh,Object params)throws SQLException:只支持INSERT语句

    • 查询

      • public Object query(Connection conn, String sql, ResultSetHandler rsh,Object... params) throws SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。

ResultSetHandler接口及实现类

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

  • ResultSetHandler 接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)。

  • 接口的主要实现类:

    • ArrayHandler:把结果集中的第一行数据转成对象数组。

    • ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。

    • BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。

    • BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。

    • ColumnListHandler:将结果集中某一列的数据存放到List中。

    • KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。

    • MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。

    • MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List

    • ScalarHandler:查询单个值对象

案例稍等

注意事项(了解):

  1. 避免过度频繁的连接操作:连接数据库是一种资源密集型操作,频繁地打开和关闭连接会导致性能下降。应该尽量减少连接操作的次数,而是通过连接池等方式复用连接,提高系统性能。

  2. 使用预编译语句:预编译语句(PreparedStatement)可以提高数据库查询的性能。它使用占位符,将SQL语句和参数分离,减少了SQL解析的开销,并提供了防止SQL注入的安全性。

  3. 适当处理异常和关闭资源:在使用JDBC时,需要适当地处理异常和关闭资源。确保在代码中使用try-catch-finally块,及时释放数据库连接、语句和结果集等资源,避免资源泄漏和不必要的开销。

  4. 使用事务管理:对于需要保证数据一致性和可靠性的操作,应该使用事务管理来确保数据库操作的原子性、一致性、隔离性和持久性。通过使用JDBC的事务管理API,可以实现对事务的控制。

  5. 合理设计SQL语句:在编写SQL语句时,应该考虑数据库的索引、关联查询等因素。选择合适的索引和编写优化的SQL语句,可以提高数据库查询和更新操作的性能。

  6. 安全性考虑:在构建动态SQL语句时,应避免使用字符串拼接的方式,以防止SQL注入攻击。可以使用预编译语句或者参数化查询来确保输入的安全性。

 总结

主要内容:

  1. DriverManager:JDBC的入口点,用于获取数据库连接。
  2. Connection:表示与数据库的连接,用于发送SQL语句和接收结果。
  3. Statement和PreparedStatement:用于执行静态SQL语句,执行数据库查询和更新操作。
  4. ResultSet:存储查询结果集,提供了对查询结果的访问和操作。
  5. CallableStatement:用于执行数据库中的存储过程。
  6. Metadata:提供了关于数据库和查询结果的元数据信息,如表结构、列名等。
  7. 事务管理:提供了控制和管理数据库事务的功能,确保数据的一致性和可靠性。

应用场景:

  1. 数据库查询和更新:通过JDBC可以执行各种数据库查询和更新操作,如数据检索、插入、修改和删除等。

  2. 数据库事务管理:使用JDBC可以控制和管理数据库事务,确保数据的一致性和完整性,在多个操作之间进行原子性控制。

  3. 数据库连接池:JDBC可以与连接池配合使用,提高数据库连接的性能和效率。

  4. 数据库连接和资源的管理:使用JDBC可以在应用程序中管理数据库连接和资源的创建、使用和释放。这包括了关闭连接、释放资源、错误处理等操作,保证了程序的正确性和稳定性。

  5. 数据库元数据的获取:通过JDBC可以获取数据库的元数据信息,如表结构、列名、约束等,方便进行动态的数据访问和操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值