JDBC入门

JDBC

JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范,能够执行SQL语句。

由一组用Java语言编写的 接口 组成

各数据库厂商根据此规范开发出相应的功能,称之为 驱动

有了 JDBC 提供的api,我们 几乎可以不改代码,就能操作不同的数据库,简化的开发难度,提高开发速度,也就是说:JDBC 实现了 跨数据库 操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GiagpsfV-1629773538468)(C:/Users/libra/Desktop/5/5.4/image-20210821130141581.png)]

核心组件

DriverManager: 此类管理数据库驱动程序列表。使用通信子协议将来自java应用程序的连接请求 与适当的数据库驱动程序匹配。

Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互。而是使用 DriverManager对象来管理这种类型的对象。

Connection:该界面具有用于联系数据库的所有方法。连接对象表示通信上下文,即,与数据库 的所有通信仅通过连接对象。

Statement:使用从此接口创建的对象将SQL语句提交到数据库。除了执行存储过程之外,一些派生接口还接受参数。

ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为一 个迭代器,允许我们移动其数据。

SQLException:此类处理数据库应用程序中发生的任何错误

操作流程

构建JDBC应用程序涉及以下六个步骤:

导入包

需要包含包含数据库编程所需的JDBC类的包。大多数情况下,使用import java.sql.*就足够 了。

注册JDBC驱动程序

要求您初始化驱动程序,以便您可以打开与数据库的通信通道。此步骤将使JVM将所需的驱动程序实现加载到内存中,以便它可以满足您的JDBC 请求。

驱动地址
RDBMSJDBC驱动程序名称网址格式
MYSQL8com.mysql.cj.jdbc.Driverjdbc:mysql://hostname:3306/databaseName?serverTimezone=UTC
MySQLcom.mysql.jdbc.Driverjdbc:mysql://hostname:3306/databaseName
RACLEoracle.jdbc.driver.OracleDriverjdbc:oracle:thin:@hostname:port Number: databaseName
DB2com.ibm.db2.jdbc.net.DB2Driverjdbc:db2:hostname:port Number / databaseName
SYBASEcom.sybase.jdbc.SybDriverjdbc:sybase:Tds:hostname:port Number / databaseName

Class.forName();

注册驱动程序最常见的方法是使用Java的Class.forName()方法,将驱动程序的类文件动态加载到内存 中,并将其自动注册

try {
Class.forName("com.mysql.cj.jdbc.Driver");
}catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
}

DriverManager.registerDriver()

第二种方法是使用静态DriverManager.registerDriver()方法。

try {
Driver myDriver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver( myDriver );
}catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
}

数据库URL配置

加载驱动程序后,可以使用DriverManager.getConnection()方法建立连接。

创建数据库连接对象

String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC";
String USER = "username";
String PASS = "password"
Connection conn = DriverManager.getConnection(URL, USER, PASS);

打开连接

需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表 示与数据库的物理连接。

使用数据库URL和属性对象 DriverManager.getConnection()方法的形式需要一个数据库URL和一个Properties对象

DriverManager.getConnection(String url, Properties info);
import java.util.*;
String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC";
Properties info = new Properties( );
info.put( "user", "username" );
info.put( "password", "password" );
Connection conn = DriverManager.getConnection(URL, info)

关闭数据库连接

conn.close();

执行查询

需要使用类型为JDBC Statement和PreparedStatement的对象来构建和提交SQL语句到数据库。

Statement接口不能 接受参数,在运行时使用静态SQL语句时很有用。

PreparedStatement接口在运行时接受 输入参数,当您计划多次使用SQL语句时使用。

Statement(状态通道)

1.在使用Statement对象执行SQL语句之前,需要使用Connection对象的createStatement()方法创建 一个对象

Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
}
catch (SQLException e) {
. . .
}
finally {
	stmt.close();
}

2.创建Statement对象后,您可以使用它来执行一个SQL语句,其中有三个执行方法之一。

boolean execute(String SQL):如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返 回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。

int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响 多个行的SQL语句,例如INSERT,UPDATE或DELETE语句。

