文章目录
JDBC概述
JDBC(Java Database Connectivity)是Java语言访问数据库的标准API。它提供了一种方法,使得Java应用程序能够与各种关系型数据库进行交互,包括连接数据库、发送查询和更新语句、获取查询结果等。JDBC API提供了一组接口和类,使开发人员能够编写数据库无关的代码,从而更容易地切换和管理不同类型的数据库。
在使用JDBC时,通常会涉及以下几个核心概念和步骤:
- 加载驱动程序:在使用JDBC之前,需要加载适当的数据库驱动程序,以便与特定的数据库进行通信。这通常通过调用Class.forName(“com.mysql.cj.jdbc.Driver”)或者DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver())来实现。
- 建立连接:一旦驱动程序加载完成,就可以使用DriverManager.getConnection(url, user, password)方法来建立与数据库的连接。其中,url是指向特定数据库的URL,user和password是数据库的用户名和密码。
- 创建语句:一旦连接建立成功,就可以使用Connection对象的createStatement()或prepareStatement()方法来创建用于执行SQL语句的Statement或PreparedStatement对象。
- 执行查询和更新:通过调用Statement或PreparedStatement对象的executeQuery()或executeUpdate()方法,可以执行数据库查询或更新操作。
- 处理结果:如果执行的是查询操作,就可以通过ResultSet对象来获取查询结果,并对结果进行处理。
- 关闭连接:最后,在使用完数据库连接和相关资源后,需要通过调用close()方法来关闭连接、Statement、ResultSet等资源。
总的来说,JDBC提供了一种基于Java的标准方式来操作各种关系型数据库,使得开发人员能够使用统一的API来访问不同类型的数据库,从而简化了数据库访问的过程。
什么是JDBC,在什么时候会用到它?
JDBC的全称是Java DataBase Connection,也就是Java数据库连接,我们可以用它来操作关系型数据库。JDBC接口及相关类在java.sql包和javax.sql包里。我们可以用它来连接数据库,执行SQL查询,存储过程,并处理返回的结果。JDBC接口让Java程序和JDBC驱动实现了松耦合,使得切换不同的数据库变得更加简单。
原生 jdbc 操作数据库流程
加载数据库驱动
建立数据库连接
创建一个预编译的Statement
执行sql语句
关闭连接
第一步:Class.forName()加载数据库连接驱动;
第二步:DriverManager.getConnection()获取数据连接对象;
第三步:根据 SQL 获取 sql 会话对象,有 2 种方式 Statement、PreparedStatement ;
第四步:执行 SQL 处理结果集,执行 SQL 前如果有参数值就设置参数值 setXXX();
第五步:关闭结果集、关闭会话、关闭连接。
PreparedStatement和Statement
1PreparedStatement 接口继承 Statement,PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement 对象。
2 、 作 为 Statement 的 子 类 , PreparedStatement 继承了 Statement 的 所 有 功 能 。 三 种 方法 execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数
3、在 JDBC 应用中,在任何时候都不要使用 Statement,原因如下:
一、代码的可读性和可维护性.Statement 需要不断地拼接,而 PreparedStatement 不会。
二、PreparedStatement 尽最大可能提高性能.DB 有缓存机制,相同的预编译语句再次被调用不会再次需要
编译。
三、最重要的一点是极大地提高了安全性.Statement 容易被 SQL 注入,而 PreparedStatementc 传入的内
容不会和 sql 语句发生任何匹配关系。
PreparedStatement比Statement有什么优势?
PreparedStatements是预编译的,因此,性能会更好。同时,不同的查询参数值,PreparedStatement可以重用。
相对于Statement,PreparedStatement的优点是什么?
它和Statement相比优点在于:
PreparedStatement有助于防止SQL注入,因为它会自动对特殊字符转义。
PreparedStatement可以用来进行动态查询。
PreparedStatement执行更快。尤其当你重用它或者使用它的拼量查询接口执行多条语句时。
使用PreparedStatement的setter方法更容易写出面向对象的代码,而Statement的话,我们得拼接字符串来生成查询语句。如果参数太多了,字符串拼接看起来会非常丑陋并且容易出错。
JDBC的Statement是什么
Statement是JDBC中用来执行数据库SQL查询语句的接口。通过调用连接对象的getStatement()方法我们可以生成一个Statement对象。我们可以通过调用它的execute(),executeQuery(),executeUpdate()方法来执行静态SQL查询。
由于SQL语句是程序中传入的,如果没有对用户输入进行校验的话可能会引起SQL注入的问题,如果想了解更多关于SQL注入的,可以看下这里。
默认情况下,一个Statement同时只能打开一个ResultSet。如果想操作多个ResultSet对象的话,需要创建多个Statement。Statement接口的所有execute方法开始执行时都默认会关闭当前打开的ResultSet
什么是JDBC连接,在Java中如何创建一个JDBC连接
JDBC连接是和数据库服务器建立的一个会话。你可以想像成是一个和数据库的Socket连接。
创建JDBC连接很简单,只需要两步:
A. 注册并加载驱动:使用Class.forName(),驱动类就会注册到DriverManager里面并加载到内存里。 B. 用DriverManager获取连接对象:调用DriverManager.getConnnection()方法并传入数据库连接的URL,用户名及密码,就能获取到连接对象。
Connection con = null;
try{
// load the Driver Class
Class.forName("com.mysql.jdbc.Driver");
// create the connection now
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/DBName",
"username",
"password");
}catch (SQLException e) {
System.out.println("Check database is UP and configs are correct");
e.printStackTrace();
}catch (ClassNotFoundException e) {
System.out.println("Please include JDBC MySQL jar in classpath");
e.printStackTrace();
}
jdbc详解
Class.forName()方法有什么作用?
初始化参数指定的类,并且返回此类对应的Class 对象
什么时候使用CallableStatement?用来准备CallableStatement的方法是什么?
CallableStatement用来执行存储过程。存储过程是由数据库存储和提供的。存储过程可以接受输入参数,也可以有返回结果。非常鼓励使用存储过程,因为它提供了安全性和模块化。准备一个CallableStatement的方法是:CallableStatement Connection.prepareCall();
数据库连接池
像打开关闭数据库连接这种和数据库的交互可能是很费时的,尤其是当客户端数量增加的时候,会消耗大量的资源,成本是非常高的。可以在应用服务器启动的时候建立很多个数据库连接并维护在一个池中。连接请求由池中的连接提供。在连接使用完毕以后,把连接归还到池中,以用于满足将来更多的请求。
解释下Serialization和Deserialization。
Java提供了一种叫做对象序列化的机制,他把对象表示成一连串的字节,里面包含了对象的数据,对象的类型信息,对象内部的数据的类型信息等等。因此,序列化可以看成是为了把对象存储在磁盘上或者是从磁盘上读出来并重建对象而把对象扁平化的一种方式。反序列化是把对象从扁平状态转化成活动对象的相反的步骤。
jDBC的DriverManager是用来做什么的
JDBC的DriverManager是一个工厂类,我们通过它来创建数据库连接。当JDBC的Driver类被加载进来时,它会自己注册到DriverManager类里面,你可以看下JDBC Driver类的源码来了解一下。
然后我们会把数据库配置信息传成DriverManager.getConnection()方法,DriverManager会使用注册到它里面的驱动来获取数据库连接,并返回给调用的程序。
execute,executeQuery,executeUpdate的区别是什么
Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。我们可以通过它的getResultSet方法来获取ResultSet,或者通过getUpdateCount()方法来获取更新的记录条数。
Statement的executeQuery(String query)接口用来执行select查询,并且返回ResultSet。即使查询不到记录返回的ResultSet也不会为null。我们通常使用executeQuery来执行查询语句,这样的话如果传进来的是insert或者update语句的话,它会抛出错误信息为 “executeQuery method can not be used for update”的java.util.SQLException。
Statement的executeUpdate(String query)方法用来执行insert或者update/delete(DML)语句,或者 什么也不返回DDL语句。返回值是int类型,如果是DML语句的话,它就是更新的条数,如果是DDL的话,就返回0。
只有当你不确定是什么语句的时候才应该使用execute()方法,否则应该使用executeQuery或者executeUpdate方法。
JDBC的ResultSet是什么
在查询数据库后会返回一个ResultSet,它就像是查询结果集的一张数据表。
ResultSet对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了ResultSet的next()方法游标会下移一行,如果没有更多的数据了,next()方法会返回false。可以在for循环中用它来遍历数据集。
默认的ResultSet是不能更新的,游标也只能往下移。也就是说你只能从第一行到最后一行遍历一遍。不过也可以创建可以回滚或者可更新的ResultSet,像下面这样。
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
当生成ResultSet的Statement对象要关闭或者重新执行或是获取下一个ResultSet的时候,ResultSet对象也会自动关闭。
可以通过ResultSet的getter方法,传入列名或者从1开始的序号来获取列数据
如何使用JDBC接口来调用存储过程
存储过程就是数据库编译好的一组SQL语句,可以通过JDBC接口来进行调用。我们可以通过JDBC的
CallableStatement接口来在数据库中执行存储过程。初始化CallableStatement的语法是这样的:
CallableStatement stmt = con.prepareCall("{call insertEmployee(?,?,?,?,?,?)}");
stmt.setInt(1, id);
stmt.setString(2, name);
stmt.setString(3, role);
stmt.setString(4, city);
stmt.setString(5, country);
//register the OUT parameter before calling the stored procedure stmt.registerOutParameter(6, java.sql.Types.VARCHAR);
stmt.executeUpdate();
JDBC的事务管理是什么,为什么需要它
默认情况下,我们创建的数据库连接,是工作在自动提交的模式下的。这意味着只要我们执行完一条查询语句,就会自动进行提交。因此我们的每条查询,实际上都是一个事务,如果我们执行的是DML或者DDL,每条语句完成的时候,数据库就已经完成修改了。
有的时候我们希望由一组SQL查询组成一个事务,如果它们都执行OK我们再进行提交,如果中途出现异常了,我们可以进行回滚。
JDBC接口提供了一个setAutoCommit(boolean flag)方法,我们可以用它来关闭连接自动提交的特性。我们应该在需要手动提交时才关闭这个特性,不然的话事务不会自动提交,每次都得手动提交。数据库通过表锁来管理事务,这个操作非常消耗资源。因此我们应当完成操作后尽快的提交事务。在这里有更多关于事务的示例程序。
如何回滚事务
通过Connection对象的rollback方法可以回滚事务。它会回滚这次事务中的所有修改操作,并释放当前连接所持有的数据库锁。
JDBC的保存点(Savepoint)是什么,如何使用?
有时候事务包含了一组语句,而我们希望回滚到这个事务的某个特定的点。JDBC的保存点可以用来生成事务的一个检查点,使得事务可以回滚到这个检查点。
一旦事务提交或者回滚了,它生成的任何保存点都会自动释放并失效。回滚事务到某个特定的保存点后,这个保存点后所有其它的保存点会自动释放并且失效。可以读下这个了解更多关于JDBC Savepoint的信息。
JDBC的DataSource是什么,有什么好处?
DataSource即数据源,它是定义在javax.sql中的一个接口,跟DriverManager相比,它的功能要更强大。我们可以用它来创建数据库连接,当然驱动的实现类会实际去完成这个工作。除了能创建连接外,它还提供了如下的特性:
缓存PreparedStatement以便更快的执行
可以设置连接超时时间
提供日志记录的功能
ResultSet大小的最大阈值设置
通过JNDI的支持,可以为servlet容器提供连接池的功能
常见的JDBC异常有哪些
有以下这些:
java.sql.SQLException——这是JDBC异常的基类。
java.sql.BatchUpdateException——当批处理操作执行失败的时候可能会抛出这个异常。这取决于具体的JDBC驱动的实现,它也可能直接抛出基类异常java.sql.SQLException。
java.sql.SQLWarning——SQL操作出现的警告信息。
java.sql.DataTruncation——字段值由于某些非正常原因被截断了(不是因为超过对应字段类型的长度限制)。
什么是JDBC的最佳实践
下面列举了其中的一些:
数据库资源是非常昂贵的,用完了应该尽快关闭它。Connection, Statement, ResultSet等JDBC对象都有close方法,调用它就好了。
养成在代码中显式关闭掉ResultSet,Statement,Connection的习惯,如果你用的是连接池的话,连接用完后会放回池里,但是没有关闭的ResultSet和Statement就会造成资源泄漏了。
在finally块中关闭资源,保证即便出了异常也能正常关闭。
大量类似的查询应当使用批处理完成。
尽量使用PreparedStatement而不是Statement,以避免SQL注入,同时还能通过预编译和缓存机制提升执行的效率。
如果你要将大量数据读入到ResultSet中,应该合理的设置fetchSize以便提升性能。
你用的数据库可能没有支持所有的隔离级别,用之前先仔细确认下。
数据库隔离级别越高性能越差,确保你的数据库连接设置的隔离级别是最优的。
如果在WEB程序中创建数据库连接,最好通过JNDI使用JDBC的数据源,这样可以对连接进行重用。
如果你需要长时间对ResultSet进行操作的话,尽量使用离线的RowSet。