Java JDBC 编程指北,java编程面试公开书

}

}

}

新增数据后,接着查询数据,得到如下结果,可以看到我们新插入的数据成功加入到了数据库中!

删除数据

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

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();

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

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

img
img

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip1024b 备注Java获取(资料价值较高,非无偿)
img

最后

手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友

image.png

if (preparedStatement != null) {

try {

preparedStatement.close();

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-Rb9xLesA-1711551474236)]
[外链图片转存中…(img-WOYfPnTq-1711551474237)]
[外链图片转存中…(img-qriLpkBF-1711551474237)]
[外链图片转存中…(img-ERbizgRW-1711551474238)]

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

[外链图片转存中…(img-yYMHtZnZ-1711551474238)]
[外链图片转存中…(img-rZc9yNu0-1711551474239)]

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip1024b 备注Java获取(资料价值较高,非无偿)
[外链图片转存中…(img-dUzFzXeO-1711551474239)]

最后

手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友

[外链图片转存中…(img-7bgkR3Go-1711551474240)]

  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值