Java与数据库的桥梁:JDBC使用详解

JDBC

在这篇文章中,我们将深入探讨JDBC(Java Database Connectivity)的核心概念和实际应用。

你将了解如何通过JDBC实现数据库的连接、操作和管理,从而使你的Java应用程序与各种数据库无缝对接。

无论是执行SQL查询、处理结果集,还是处理事务,我们将逐步解析每个环节,提供实用示例和最佳实践。

掌握JDBC不仅能提升你的数据操作能力,更能为你的项目带来更高的灵活性和效率,让我们一起揭开这一强大工具的面纱,开启你的数据库编程之旅!

JDBC简介

为了便于程序保存和读取数据,而且能直接通过条件快速查询大指定的数据,就出现了数据库(Datebase)这种专门用于集中存取和查询的软件。

JDBC是Java程序访问数据库的标准接口。

使用Java程序访问数据库时,Java代码并不是直接通过TCP连接去访问数据库,而是通过JDBC接口来访问数据库的,而JDBC接口则通过JDBC驱动来实现真正对数据库的访问。

JDBC接口是Java标准库自带的,具体的JDBC驱动是由数据库厂商提供的从代码上来看,JDBC就是定义了一组接口,某个具体的JDBC驱动就是实现这些JDBC接口的类。

MySQL的JDBC驱动就是一个jar包,它本身也是纯Java编写的。我们只需要引入这个JDBC驱动的jar包就可以正常访问MySQL服务器。

我们自己编写的代码只需要引用Java标准库提供的java.sql包下面的相关接口,就可以间接地通过JDBC驱动jar包,通过网络,来访问MySQL服务器了,所有的复杂的网络通讯也都被封装到了JDBC驱动中。

现在Maven的依赖最新版本号是8.0.33。

</dependency>        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>8.0.33</version>            <scope>runtime</scope></dependency>

JDBC连接

Connection

Connection代表一个JDBC连接,它相当于Java程序到数据库的连接(通常是TCP连接)。

打开一个Connection时,需要准备URL、用户名和密码,才能成功连接到数据库。

核心代码

核心代码是DriverManager提供的静态方法getConnection()。

DriverManager会自动扫描classpath,找到所有的JDBC驱动,然后根据我们传入的URL自动挑选一个合适的驱动。

因为JDBC连接是一种昂贵的资源,所以使用后要及时释放,所以使用try (resource)来自动释放。

class Main{    public static void main(String[] args) throws SQLException {        String JDBC_URL = "jdbc:mysql://localhost:3306/learnjdbc?useSSL=false&serverTimezone=UTC";//要连接已创建的数据库,我这个test数据库是已经创建好的。        String JDBC_USER = "root";//root是默认的超级用户        String JDBC_PASSWORD = "11111111";//自定义密码,千万设置完别忘了        Connection conn = null;        try {            // 获取连接            conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);            System.out.println("连接成功!");            // TODO: 访问数据库...        } catch (SQLException e) {            e.printStackTrace();        } finally {            // 关闭连接            if (conn != null) {                try {                    conn.close();                } catch (SQLException e) {                    e.printStackTrace();                }            }        }    }}

JDBC查询

代码步骤:

1.通过Connection提供的createStatement()方法创建一个Statement对象,用于执行一个查询;

2.执行Statement对象提供的executeQuery("SELECT * FROM students")并传入SQL语句,执行查询并获得返回的结果集,使用ResultSet来引用这个结果集;

3.反复调用ResultSet的next()方法并读取每一行结果。

注意:

因为Connection、Statement、ResultSet都是许哟啊关闭的资源,所以需要嵌套使用try,确保即时关闭,所以显得繁琐。

ResultSet获取列时,是从1开始的。

ResultSet获取列时,必须根据select的列对应的位置调用getLong()、getString()这些方法,否则对应位置的数据类型不对,将报错。

