Java JDBC 编程指北,京东java面试问题大全及答案大全

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

/**

  • @author : cunyu

  • @version : 1.0

  • @className : DeleteTest

  • @date : 2021/4/23 15:23

  • @description : 删除数据

*/

public class DeleteTest {

public static void main(String[] args) {

try {

Class.forName(“com.mysql.cj.jdbc.Driver”);

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

String url = “jdbc:mysql://localhost:3306/javalearning?charactersetEncoding=UTF-8”;

String username = “root”;

String password = “0908”;

String deleteString = “DELETE FROM students WHERE id = ?”;

try (Connection connection = DriverManager.getConnection(url, username, password); PreparedStatement preparedStatement = connection.prepareStatement(deleteString)😉 {

System.out.println(“连接成功”);

preparedStatement.setLong(1, 101);

preparedStatement.executeUpdate();

System.out.println(“删除成功”);

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

删除数据后,接着查询数据,得到如下结果,可以看到 id = 101 的数据列已经被删除了,说明我们删除数据成功了!

修改数据

修改数据的方式同删除数据和新增数据基本一致,最大的区别在于 SQL 语句的不同,修改操作利用的是 UPDATE 语句,能一次更新若干列。

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

/**

  • @author : cunyu

  • @version : 1.0

  • @className : UpdateTest

  • @date : 2021/4/23 15:23

  • @description : 更新数据

*/

public class UpdateTest {

public static void main(String[] args) {

try {

Class.forName(“com.mysql.cj.jdbc.Driver”);

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

String url = “jdbc:mysql://localhost:3306/javalearning?charactersetEncoding=UTF-8”;

String username = “root”;

String password = “0908”;

String updateString = “UPDATE students SET name = ? WHERE id = ?”;

try (Connection connection = DriverManager.getConnection(url, username, password); PreparedStatement preparedStatement = connection.prepareStatement(updateString)😉 {

System.out.println(“连接成功”);

preparedStatement.setString(1, “村雨遥”);

preparedStatement.setLong(2, 201);

preparedStatement.executeUpdate();

System.out.println(“更新成功”);

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

修改数据后,接着查询数据,得到如下结果,可以看到 id = 201 对应的数据列中,name 从小黄变成了村雨遥,说明数据更新成功。

注意

当我们的数据库表设置自增主键后,在新增数据时无需指定主键也会自动更新。但是在获取自增主键的值时,不能先插入再查询,否则可能会导致冲突。要正确获取自增主键,需要在创建 PreparedStatement 时,指定一个标志位 RETURN_GENERATED_KEYS,用于表示 JDBC 驱动必须返回插入的自增主键。

假设我们创建表时,设置了自增长的键:

CREATE TABLE students(

id int(11) AUTO_INCREMENT,

);

此时无论是 executeQuery() 还是 execureUpdate() 都不会返回这个自增长的 id,所以需要在创建 PreparedStatement 对象时加入 Statement.RETURN_GENERATED_KEYS 参数以确保会返回自增长 ID,然后通过 getGeneratedKeys 获取该字段;

import java.sql.*;

/**

  • @author : cunyu

  • @version : 1.0

  • @className : QueryTest

  • @date : 2021/4/23 18:01

  • @description : 自增主键查询

*/

public class QueryTest {

public static void main(String[] args) {

try {

Class.forName(“com.mysql.cj.jdbc.Driver”);

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

String url = “jdbc:mysql://localhost:3306/javalearning?characterEncoding=UTF-8”;

String username = “root”;

String password = “12345”;

String queryString = “INSET INTO students VALUES(null,?,……)”;

try (Connection connection = DriverManager.getConnection(url, username, password); PreparedStatement preparedStatement = connection.prepareStatement(queryString, Statement.RETURN_GENERATED_KEYS); ResultSet resultSet = preparedStatement.getGeneratedKeys()😉 {

System.out.println(“连接成功”);

preparedStatement.setString(1, “村雨遥”);

……

preparedStatement.executeUpdate();

System.out.println(“查询到的信息如下:”);

while (resultSet.next()) {

// 查询到的结果索引从 1 开始

System.out.println(“id:” + resultSet.getLong(1));

}

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

JDBC 工具类

观察上面的代码,我们可以注意到每次都需要注册驱动、传递参数,关闭连接等操作,为了提高工具通用性,我们利用配置文件来配置数据库相关信息,然后创建一个 JDBC 工具类来简化上述操作。

  1. 首先在 src 目录下创建一个配置文件 jdbc.properties,并且填入数据库的相关信息;

url=jdbc:mysql://localhost/demo?characterEncoding=UTF-8

user=root

password=“12345”

driver=com.mysql.jdbc.cj.Driver

  1. 创建工具类

import java.io.FileReader;

import java.io.IOException;

import java.net.URL;

import java.sql.*;

import java.util.Properties;

/**

  • @author : cunyu

  • @version : 1.0

  • @className : JDBCUtils

  • @date : 2021/4/24 15:10

  • @description : JDBC 工具类

*/

public class JDBCUtils {

// 配置文件中的各个参数

private static String url;

private static String user;

private static String password;

private static String driver;

// 静态代码块

static {

try {

// 读取配置文件并获取参数值

// 创建集合类

Properties properties = new Properties();

// 获取配置文件所在位置

ClassLoader classLoader = JDBCUtils.class.getClassLoader();

URL resource = classLoader.getResource(“jdbc.properties”);

String path = resource.getPath();

System.out.println(“配置文件所在位置”);

// 加载配置文件

properties.load(new FileReader(path));

// 获取参数的值并赋值

url = properties.getProperty(“url”);

user = properties.getProperty(“user”);

password = properties.getProperty(“password”);

driver = properties.getProperty(“driver”);

// 注册驱动

Class.forName(driver);

} catch (IOException | ClassNotFoundException e) {

e.printStackTrace();

}

}

/**

  • @param

  • @return 连接对象

  • @description 获取连接

  • @date 2021/4/24 15:24

  • @author cunyu1943

  • @version 1.0

*/

public static Connection getConnection() {

try {

return DriverManager.getConnection(url, user, password);

} catch (SQLException throwables) {

throwables.printStackTrace();

}

return null;

}

/**

  • @param preparedStatement 预声明

  • @param connection 连接对象

  • @return

  • @description 关闭连接

  • @date 2021/4/24 15:27

  • @author cunyu1943

  • @version 1.0

*/

public static void close(PreparedStatement preparedStatement, Connection connection) {

if (preparedStatement != null) {

try {

preparedStatement.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (connection != null) {

try {

connection.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

/**

  • @param resultSet 结果集

  • @param preparedStatement 预声明对象

  • @param connection 连接对象

  • @return

  • @description 关闭连接

  • @date 2021/4/24 15:28

  • @author cunyu1943

  • @version 1.0

*/

public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {

if (resultSet != null) {

try {

resultSet.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (preparedStatement != null) {

try {

preparedStatement.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (connection != null) {

try {

connection.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

}

JDBC 事务


事务 4 大特性

事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行结果必须使数据库从一种一致性状态切换到另一中一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。事务能够在数据库提交工作时确保要么所有修改都保存,要么所有修改都不保存。即事务是逻辑上的一组操作,要么都执行,要么都不执行

  1. 原子性(Atomicity)

原子性是整个数据库事务中不可分割的工作单位,只有事务中的所有的数据库操作都执行成功,才代表整个事务成功,如果其中任一环节执行失败,那么就算已经执行成功的 SQL 语句也必须撤销,回滚到事务执行前的状态。即原子性能够保证 动作要么全部完成,要么完全不起作用。 即事务是最小的执行单位,不允许分割

  1. 一致性(Consistency)

指事务将数据库从一种一致性状态变为另一种一致性状态。在事务开始前后,数据库的完整性约束未被破坏。在事务执行前后,数据能够保持一致,多个事务对统一数据读取的结果相同

  1. 隔离性(Isolation)

并发访问数据库时,隔离性要求每个读写事务对其他事务的操作对象能够相互分离,即一个用户的事务不被其他事务所干扰,各并发事务间数据库是独立的;

  1. 持久性(Durability)

表示事务一旦被提交,其结果就是永久性的,它对数据库中数据的改变是持久的,即便数据库发生故障也不应该对其产生影响;

脏读、幻读 & 不可重复读

了解事务隔离级别之前,先来看看这几个读的概念:

  1. 脏读(Dirty Read)

表示某一事务已经更新了一份数据,另一个事务在此时读取了同一份数据。当前一个事务撤销操作后,就会导致后一个事务所读取的数据不正确。

  1. 幻读(Phantom Read)

在一个事务的两次查询中数据量不一致,假如有一个事务查询了几列数据,同时另一个事务中在此时查询了新的数据,则查询事务在后续查询中,就会发现数据比最开始的查询数据更丰富。

  1. 不可重复读(Non-repeatable Read)

一个事务中两次查询数据不一致,有可能是因为两次查询过程中插入了一个更新原有数据的事务。

注意:不可重复读和幻读的区别在于:

不可重复读的重点在于修改, 比如多次读取一条记录发现其中某些列的值被修改,而 幻读的重点在于新增或删除,比如多次读取一条记录发现记录增多或减少了。

隔离级别

SQL 标准定义了 4 个隔离级别,隔离级别从低到高分别是:

  1. READ-UNCOMMITTED(读取未提交)

最低的隔离级别,允许读取尚未提交的数据变更,可能导致脏读、幻读或不可重复读

  1. READ-COMMITTED(读取已提交)

允许读取并发事务已经提交的数据,能够阻止脏读,但可能导致幻读或不可重复读

  1. REPEATABLE-READ(可重复读)

对同一字段的多次读取结果时一致的,除非数据是被本身事务自己所修改,能够阻止脏读和不可重复读,但可能导致幻读

  1. SERIALIZABLE(可串行化)

最高的隔离级别,完全服从 ACID 的隔离级别,所有事务依次逐个执行,这样事务之间就完全不可能产生干扰,能够防止脏读、幻读以及不可重复读

以下是 SQL 隔离级别和各种读之间的关系:

| 隔离级别 | 脏读 | 不可重复读 | 幻读 |

| — | — | — | — |

| READ-UNCOMMITTED | ✔ | ✔ | ✔ |

| READ-COMMITTED | ❌ | ✔ | ✔ |

| REPEATABLE-READ | ❌ | ❌ | ✔ |

| SERIALIZABLE | ❌ | ❌ | ❌ |

实例

关于回滚,主要涉及 Connection 对象,常用的三个方法如下:

| 返回值 | 方法 | 描述 |

| — | — | — |

| void | setAutoCommit(boolean autoCommit) | 设定连接的自动提交模式,true 表示自动提交,false 表示手动提交 |

| void | commit() | 使上次提交/回滚以来所做的所有更改成为永久更改,并释放此 Connection 对象当前持有的所有数据库锁 |

| void | rollback() | 撤销当前十五中所做的所有更改,并释放此 Connection 对象当前持有的所有数据库锁 |

以下是一个回滚实例,我们当我们第一次插入一条数据时,由于是新数据,所以不会报错,但是如果我们执行一次程序之后再次执行,此时按理来说就会报错,因为插入的数据重复,这时候利用事务就可以十分方便的解决这个问题,我们设置插入出错就回滚到未出错之前的状态,这样就能保证插入数据不会报错了。

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

/**

  • @author : cunyu

  • @version : 1.0

  • @className : AffairTest

  • @date : 2021/4/23 22:35

  • @description : 事务

*/

public class AffairTest {

public static void main(String[] args) {

try {

Class.forName(“com.mysql.cj.jdbc.Driver”);

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

String url = “jdbc:mysql://localhost:3306/javalearning?characterEncoding=UTF-8”;

String username = “root”;

String password = “12345”;

String insertString = “INSERT INTO students VALUES (?,?,?,?,?)”;

Connection connection = null;

PreparedStatement preparedStatement = null;

try {

connection = DriverManager.getConnection(url, username, password);

// 关闭自动提交

connection.setAutoCommit(false);

preparedStatement = connection.prepareStatement(insertString);

System.out.println(“连接成功”);

// 依次插入数据

preparedStatement.setLong(1, 401);

preparedStatement.setString(2, “小紫”);

preparedStatement.setInt(3, 0);

preparedStatement.setLong(4, 4);

preparedStatement.setLong(5, 88);

preparedStatement.executeUpdate();

// 如果没有出错,则提交事务

connection.commit();

System.out.println(“插入数据成功”);

} catch (SQLException throwables) {

// 一旦出错,则回滚事务

try {

connection.rollback();

} catch (SQLException e) {

e.printStackTrace();

}

} finally {

// 最后关闭连接

if (connection != null) {

try {

connection.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (preparedStatement != null) {

try {

preparedStatement.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

}

}

除了上述回滚的方式外,JDBC 还支持设置保存点的方式,我们可以使用事务回滚到指定的保存点,主要涉及的方法如下:

  • setSavepoint(String savePointName):创建新的保存点,返回一个 SavePoint 对象;

  • rollback(String savePointName):回滚到指定保存点;

连接池


简介

当我们使用多线程时,每个线程如果都需要连接数据库来执行 SQL 语句,那么每个线程都得创建一个连接,然后在使用之后关闭。这个创建和关闭连接的过程是十分耗时的,一旦多线程并发时,就容易导致系统卡顿。针对这一问题,提出使用数据库连接池。数据库连接池,其实就相当于一个集合,是一个存放数据库连接的容器。当我们的系统初始化好之后,集合就被创建,集合中会申请一些连接对象,当用户来访问数据库时,从集合中获取连接对象,一旦用户访问完毕,就将连接对象返还给容器。

使用数据库连接池的优点:一来是节约资源,二来提高了用户访问的效率。

常用数据库连接池

C3P0
  1. 导包

首先需要导包,先去下载 C3P0 对象的 jar 包,下载地址:https://sourceforge.net/projects/c3p0/,然后将其中的如下两个包导入;

  1. 定义配置文件

创建 C3P0 对应的配置文件,注意:配置文件一般放在 src 路径下,而且文件的名称要必须为以下其中的一个:

  • c3p0.properties

  • c3p0-config.xml

com.mysql.cj.jdbc.Driver

jdbc:mysql://localhost:3306/javalearning?characterEncoding=UTF-8

root

0908

5

10

3000

  1. 创建连接池对象

  2. 获取连接对象

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;

import java.sql.Connection;

import java.sql.SQLException;

/**

  • @author : cunyu

  • @version : 1.0

  • @className : C3POTest

  • @date : 2021/4/24 16:01

  • @description : C3PO 连接池

*/

public class C3POTest {

public static void main(String[] args) {

// 创建数据库连接池对象

DataSource dataSource = new ComboPooledDataSource();

// 获取连接对象

try {

Connection connection = dataSource.getConnection();

System.out.println(connection);

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

Druid
  1. 导包

总结

以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。现在重新好好复习手上的面试大全资料(含JAVA、MySQL、算法、Redis、JVM、架构、中间件、RabbitMQ、设计模式、Spring等),现在起闭关修炼半个月,争取早日上岸!!!

下面给大家分享下我的面试大全资料

  • 第一份是我的后端JAVA面试大全

image.png

后端JAVA面试大全

  • 第二份是MySQL+Redis学习笔记+算法+JVM+JAVA核心知识整理

字节二面拜倒在“数据库”脚下,闭关修炼半个月,我还有机会吗?

MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理

  • 第三份是Spring全家桶资料

字节二面拜倒在“数据库”脚下,闭关修炼半个月,我还有机会吗?

MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

连接池对象

DataSource dataSource = new ComboPooledDataSource();

// 获取连接对象

try {

Connection connection = dataSource.getConnection();

System.out.println(connection);

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

Druid
  1. 导包

总结

以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。现在重新好好复习手上的面试大全资料(含JAVA、MySQL、算法、Redis、JVM、架构、中间件、RabbitMQ、设计模式、Spring等),现在起闭关修炼半个月,争取早日上岸!!!

下面给大家分享下我的面试大全资料

  • 第一份是我的后端JAVA面试大全

[外链图片转存中…(img-LwXntd8N-1713604879066)]

后端JAVA面试大全

  • 第二份是MySQL+Redis学习笔记+算法+JVM+JAVA核心知识整理

[外链图片转存中…(img-gvsvchhO-1713604879067)]

MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理

  • 第三份是Spring全家桶资料

[外链图片转存中…(img-LRQSwSyl-1713604879067)]

MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-46hpu5KF-1713604879068)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 15
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值