一、简介
1.概述
JDBC使用Java语言操作不同的关系型数据库的一套API(标准接口)
( Java DataBase Connectivity )Java数据库连接
2.好处
①各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
②可随时替换底层数据库,访问数据库的Java代码基本不变
3.驱动
JDBC驱动由数据库厂商提供
-
在个人开发与测试中,可以使用JDBC-ODBC桥连方式
- 将对JDBC API的调用,转换为对另一组数据库连接API的调用
- 优点:可以访问所有ODBC可以访问的数据库
- 缺点:执行效率低、功能不够强大
-
在生产型开发中,推荐使用纯Java驱动方式
- 由JDBC驱动直接访问数据库
- 优点:完全Java代码,快速、跨平台
- 缺点:访问不同的数据库需要下载专用的JDBC驱动
二、步骤
0.创建工程,导入驱动jar包
(1)导入jar后需要add as library
(2)创建Java实现类Class
1. 加载数据库驱动程序:
Class.forName("com.mysql.jdbc.Driver"); // 加载MySQL驱动程序
2. 建立数据库连接:
String url = "jdbc:mysql://localhost:3306/mydatabase";
String username = "username";
String password = "password";
Connection connection =
DriverManager.getConnection(url, username, password);
3. 创建Statement对象:
Statement statement = connection.createStatement();
4. 执行SQL查询语句:
String sql = "SELECT * FROM customers";
// 执行查询语句并返回结果集
ResultSet resultSet = statement.executeQuery(sql);
// 遍历结果集
while (resultSet.next()) {
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
System.out.println("Name: " + name + ", Age: " + age);
}
5. 执行SQL更新语句:
String sql = "UPDATE customers SET age = 25 WHERE id = 1";
// 执行更新语句并返回受影响的行数
int rowsAffected = statement.executeUpdate(sql);
6. 关闭连接和相关资源:
if(resultSet!=null)
resultSet.close();
if(statement!=null)
statement.close();
if(connection!=null)
connection.close();
释放资源是为了优化系统的性能和效率,好处:
- 节省内存:释放不再使用的资源可以释放占用的内存空间,提高系统的可用内存,从而使其他应用程序可以更快速地执行。
- 避免内存泄漏:释放资源可以防止内存泄漏的问题。内存泄漏是指程序中分配的内存空间在不再使用时没有被释放,导致内存占用不断增加,严重时可能导致系统崩溃。
- 提高系统稳定性:释放资源可以减少系统负载和内存使用量,从而提高系统的稳定性和可靠性。避免资源过度占用也可以降低系统崩溃的风险。
- 提升用户体验:释放资源可以加快应用程序的响应速度,减少卡顿和延迟现象,提升用户的使用体验。
三、API详解
API解释
[API 是 “Application Programming Interface” 的缩写,指的是应用程序编程接口。它是一组定义了软件组件如何相互通信和交互的规范。
API 允许不同的软件系统之间进行交互,并共享数据和功能。通过使用 API,开发人员可以直接访问其他软件或服务的功能,而无需了解其内部工作原理]
JDBC API
JDBC API主要功能:与数据库建立连接、执行SQL语句、处理结果
- DriverManager:依据数据库的不同,管理JDBC驱动
- Connection:负责连接数据库并担任传送数据的任务
- Statement:由 Connection产生、负责执行SQL语句
- ResultSet:负责保存Statement执行后所产生的查询结果
驱动管理类DriverManager作用
1.注册驱动(反射原理)
[将一个类加载到内存],抛出异常,[在mysql5后可省略]
Class.forName("com.mysql.jdbc.Driver");
在使用 JDBC 连接 MySQL 数据库之前,需要确保 MySQL JDBC 驱动程序已经被加载。通过调用 `Class.forName()` 方法,并传递驱动程序的完整类名 `"com.mysql.jdbc.Driver"`,可以动态加载该驱动程序的类,并注册到 Java 的 `DriverManager` 中。
`com.mysql.jdbc.Driver` 是旧版本 MySQL JDBC 驱动程序的包名。
如果使用的是 MySQL Connector/J 8.0 或更新版本,应该使用 `com.mysql.cj.jdbc.Driver`。
在Java 6及更高版本中,JDBC驱动程序的自动加载已经被引入,因此不再需要显式调用 `Class.forName()` 来加载驱动程序。只需要在连接数据库之前,确保相应的驱动程序 JAR 文件已经被添加到类路径即可。例如:
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/mydatabase", "username", "password");
这将自动扫描类路径上可用的驱动程序,并注册与数据库 URL 匹配的驱动程序,无需显式加载驱动程序类。
Driver类的静态方法,加载自动执行
registerDriver(Driver,driver)使用DriverManager注册给定的驱动程序
在mysql5.5之后,自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动
2.获取连接
String url="jdbc:mysql://ip端口/需要连接的数据库?参数键值对"
String username="";
String password="";
Connection conn =DriverManager.getConnection(url,username,password);
url连接路径
jdbc连接MySQL的协议---jdbc:mysql://
需要连接的数据库地址---ip地址(域名):端口号/
需要连接的数据库---数据库名称?参数键值对1&参数键值对2...
例如
jdbc:mysql://ip地址:端口号/数据库名称?serverTimezone=Asia/Shanghai&characterEncording=utf-8
如果连接的是本机MySQL服务器,并且MySQL服务默认端口是3306
url简写jdbc:mysql:///数据库名称?参数键值对1...
数据库连接对象Connection作用
1.获取执行SQL对象
//普通执行SQL对象
Statement createStatement();
//预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement preparedStatement(sql);
//执行存储过程的对象[不常使用]
CallableStatement prepareCall(sql);
(事务管理)
MySQL事务管理
开启事务:begin;/start transaction;
提交事务:commit;
回滚事务:rollback;
MySQL默认自动提交事务
JDBC事务管理
开启事务:setAutoCommit(boolean autoCommit):
true自动提交事务,false为手动提交事务
提交事务:commit()
回滚事务:rollback()
2.事务管理版
Statement stmt =conn.createStatement();
//如果在多个执行sql语句时发现异常,需要回滚
try{
//开启事务
conn.setAutoCommit(false);
int count=stmt.executeUpadte(sql);
Sysytem.out.print(count);
//提交事务
conn.commit();
}catch(Exception e){
//回滚事务
conn.rollback();
e.printStackTrace();
}
Statement作用
1.执行sql语句,处理结果
//执行DML增删改、DDL对表和库的增删改查语句
//返回值(1)DML语句影响的行数(2)DDL语句执行后,执行成功也可能返回0
int count=stmt.executeUpadte(sql);
结果集对象ResultSet作用
1.封装DQL查询语句的结果
2.获取查询结果
next(): 光标向下移动一行,并且判断当前行是否为有效行
返回值 true有效行,当前行有数据;false无效行,当前行没有数据
get数据类型():获取数据
int getInt(参数);
String getString(参数);
参数int :列的编号,从1开始
参数String :列的名称
例:
//执行DQL查询语句,返回ResultSet对象
ResultSet rs=stmt.executeQuery(sql);
//遍历结果集
while(rs.next()){
int a=rs.getInt(1);
int b=rs.getInt("id");
}
PreparedStatement作用
1.预编译SQL的执行SQL对象:防止SQL注入
SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法,如: ‘or’1’='1
1.步骤
①获取preparedStatement对象
//SQL语句中的参数值,使用占位符?替代
String sql="select * from user where username =? and password =?";
//通过Connection对象获取,并传入对应的sql语句
PreparedStatement pstmt =conn.prepareStatement(sql);
②设置参数值
PreparedStatement对象,setXxx(参数1,参数2):给?赋值
?的位置编号从1开始
③执行SQL语句
executeUpdate();executeQuery();//不需要再传递sql
2.好处
①预编译SQL,性能更高
②防止SQL注入:将敏感字符进行转义
3.原理
①在获取PreparedStatement对象时,将SQL语句发送给mysql服务器
进行检查,编译(耗时)
②执行时就不用再进行这些步骤了,速度很快
③如果SQL模板一样,则只需要进行一次检查、编译
4.开启功能及展示日志
开启PreparedStatement预编译功能
String url="...参数键值对 & useServerPrepStmts=true ";
配置MySQL执行日志my.imi(重启mysql服务后生效)
log-output=FILE
general-log=1
general_log_file="D:\mysql.log"
slow-query-log=1
slow_query_log_file="D:\mysql_slow.log"
long_query_time=2
四、JDBC预编译功能代码
public class BaseDao {
//4个属性
//驱动地址
public static final String DRIVER="com.mysql.cj.jdbc.Driver";
//连接地址
public static final String URL="jdbc:mysql://localhost:3306/数据库名?serverTimezone=Asia/Shanghai";
//用户名
public static final String USER="root";
//密码
public static final String PASSWORD="ok";
//3个对象
//连接对象
public static Connection conn;
//预编译对象
public static PreparedStatement ppst;
//结果集对象
public static ResultSet rs;
//1个静态方法块
//加载驱动
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
//4个方法
//获取连接方法
public static void getConnection(){
try {
//当没有连接或者连接被关闭的时候
if (conn==null||conn.isClosed())
conn= DriverManager.getConnection(URL, USER,PASSWORD);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//释放资源方法
public static void closeAll(){
try {
if (rs!=null)rs.close();
if (ppst!=null)ppst.close();
if (conn!=null)conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 通用增删改方法
* @param sql 输入的sql语句
* @param o 可变参数
*/
public static int excuteUpdate(String sql, Object...o){
//声明返回结果
int result=0;
//获取连接对象
getConnection();
try {
//通过conn获取ppst对象。并对sql进行预编译
ppst= conn.prepareStatement(sql);
//循环遍历可变参数(当成数组来用)
for (int i = 0; i < o.length; i++) {
ppst.setObject((i+1),o[i]);
}
//执行sql语句,返回受影响的行数
result=ppst.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
//关闭资源
closeAll();
}
return result;
}
/**
* 通用查询方法
* @param sql 输入的sql语句
* @param o 可变参数
*/
public static void excuteQuery(String sql, Object...o){
//获取连接对象
getConnection();
try {
//通过conn获取ppst对象。并对sql进行预编译
ppst= conn.prepareStatement(sql);
//循环遍历可变参数(当成数组来用)
for (int i = 0; i < o.length; i++) {
ppst.setObject((i+1),o[i]);
}
//执行sql语句,返回受影响的行数
rs=ppst.executeQuery();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}