        Connection conn = null;        try {            // 获取连接            conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);            System.out.println("连接成功!");            // TODO: 访问数据库...            Statement statement=null;            try {                statement = conn.createStatement();                ResultSet result=null;                try {                    result = statement.executeQuery("select * from students");                    while (result.next()){                        long id=result.getLong(1);                        String name=result.getString(2);                        long gender=result.getLong(3);                        long grade=result.getLong(4);                        int score=result.getInt(5);                        System.out.println(id+" "+name+" "+gender+" "+grade+" "+score);                    }                } catch (SQLException e) {                    throw new RuntimeException(e);                } finally {                    if (result!=null)                        try {                            result.close();                        } catch (SQLException e) {                            throw new RuntimeException(e);                        }                }            } catch (SQLException e) {                throw new RuntimeException(e);            } catch (RuntimeException e) {                throw new RuntimeException(e);            }        } catch (SQLException e) {            e.printStackTrace();        } finally {            // 关闭连接            if (conn != null) {                try {                    conn.close();                } catch (SQLException e) {                    e.printStackTrace();                }            }        }

SQL注入

为了避免SQL注入攻击,和statement拼接字符串非常容易引发SQL注入问题。

所以使用Java对数据库进行操作时,必须使用PreparedStatement,严禁任何通过参数拼字符串的代码!!!!

            // TODO: 访问数据库...            PreparedStatement ps=null;            ps = conn.prepareStatement("select * from students where id>? and score>=?");            ps.setObject(1,2);            ps.setObject(2,60);            ResultSet result=null;            result=ps.executeQuery();            while (result.next()){                long id=result.getLong(1);                String name=result.getString(2);                long gender=result.getLong(3);                long grade=result.getLong(4);                int score=result.getInt(5);                System.out.println(id+" "+name+" "+gender+" "+grade+" "+score);            }

数据类型

使用JDBC的时候,我们需要在Java数据类型和SQL数据类型之间进行转换。JDBC在java.sql.Types定义了一组常量来表示如何映射SQL数据类型。

JDBC的增删改查

// TODO: 访问数据库...PreparedStatement ps=null;            ps = conn.prepareStatement("select * from students where id>? and score>=?");            ps.setObject(1,2);            ps.setObject(2,60);            ResultSet result=null;            result=ps.executeQuery();            while (result.next()){                long id=result.getLong(1);                String name=result.getString(2);                long gender=result.getLong(3);                long grade=result.getLong(4);                int score=result.getInt(5);                System.out.println(id+" "+name+" "+gender+" "+grade+" "+score);            }

// TODO: 访问数据库...            PreparedStatement ps=null;            ps=conn.prepareStatement("INSERT INTO students (grade, name, gender,score) VALUES (?,?,?,?)",Statement.RETURN_GENERATED_KEYS);            ps.setObject(1, 1); // grade            ps.setObject(2, "olderhard"); // name            ps.setObject(3, 1); // gender            ps.setObject(4, 90); // score            int n = ps.executeUpdate();            ResultSet result=null;            result=ps.getGeneratedKeys();            if (result.next()){                System.out.println(result.getLong(1));            }

// TODO: 访问数据库...            PreparedStatement ps=null;            ps=conn.prepareStatement("UPDATE students SET name=? WHERE id=?");            ps.setObject(1,"bob");            ps.setObject(2,14);            iint n=ps.executeUpdate();

// TODO: 访问数据库...            PreparedStatement ps=null;            ps=conn.prepareStatement("DELETE FROM students WHERE id=?");            ps.setObject(1,15);            int n=ps.executeUpdate();

JDBC事务

数据库事务时由若干个SQL语句构成的一个操作序列。数据库系统保证在一个事务中所有SQL要么全部执行成功,要么全部不执行,即数据库事务具有ACID特性,原子性,一致性,隔离性,持久性。

要在JDBC中执行事务,本质上就是如何把多条SQL包裹在一个数据库事务中执行。

注意关键点即可:连接成功后;conn.setAutoCommit(false);之后对数据库操作完成后;就conn.commit(),提交事务;再加一个异常回滚conn.rollback()。

Connection conn = null;        PreparedStatement p1=null;        PreparedStatement p2=null;        try {            // 获取连接            conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);            System.out.println("连接成功!");            conn.setAutoCommit(false);  //关闭自动提交模式            // TODO: 一系列对数据库的操作...            conn.commit();  //提交事务        } catch (SQLException e) {            if(conn!=null){                try {                    conn.rollback();                    System.out.println("Transaction rolled back.");                } catch (SQLException ex) {                    throw new RuntimeException(ex);                }            }        }

JDBC批处理

在JDBC代码中,我们可以利用SQL数据库的特性,把同一个SQL但参数不同的若干次操作合并为一个batch执行。

使用JDBC的batch操作会大大提高执行效率,对内容相同,参数不同的SQL,要优先考虑batch操作。

// TODO: 访问数据库...            PreparedStatement ps=null;            ps=conn.prepareStatement("INSERT INTO students (name, gender, grade, score) VALUES (?, ?, ?, ?)");            for (Student s : students) {                ps.setString(1, s.name);                ps.setBoolean(2, s.gender);                ps.setInt(3, s.grade);                ps.setInt(4, s.score);                ps.addBatch(); // 添加到batch            }            // 执行batch:            int[] ns = ps.executeBatch();            for (int n : ns) {                System.out.println(n + " inserted."); // batch中每个SQL执行的结果数量            }

JDBC连接池

与多线程的线程池原因类似,在执行JDBC的增删改查的操作时,如果每一次操作都来一次打开连接,操作,关闭连接。那么创建和销毁JDBC连接的开销就太大了。为了避免频繁地创建和销毁JDBC连接,我们可以通过连接池复用已经创建好的连接。

JDBC连接池有一个标准的接口javax.sql.DataSource,要使用JDBC连接池,我们必须选择一个JDBC连接池的实现。

常用的JDBC连接池有:HikariCP、C3P0、BoneCP、Druid

之后我们通过创建一个DATa Source实例(对象),这个就是连接池。

HikariConfig config = new HikariConfig();config.setJdbcUrl("jdbc:mysql://localhost:3306/test");config.setUsername("root");config.setPassword("password");config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时:1秒config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时:60秒config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数:10DataSource ds = new HikariDataSource(config);

如何使用连接池?

类似这个

conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);

这样使用

conn = config.getConnection();
#Java##数据库##Java后端#
Java面试题 文章被收录于专栏

本专栏汇总了大量的Java面试题和Java面经,希望对大家有所帮助!

全部评论

相关推荐

点赞 评论 收藏
分享
点赞 2 评论
分享
牛客网
牛客企业服务