文章目录
JDBC:是标准库提供的一套API。
环境:JDBC在使用的时候,需要下载并导入对应数据库的驱动包。
一、JDBC介绍
JDBC,即Java Database Connectivity,java数据库连接。是一种用于执行SQL语句的Java API,它是Java中的数据库连接规范。这个API由java.sq1.* ,javax. sq1.*
包中的一些类和接口组成,它为Java开发人员操作数据库提供了一个标准的APl,可以为多种关系数据库提供统一访问。
1、JDBC原理
JDBC 为多种关系数据库提供了统一访问方式,作为特定厂商数据库访问API的一种高级抽象,它主要包含一些通用的接口类。
JDBC优势:
- Java语言访问数据库操作完全面向抽象接口编程
- 开发数据库应用不用限定在特定数据库厂商的API
- 程序的可移植性大大增强
2、JDBC安装
将这个jar包下载下来,然后直接粘贴进需要的项目当中即可。
在导入jar包的时候不要忘记右键:Add as library,并且要确保新建的目录和src是同一级,但不要放到src里面。
二、JDBC常见的接口和类
1、数据库连接Connection
Connection接口实现类由数据库提供,获取Connection对象通常有两种方式:
- 一种是通过DriverManager(驱动管理类)的静态方法获取:
// 加载JDBC驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 创建数据库连接
Connection connection = DriverManager.getConnection(url);
- 一种是通过DataSource(数据源)对象获取。实际应用中会使用DataSource对象。
DataSource ds = new MysqlDataSource();
((MysqlDataSource) ds).setUrl("jdbc:mysql://localhost:3306/test");
((MysqlDataSource) ds).setUser("root");
((MysqlDataSource) ds).setPassword("root");
Connection connection = ds.getConnection();
以上两种方式的区别是:
- DriverManager类来获取的Connection连接,是无法重复利用的,每次使用完以后释放资源时,通过connection.close()都是关闭物理连接。
- DataSource提供连接池的支持。连接池在初始化时将创建一定数量的数据库连接,这些连接是可以复用的,每次使用完数据库连接,释放资源调用connection.close()都是将Conncetion连接对象回收。
2、Statement对象
Statement对象主要是将SQL语句发送到数据库中。JDBC API中主要提供了三种Statement对象。JDBC API中主要提供了三种Statement对象。
- 1、Statement:用于执行不带参数的简单SQL语句。
- 2、PreparedStatement:用于执行带或者不带参数的SQL语句,SQL语句会编译在数据库系统,执行速度快于Statement对象。
- CallableStatement:用于执行数据库存储过程的调用。
实际开发中最常用的是PreparedStatement对象,以下对其的总结:
主要掌握两种执行SQL的方法:
- executeQuery() 方法执行后返回单个结果集的,通常用于select语句
- executeUpdate()方法返回值是一个整数,指示受影响的行数,通常用于update、insert、delete
语句
3、ResultSet对象
ResultSet对象它被称为结果集,它代表符合SQL语句条件的所有行,并且它通过一套getXXX方法提供 了对这些行中数据的访问。
ResultSet里的数据一行一行排列,每行有多个字段,并且有一个记录指针,指针所指的数据行叫做当前数据行,我们只能来操作当前的数据行。我们如果想要取得某一条记录,就要使用ResultSet的next()方法 ,如果我们想要得到ResultSet里的所有记录,就应该使用while循环。
三、JDBC往数据库插入记录
操作:往数据库当中插入一条记录
通过JDBC操作数据库,往test数据库当中的student表里面插入一条记录:
1、创建数据源对象
1、创建数据源对象,数据源对象就描述了要访问的数据库是啥,在哪。
DataSource dataSource=new MysqlDataSource();//向上转型
每种数据库都会提供对应的类来实现DataSource接口。
上述代码使用到了多态,多态可以认为是封装的更进一步。
封装是把实现细节隐藏起来,让调用者不必考虑细节就能使用,从而降低调用者的使用成本和学习负担。
多态则是把实现类的类型也隐藏起来了,调用者不仅不必考虑细节,而且连它是啥类型都不管了。
DataSource是服务于各种数据库的,MysqlDataSource只是服务于MySQL的。
在MySQL里面,是一个客户端服务器的程序,描述服务器的位置,会使用URL这个概念来表示。
但是有的数据库,比如SQLite,就不是客户端服务器结构的,也就谈不上URL。
DataSource考虑到通用性,就不能把setURL这样的方法给搞过来。
关于耦合性,什么叫耦合:一个大的程序里面包含很多个部分,如果这些部分之间关联性比较强,则耦合度较高。关联性比较弱,耦合度较低。
URL:唯一资源定位符。就是网址。
当前数据库客户端(咱自己写的代码)和服务器都在咱自己的电脑上面。
DataSource描述了在哪里可以找到数据库的数据。URL里面就体现出数据库服务器的位置以及数据库的名字。
((MysqlDataSource)dataSource).setUser("root");//用户名
((MysqlDataSource)dataSource).setPassword("1234");//密码
用户名统一都是root(mysql自带的用户名),密码就是安装数据库的时候设置的密码。
2、让代码和数据库服务器建立连接
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author Susie-Wen
* @version 1.0
* @description:
* @date 2022/8/15 12:43
*/
public class JDBC {
//通过JDBC操作数据库,往数据库里插入一条记录
//往test数据库当中的student表里面插入一条记录:
public static void main(String[] args) throws SQLException {
DataSource dataSource=new MysqlDataSource();//向上转型
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");//用户名
((MysqlDataSource)dataSource).setPassword("123456");//密码
//2、让代码和数据库服务器建立连接
Connection connetcion= dataSource.getConnection();
System.out.println(connetcion);
}
}
运行上述代码,如果没有报错,则说明连接数据库成功了。
如果出现如下错误,则说明用户名或者密码发生错误。
3、构造要执行的SQL语句(构造请求)
//3、构造要执行的SQL语句
String sql="insert into student values(3,'三三')";
PreparedStatement statement=connetcion.prepareStatement(sql);
使用java/C++/Python操作数据库,本质上还是通过SQL。
PreparedStatement:表示一个预处理过的SQL语句对象。
4、执行SQL(发送请求&读取响应)
执行方法有两个:executeUpdate,executeQuery。
executeUpdate:对应插入删除修改语句,返回值表示。
executeQuery:对应查询语句,返回值则是返回的临时表数据。
//4、执行SQL
//执行方法有两个:executeUpdate,executeQuery
int n=statement.executeUpdate();
System.out.println("n="+n);
5、完成后,就需要关闭释放相关资源
手动释放资源:
statement.close();
connetcion.close();
前面的语句对象和连接对象都是需要消耗资源的,常说的资源,主要是指一些硬件资源(也有的时候指软件资源)
释放资源的顺序要和申请资源的顺序正好相反。
6、用户输入+完整代码
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;
/**
* @author Susie-Wen
* @version 1.0
* @description:
* @date 2022/8/15 12:43
*/
public class JDBC {
//通过JDBC操作数据库,往数据库里插入一条记录
//往test数据库当中的student表里面插入一条记录:
public static void main(String[] args) throws SQLException {
DataSource dataSource=new MysqlDataSource();//向上转型
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");//用户名
((MysqlDataSource)dataSource).setPassword("123456");//密码
//2、让代码和数据库服务器建立连接
Connection connetcion= dataSource.getConnection();
//[用户输入]:通过用户输入的数据,来确定插入的值
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要插入的学号:");
int id=scanner.nextInt();
System.out.println("请输入要插入的姓名:");
String name=scanner.next();
//3、构造要执行的SQL语句
String sql="insert into student values(" + id +",' "+name+" ' )";
PreparedStatement statement=connetcion.prepareStatement(sql);
System.out.println("statement:"+statement);
//4、执行SQL
//执行方法有两个:executeUpdate,executeQuery
int n=statement.executeUpdate();
System.out.println("n="+n);
//5、完成后,就需要关闭释放相关资源
statement.close();
connetcion.close();
}
}
当前通过字符串拼接的方式,可以让用户输入数据进行插入,但是效果不太好。
1、代码非常乱,尤其是拼的SQL变成啥样,不太直观。
2、不安全,容易引发SQL注入漏洞。
因此,不应该手动拼接SQL,而应该借助PreparedStatement内部提供的SQL拼装机制。
使得代码更简单更直观,会对拼接的内容进行更严格的校验检查,避免SQL注入。
将上述代码进行更改,如下:
public class JDBC {
//通过JDBC操作数据库,往数据库里插入一条记录
//往test数据库当中的student表里面插入一条记录:
public static void main(String[] args) throws SQLException {
DataSource dataSource=new MysqlDataSource();//向上转型
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");//用户名
((MysqlDataSource)dataSource).setPassword("123456");//密码
//2、让代码和数据库服务器建立连接
Connection connetcion= dataSource.getConnection();
//[用户输入]:通过用户输入的数据,来确定插入的值
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要插入的学号:");
int id=scanner.nextInt();
System.out.println("请输入要插入的姓名:");
String name=scanner.next();
//3、构造要执行的SQL语句[构造请求]
//使用?作为占位符,占个位置,后面会替换成其他的值。
String sql="insert into student values(?,?)";
PreparedStatement statement=connetcion.prepareStatement(sql);
statement.setInt(1,id);
statement.setString(2,name);
System.out.println("statement:"+statement);
//4、执行SQL
//执行方法有两个:executeUpdate,executeQuery
int n=statement.executeUpdate();
System.out.println("n="+n);
//5、完成后,就需要关闭释放相关资源
statement.close();
connetcion.close();
}
}
四、JDBC往数据库修改记录
import java.sql.Connection;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;
/**
* @author Susie-Wen
* @version 1.0
* @description:
* @date 2022/8/16 8:17
*/
//通过JDBC来修改数据
public class JDBCUpdate {
public static void main(String[] args) throws SQLException {
//1、创建数据源
DataSource dataSource=new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");//用户名
((MysqlDataSource)dataSource).setPassword("123456");//密码
//2、建立连接
Connection connection=dataSource.getConnection();
//3、构造SQL
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要修改的同学学号:");
int id=scanner.nextInt();
System.out.println("请输入要修改的同学姓名:");
String name=scanner.next();
String sql="update student set name = ? where id = ?";
PreparedStatement statement=connection.prepareStatement(sql);
statement.setString(1,name);
statement.setInt(2,id);
//4、执行SQL
int n=statement.executeUpdate();
System.out.println("n="+n);
//5、关闭释放资源
statement.close();
connection.close();
}
}
在实际开发当中,很少会直接使用JDBC,代码比较啰嗦。在实际开发当中会用到一些库/框架,来简化这里的数据库操作。(MyBatis)
各种库和框架本质上也就是针对JDBC又进行的封装。
五、JDBC往数据库删除记录
public class JDBCDelete {
public static void main(String[] args) throws SQLException {
//1、创建数据源
DataSource dataSource=new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");//用户名
((MysqlDataSource)dataSource).setPassword("123456");//密码
//2、建立连接
Connection connection=dataSource.getConnection();
//3、构造SQL
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要删除的同学学号:");
int id=scanner.nextInt();
String sql="delete from student where id = ?";
PreparedStatement statement=connection.prepareStatement(sql);
statement.setInt(1,id);
//4、执行SQL
int n=statement.executeUpdate();
System.out.println("n="+n);
//5、关闭释放资源
statement.close();
connection.close();
}
}
六、JDBC往数据库查找记录
public class JDBCSelect {
public static void main(String[] args) throws SQLException {
//1、创建数据源
DataSource dataSource=new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");//用户名
((MysqlDataSource)dataSource).setPassword("123456");//密码
//2、建立连接
Connection connection=dataSource.getConnection();
//3、构造SQL
String sql="select * from student";
PreparedStatement statement=connection.prepareStatement(sql);
//4、执行SQL
ResultSet resultSet=statement.executeQuery();
//5、遍历结果集合
while(resultSet.next()){
//每次循环,就能够获取到resultSet中的一行,进一步的就可以拿到每一列
int id=resultSet.getInt("id");
String name=resultSet.getString("name");
System.out.println("id="+id+",name="+name);
}
//6、关闭释放资源
resultSet.close();
statement.close();
connection.close();
}
}
七、JDBC作业
1、新增记录
新增貂蝉同学的借阅记录:诗经,从2019年9月25日17:50到2019年10月25日17:50
package com.bit.util;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Util {
//使用连接池
private static final DataSource DATA_SOURCE = new MysqlDataSource();
static {
((MysqlDataSource) DATA_SOURCE).setUrl("jdbc:mysql://localhost:3306/book");
((MysqlDataSource) DATA_SOURCE).setUser("root");
((MysqlDataSource) DATA_SOURCE).setPassword("root");
}
public static void main(String[] args) {
System.out.println(getConnection());
}
// 获取数据库连接
public static Connection getConnection(){
try {
return DATA_SOURCE.getConnection();
} catch (SQLException e) {
throw new RuntimeException("获取数据库连接失败", e);
}
}
// 释放资源
public static void close(ResultSet resultSet, Statement statement,
Connection connection){
try {
if(resultSet != null) {
resultSet.close();
}
if(statement != null){
statement.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException("数据库操作异常", e);
}
}
//日期字符串转Java日期类Date和sql时间戳Timestamp
public static Timestamp getTimestamp(String dateString){
try {
// 年-月-日 小时:分钟:秒
java.util.Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateString);
return new java.sql.Timestamp(date.getTime());
} catch (ParseException e) {
throw new RuntimeException("日期格式化错误:"+dateString, e);
}
}
}
package com.bit.book;
import com.bit.util.Util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class AddBorrow {
/**
* 新增貂蝉同学的借阅记录:诗经,从2019年9月25日17:50到2019年10月25日17:50
*/
public static void main(String[] args) {
//1.创建数据库连接对象
Connection connection = null;
//2.创建操作命令对象
PreparedStatement preparedStatement = null;
try {
connection = Util.getConnection();
String sql = "insert into borrow_info(book_id, student_id," +
" start_time, end_time) select b.id,s.id,?,?" +
" from book b,student s where b.name=? and s.name=?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setTimestamp(1, Util.getTimestamp("2019-09-25 17:50:00"));
preparedStatement.setTimestamp(2, Util.getTimestamp("2019-10-25 17:50:00"));
preparedStatement.setString(3, "诗经");
preparedStatement.setString(4, "貂蝉");
System.out.println(preparedStatement);
//3.执行sql
int result = preparedStatement.executeUpdate();
System.out.println(result);
} catch (SQLException e) {
e.printStackTrace();
} finally {
//4.释放资源
Util.close(null, preparedStatement, connection);
}
}
}
2、查询记录
查询计算机分类下的图书借阅信息
package com.bit.book;
import com.bit.util.Util;
import java.sql.*;
public class QueryBorrow {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = Util.getConnection();
String sql = "SELECT bk.NAME book_name,bk.author book_author," +
"s.NAME student_name,bi.start_time,bi.end_time" +
" FROM borrow_info bi JOIN book bk ON bi.book_id = bk.id" +
" JOIN category c ON bk.category_id = c.id" +
" JOIN student s ON bi.student_id = s.id" +
" WHERE c.NAME = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "计算机");
resultSet = preparedStatement.executeQuery();
while(resultSet.next()){
String bookName = resultSet.getString("book_name");
String bookAuthor = resultSet.getString("book_author");
String studentName = resultSet.getString("student_name");
Timestamp startTime = resultSet.getTimestamp("start_time");
Timestamp endTime = resultSet.getTimestamp("end_time");
System.out.println(String.format("书名:%s,作者:%s,借阅者:%s," +"借阅起始日期:%s,结束日期:%s",
bookName, bookAuthor, studentName, startTime, endTime));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
Util.close(resultSet, preparedStatement, connection);
}
}
}
3、修改记录
修改图书《深入理解Java虚拟机》的价格为61.20
package com.bit.book;
import com.bit.util.Util;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class UpdateBook {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = Util.getConnection();
String sql = "update book set price=? where name =?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setBigDecimal(1, new BigDecimal("61.20"));
preparedStatement.setString(2, "深入理解Java虚拟机");
System.out.println(preparedStatement);
int result = preparedStatement.executeUpdate();
System.out.println(result);
} catch (SQLException e) {
e.printStackTrace();
} finally {
Util.close(null, preparedStatement, connection);
}
}
}
4、删除记录
删除id最大的一条借阅记录
package com.bit.book;
import com.bit.util.Util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class DeleteBorrow {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = Util.getConnection();
String sql = "delete from borrow_info where id =" +
"(select r.id from (select max(id) id from borrow_info) r)";
preparedStatement = connection.prepareStatement(sql);
int result = preparedStatement.executeUpdate();
System.out.println(result);
} catch (SQLException e) {
e.printStackTrace();
} finally {
Util.close(null, preparedStatement, connection);
}
}
}