ResultSet executeQuery(String SQL):返回一个ResultSet对象。当您希望获得结果集时,请使 用此方法,就像使用SELECT语句一样。

3.关闭Statement对象

就像我们关闭一个Connection对象以保存数据库资源一样,由于同样的原因,还应该关闭Statement对 象。**如果先关闭Connection对象,它也会关闭Statement对 象。**但是,应始终显式关闭Statement对象,以确保正确清理。

SQL注入

指使用Statement对象提交时通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执 行恶意的SQL命令。

PreparedStatement(预状态通道)

创建PreparedStatement对象

PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERE id = ?";
pstmt = conn.prepareStatement(SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
 	pstmt.close();
}

JDBC中的所有参数都由?符号,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。

所述的setXXX()方法将值绑定到所述参数,其中XXX代表要绑定到输入参数的值的Java数据类型。如果 忘记提供值,将收到一个SQLException。

每个参数标记由其顺序位置引用。第一个标记表示位置1,下一个位置2等等。该方法与Java数组索引从0开始是不 同的。

关闭PreparedStatement对象 就像关闭Statement对象一样,由于同样的原因,还应该关闭PreparedStatement对象。 一个简单的调用close()方法将执行该作业。**如果先关闭Connection对象,它也会关闭 PreparedStatement对象。**但是,应始终显式关闭PreparedStatement对象,以确保正确清理。

对比statement和PreparedStatement

(1)statement属于状态通道,PreparedStatement属于预状态通道

(2)预状态通道会先编译sql语句,再去执行,比statement执行效率高

(3)预状态通道支持占位符?,给占位符赋值的时候,位置从1开始

(4)预状态通道可以防止sql注入,原因:预状态通道在处理值的时候以字符串的方式处理

从结果集中提取数据

查询:用ResultSet对象接收,需要使用相应的ResultSet.getXXX()方法(XXX为数据类型)从结果集中检索数据。

ResultSet对象维护指向结果集中当前行的游标。术语“结果集”是指包含在ResultSet对象中的行和列数 据。

类型描述
ResultSet.TYPE_SCROLL_INSENSITIVE光标可以向前和向后滚动,结果集对创建结果集后发生的数据库的其他更改不敏感。
ResultSet.TYPE_SCROLL_SENSITIVE。光标可以向前和向后滚动,结果集对创建结果集之后发生的其他数据库所做的更改敏感。
ResultSet.TYPE_FORWARD_ONLY(默认状态)光标只能在结果集中向前移动。

修改:仅返回受到影响的行数,只需要基础类(如int),就能接收。

释放资源

需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。

为确保连接关闭,您可以在代码中提供一个“finally”块。一个finally块总是执行,不管是否发生异常。 要关闭上面打开的连接,你应该调用close();

通常需要关闭的有以下几种:

Connectionl;

PreparedStatement;

ResultSet;

JDBC批处理

批量处理允许您将相关的SQL语句分组到批处理中,并通过对数据库的一次调用提交它们。 当您一次向数据库发送多个SQL语句时,可以减少连接数据库的开销,从而提高性能。

Statement批处理

使用createStatement()方法创建Statement对象。

使用setAutoCommit()将auto-commit设置为false 。

使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。

在创建的语句对象上使用executeBatch()方法执行所有SQL语句。

最后,使用commit()方法提交所有更改。

Statement stmt = conn.createStatement();
conn.setAutoCommit(false);
//sql1
String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(200,'Zia',
'Ali', 30)";
stmt.addBatch(SQL);
//sql2
String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(201,'Raj',
'Kumar', 35)";
stmt.addBatch(SQL);
//sql3
String SQL = "UPDATE Employees SET age = 35 WHERE id = 100";
stmt.addBatch(SQL);
int[] count = stmt.executeBatch();
conn.commit();

PreparedStatement批处理

使用占位符创建SQL语句。

使用prepareStatement() 方法创建PrepareStatement对象。

使用setAutoCommit()将auto-commit设置为false 。

使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。

在创建的语句对象上使用executeBatch()方法执行所有SQL语句。

最后,使用commit()方法提交所有更改。

