Java JDBC
Java JDBC
简介
JDBC全称: Java Data Base Connectivity,Java 数据库连接;
JDBC是Sun公司提供的一套用于数据库操作的接口,Java程序可以通过JDBC接口连接到数据库并执行SQL语句;
JDBC的本质是:官方(sun公司)定义的接口,数据库厂商去实现接口,提供数据库驱动jar包;
我们可以使用JDBC接口编程,真正执行的代码是驱动jar包中的实现类;
JDBC的工作原理示意图如下:
JDBC的好处:
- 各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发;
- 可随时替换底层数据库,访问数据库的Java代码基本不变;
JDBC连接数据库
JDBC连接数据的细致流程使用步骤:
- 读取配置
- 加载驱动
- 连接数据库
// 1. 读取配置,即获取数据库的连接信息
private static String url = "jdbc:mysql://localhost:3306/yygh_user";
private static String username = "root";
private static String password = "your password";
// 2. 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 3. 获取连接
Connection connection = DriverManager.getConnection(url, username, password);
JDBC的URL格式:
JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。
- 第一部分是jdbc,这是固定的;
- 第二部分是数据库名称,那么连接mysql数据库,第二部分当然是mysql了;
- 第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及DATABASE名称(mydb)组成。
如果连接的是本地的Mysql数据库,并且连接使用的端口是3306,那么的url地址可以简写为:
jdbc: mysql://数据库,
例如:jdbc: mysql://localhost:3306/mydb
导入驱动包
第0步:首要步骤!!
- 在当前项目根目录下建立一个“lib”文件夹;
- 把“mysql-connector-java-5.1.18.jar”复制到该文件夹中;
- 选中该jar包,右键,执行“build Path”才能真正导入该jar包。才可以开始执行以下的步骤!
为什么要导入这个jar包?
- 因为我们在程序中要使用mysql的驱动,而mysql的驱动在jar包中,所以需要导入jar包;
- 里面提供了MySQL的实现类:com.mysql.jdbc.Driver;
- 我们可以在mysql的官网上下载mysql的驱动包,也可以在maven仓库中下载mysql的驱动包。
注册驱动
注册驱动有两种方式:
- 注册驱动的方式一:使用Class.forName()方法注册驱动;
- 注册驱动的方式二:使用DriverManager.registerDriver()方法注册驱动;
注意
- JDBC规范定义驱动接口在java.sql.Driver,也就是你要操作数据库的所有方法都要在这个包下查找。
注册驱动法一:创建驱动对象,直接连接数据库
package com.basic.jdbc;
import com.mysql.jdbc.Driver;
import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
@Slf4j
public class JdbcMethodOne {
private static final Logger logger = LoggerFactory.getLogger(JdbcMethodOne.class);
//数据库连接信息
private static String url = "jdbc:mysql://localhost:3306/yygh_user";
private static String username = "root";
private static String password = "your password";
private static Connection connect;
//使用驱动程序链接测试
public static void main(String[] args){
try {
//1.创建驱动程序类对象;
Driver driver = new Driver();
//2.设置用户名和密码
Properties properties = new Properties();
properties.setProperty("user", username);
properties.setProperty("password", password);
//3.连接数据库,返回连接对象
connect = driver.connect(url, properties);
System.out.println(connect.toString());
}catch (SQLException e){
logger.error(String.valueOf(e));
}finally {
try {
connect.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
不推荐使用这种注册方式:
- 通过查询驱动包中的Driver类的源码可知:该类的static代码块中已经执行了“DriverManager.registerDriver(driver);”,那么这就相当于注册了两次,也就是在内存中会有两个Driver对象,冗余了
注册驱动法二: 使用驱动管理器类连接数据库
package com.basic.jdbc;
import com.mysql.jdbc.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JdbcMethodTwo {
private static String url = "jdbc:mysql://localhost:3306/yygh_user";
private static String username = "root";
private static String password = "your password";
private static Driver driver;
public static void main(String[] args) throws SQLException {
try {
driver = new Driver();
// 1.注册驱动程序(可以注册多个驱动程序)
DriverManager.registerDriver(driver);
//注意,通过查询驱动包中的Driver类的源码可知:该类的static代码块中已经执行了“DriverManager.registerDriver(driver);”,那么这就相当于注册了两次,冗余了
//2.获取连接
java.sql.Connection connect = DriverManager.getConnection(url, username, password);
System.out.println(connect.toString());
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
//Removes the specified driver from the DriverManager's list of registered drivers.
DriverManager.deregisterDriver(driver);
}
}
}
不推荐使用这种注册方式:
- 硬编码,后期不易于程序扩展和维护
- 通过查询驱动包中的Driver类的源码可知:该类的static代码块中已经执行了“DriverManager.registerDriver(driver);”,那么这就相当于注册了两次,也就是在内存中会有两个Driver对象,冗余了
- 程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
注册驱动法三: 使用加载驱动程序类来注册驱动程序
package com.basic.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JdbcMethodTri {
private static String url = "jdbc:mysql://47.93.122.157:3306/yygh_user";
private static String username = "root";
private static String password = "shart1314";
private static Connection connection;
public static void main(String[] args) {
try {
// 1.通过得到字节码对象的方式加载静态代码块,从而注册驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 2.通过加载驱动程序类连接到具体的数据库
connection = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 3.关闭连接
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
底层原理:
- 通常开发我们使用Class.forName() 加载一个使用字符串描述的驱动类。
- 如果使用Class.forName()将类加载到内存,该类的静态代码将自动执行。
- 通过查询com.mysql.jdbc.Driver源码,我们发现Driver类“主动”将自己进行注册。
- 结论:推荐使用
JDBC操作数据库
基本步骤:
- 加载JDBC驱动程序
- 建立数据库连接Connection
- 创建执行SQL的语句Statement
- 处理执行结果ResultSet/int
前提准备
在 resource 目录新建个配置文件,application.properties:
#value值不要有双引号("")和分号(;)
jdbc.url=jdbc:mysql://xxxx:3306/yygh_user
jdbc.username=root
jdbc.password=xxxxxx
新建个 工具类,主要功能就是获取连接和关闭连接:
package com.basic.jdbc.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtil {
public static Connection getConn(){
Properties properties = new Properties();
try {
//使用 JDBCUtil 类的类加载器获取 application.properties 文件的输入流。getResourceAsStream 方法会在类路径下查找指定名称的文件,若找到则返回其输入流。
InputStream resourceAsStream = JDBCUtil.class.getClassLoader().getResourceAsStream("application.properties");
// 调用 Properties 对象的 load 方法,将输入流中的属性加载到 properties 对象中。该方法会解析输入流中的键值对,格式通常为 key=value。
properties.load(resourceAsStream);
String url = properties.getProperty("jdbc.url");
String username = properties.getProperty("jdbc.username");
String password = properties.getProperty("jdbc.password");
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//连接数据库
Connection connection = DriverManager.getConnection(url, username, password);
return connection;
} catch (IOException e) {
System.out.println("未找到配置文件");
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
System.out.println("驱动类无法找到");
throw new RuntimeException(e);
} catch (SQLException e) {
System.out.println("数据库连接失败");
throw new RuntimeException(e);
}
}
public static void close(Connection connection, Statement statement, ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
增-插入操作(insert)
主要演示单条插入和批量插入数据:
package com.basic.jdbc.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @description: 单条插入和批量插入数据
*/
public class SqlInsert {
public void insert() throws SQLException {
Connection connection = null;
//1.获取conn
connection = JDBCUtil.getConn();
//2.sql 语句,占位符
String sql = "INSERT INTO user_login_record (`user_id`,`create_time`,`update_time`,`is_deleted`) VALUES (?, ?, ?, ?)";
// 3.获取sql语句对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//4.填入字段内容
// 第一个占位符字段,Int类型
preparedStatement.setInt(1,100);
// 第二个占位符字段,Date类型
preparedStatement.setDate(2,new java.sql.Date(System.currentTimeMillis()));
// 第二个占位符字段,Date类型
preparedStatement.setDate(3,new java.sql.Date(System.currentTimeMillis()));
// 第四个占位符字段,Int类型
preparedStatement.setInt(4,0);
//5,执行sql
preparedStatement.executeUpdate();
JDBCUtil.close(connection,preparedStatement,null);
}
public void insertBatch() throws SQLException {
Connection connection = null;
connection = JDBCUtil.getConn();
//关闭自动提交
connection.setAutoCommit(false);
String sql = "INSERT INTO user_login_record (`user_id`,`create_time`,`update_time`,`is_deleted`) VALUES (?, ?, ?, ?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < 10; i++) {
preparedStatement.setInt(1,100+i);
preparedStatement.setDate(2,new java.sql.Date(System.currentTimeMillis()));
preparedStatement.setDate(3,new java.sql.Date(System.currentTimeMillis()));
preparedStatement.setInt(4,0);
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
//开始提交执行
connection.commit();
//手动执行关闭(也可以调用JDBCUtil.close()方法)
preparedStatement.close();
connection.close();
}
}
删-按条件删除记录行(delete)
package com.basic.jdbc.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class SqlDelete {
public void delete() throws SQLException {
Connection connection = null;
connection = JDBCUtil.getConn();
String sql = "DELETE FROM user_login_record WHERE id=?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,121);
int i = preparedStatement.executeUpdate();
if (i==0){
System.out.println("执行失败!");
}else {
System.out.println("执行成功!");
}
JDBCUtil.close(connection,preparedStatement,null);
}
}
改-更新数据(update)
按照条件更新记录行:
package com.basic.jdbc.util;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @Title: SqlUpdate
* @Author Joudys
* @Package com.basic.jdbc.util
* @date: 2025/6/29 14:36
* @description: TODO
*/
public class SqlUpdate {
public void update() throws SQLException {
Connection conn = null;
conn = JDBCUtil.getConn();
//String sql = "UPDATE user_login_record SET user_id=?,create_time=?,update_time=?,is_deleted=? WHERE id=?";
String sql = "UPDATE user_login_record SET user_id=? WHERE id=?";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setInt(1,200);
//preparedStatement.setDate(2, new Date(System.currentTimeMillis()));
//preparedStatement.setDate(3, new Date(System.currentTimeMillis()));
//preparedStatement.setInt(4,1);
preparedStatement.setInt(2,122);
int result = preparedStatement.executeUpdate();
System.out.println("影响行数:"+result);
JDBCUtil.close(conn,preparedStatement,null);
}
}
查-查询数据(select)
这里简单获取所有数据,或者按照条件查询数据:
package com.basic.jdbc.util;
import java.sql.*;
public class SqlSelect {
public void queryAll() throws SQLException {
Connection conn = null;
conn = JDBCUtil.getConn();
String sql = "SELECT * FROM user_login_record";
PreparedStatement statement = conn.prepareStatement(sql);
//执行查询语句
ResultSet resultSet = statement.executeQuery();
//处理结果,多条解=结果用while,单条用if
while(resultSet.next()){
// 通过字段名获取对象值
int id = resultSet.getInt("id");
int userId = resultSet.getInt("user_id");
String ip = resultSet.getString("ip");
Date createTime = resultSet.getDate("create_time");
Date updateTime = resultSet.getDate("update_time");
int isDeleted = resultSet.getInt("is_deleted");
System.out.println(String.format("`id`=%d,`user_id`=%d,`ip`=%s,`create_time`=%s,`update_time`=%s,`is_deleted`=%d",
id,userId,ip,createTime.toString(),updateTime.toString(),isDeleted));
}
JDBCUtil.close(conn,statement,resultSet);
}
public void queryById(int id) throws SQLException {
Connection conn = null;
conn = JDBCUtil.getConn();
String sql = "SELECT * FROM user_login_record WHERE id=?";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setInt(1,id);
//执行查询语句
ResultSet resultSet = statement.executeQuery();
//处理结果,多条解=结果用while,单条用if
if(resultSet.next()){
// 通过字段名获取对象值
int tableId = resultSet.getInt("id");
int userId = resultSet.getInt("user_id");
String ip = resultSet.getString("ip");
Date createTime = resultSet.getDate("create_time");
Date updateTime = resultSet.getDate("update_time");
int isDeleted = resultSet.getInt("is_deleted");
System.out.println(String.format("`id`=%d,`user_id`=%d,`ip`=%s,`create_time`=%s,`update_time`=%s,`is_deleted`=%d",
tableId,userId,ip,createTime.toString(),updateTime.toString(),isDeleted));
}
JDBCUtil.close(conn,statement,resultSet);
}
}
事务处理
事务处理,先开启事务,关闭自动提交,然后执行语句,提交,执行有问题则回滚事务:
package com.basic.jdbc.util;
import java.sql.*;
public class SqlTransaction {
public void transactionInsert(int queryId) throws SQLException {
Connection conn = null;
PreparedStatement statement = null;
conn = JDBCUtil.getConn();
try{
//开启事务
conn.setAutoCommit(false);
String sql = "SELECT * FROM user_login_record WHERE id=?";
statement = conn.prepareStatement(sql);
statement.setInt(1,queryId);
ResultSet resultSet = statement.executeQuery();
//提交事务
conn.commit();
if(resultSet.next()){
// 通过字段名获取对象值
int id = resultSet.getInt("id");
int userId = resultSet.getInt("user_id");
String ip = resultSet.getString("ip");
Date createTime = resultSet.getDate("create_time");
Date updateTime = resultSet.getDate("update_time");
int isDeleted = resultSet.getInt("is_deleted");
System.out.println(String.format("`id`=%d,`user_id`=%d,`ip`=%s,`create_time`=%s,`update_time`=%s,`is_deleted`=%d",
id,userId,ip,createTime.toString(),updateTime.toString(),isDeleted));
}
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
//回滚事务
conn.rollback();
}
JDBCUtil.close(conn,statement,null);
}
public void transactionUpdate() throws SQLException {
Connection conn = null;
PreparedStatement statement = null;
conn = JDBCUtil.getConn();
try {
//关闭自动提交,开启事务
conn.setAutoCommit(false);
String sql = "UPDATE user_login_record SET user_id=?,is_deleted=? WHERE id=?";
statement = conn.prepareStatement(sql);
statement.setInt(1,300);
statement.setInt(2,0);
statement.setInt(3,122);
statement.executeUpdate();
//2.提交事务
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
//3.回滚事务
conn.rollback();
}finally {
statement.close();
conn.close();
}
}
}
方法介绍
重要类、接口、方法:
-
Statement :接口,主要声明执行语句和结果获取,在我们进行 DDL 操作的时候,可以通过 Connection.createStatement() 获取再操作。
-
preparestatement :是 Connection 类 的方法,通过调用此方法,传入提前定义好的 sql 语句,返回 PrepareStatement 接口的对象,同样也可以去调用 executeQuery/executeUpdate 去执行静态语句。
-
callablestatement: 继承自PreparedStatement接口,用于调用存储过程。
-
boolean execute():在 PrepareStatement 语句中使用,效果等同于 executeQuery/executeUpdate,但有一点需要注意,如是是查询语句,执行后要返回 true/false,如果要获取查询的结果,应该再次调用 Statement.getResultSet,如果是 update 类的语句,则可以调用 Statement.getUpdateCount。
-
ResultSet executeQuery():执行了 SQL DQL 查询语句后,返回查询的结果集。
-
int executeUpdate :执行 DML 后,返回整型值,可以是影响行数,或者0,主要针对 INSERT、UPDATE、DELETE 语句。
-
void addBatch():在如执行批量插入操作时,将一组参数加入到 PrepareStatement 中。
-
int[] executeBatch():提交批量操作的命令,正式执行批量操作。
-
setSomeType():主要针对 PrepareStatement 对象,对占位符的参数进行设置,占位符的序号+字段值。