String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(?, ?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(SQL);
conn.setAutoCommit(false);
// Set the variables
pstmt.setInt( 1, 400 );
pstmt.setString( 2, "Pappu" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 33 );
// Add it to the batch
pstmt.addBatch();
// Set the variables
pstmt.setInt( 1, 401 );
pstmt.setString( 2, "Pawan" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 31 );
// Add it to the batch
pstmt.addBatch();
//add more batches
//Create an int[] to hold returned values
int[] count = stmt.executeBatch();
//Explicitly commit statements to apply changes
conn.commit();

反射处理结果集

java反射机制是什么

反射机制是在运行状态中,可以知道任何一个类的属性和方法,并且调用类的属性和方法;

反射机制能够做什么

1、判断运行对象的所属类

2、构造任意一个类的对象

3、获取任意一个类的属性和方法

4、调用任意属性和方法

5、生成动态代理

主要步骤

1.先利用 SQL 进行查询,得到结果集

2.利用反射创建实体类的对象:创建 Student 对象

3.获取结果集的列的数量,赋予”set+名“的字符串

4.再获取结果集的每一列的值, 结合 3的字符串,利用method写入Object无参对象,将Object的对象写入 list集合,就可以查看了

@Override
public List<Student> findallstudent(Class cla) {
Connection con = null;
PreparedStatement pps = null;
ResultSet rs =null;
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/yhp",
"root", "123456");
List list=new ArrayList();
String sqla = "select * from student";
pps = con.prepareStatement(sqla);
rs = pps.executeQuery();
//得到数据库中的所有的列有哪些?
ResultSetMetaData metaData = rs.getMetaData();//返回数据库中的相关信息
int count=metaData.getColumnCount();//得到列数
String[] columnnames=new String[count];
for (int i = 0; i < count; i++) {
// System.out.println(metaData.getColumnName(i+1));//列的位置从1开始
columnnames[i]=metaData.getColumnName(i+1);
}
//得到实体类中的所有的方法
Method[] methods =cla.getDeclaredMethods();
while(rs.next()){
Object s=cla.newInstance();//调取无参构造创建对象
for (String columnname : columnnames) {
String name="set"+columnname;//setstuid
for (Method method : methods) {
if(method.getName().equalsIgnoreCase(name)){
method.invoke(s,rs.getObject(columnname));//执行了对应的set方法
break;
}
}
}
list.add(s);
}
System.out.println("执行成功");
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) {
rs.close();
}
if (pps != null) {
pps.close();
}
if (con != null) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}

可以写一个util包的jdbc工具类,用于储存常用的连接,查找,修改,关闭资源等方法。

使用ResourceBundle访问本地资源

在设计时,我们往往需要访问一些适合本地修改的配置信息,如果作为静态变量,那么每次修改都 需要重新编译一个class,.config保存此类信息并不适合,这时我们需要ResourceBundle。

通过ResourceBundle,我们需要访问位于/WEB-INF/classes目录下的一个后缀名为properties的文本类型文件,从里面读取我们需要的值。

连接池

最小连接数:

是数据库一直保持的数据库连接数,所以如果应用程序对数据库连接的使用量不大,将有大量的数据库 资源被浪费。

初始化连接数:

连接池启动时创建的初始化数据库连接数量。

最大连接数:

是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队 列中。

最大等待时间:

当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为0或者负 数使得无限等待(根据不同连接池配置)。

数据连接池原理

连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数 据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户 也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连 接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数 以及每个连接的最大使用次数、最大空闲时间等等,也可以通过其自身的管理机制来监视数据库连接的 数量、使用情况等。

[(img-DU2RUouK-1629773538473)(C:/Users/libra/Desktop/kkb/5/5.4/image-20210822200515448.png)]

注1:在DBCP连接池的配置中,还有一个maxIdle的属性,表示最大空闲连接数,超过的空闲连接将被释 放,默认值为8。对应的该属性在Druid连接池已不再使用,配置了也没有效果,c3p0连接池则没有对 应的属性。

注2:数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连 接。如果当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个 连接,如果这个等待时间超过了maxWait,则会报错;如果当前正在使用的连接数没有达到 maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在 连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值