JDBC(Java Database Connectivity)
JDBC属于JavaSE的一部分,是一个用于连接数据库和执行SQL语句的java api。它通过JDBC驱动去连接数据库,其驱动程序主要分为以下四种(解释参考百度百科):
- JDBC-ODBC Bridge Driver(JDBC-ODBC桥驱动程序)(在 java 8,其已经被移除)
- 由JDBC-ODBC桥和一个ODBC驱动程序组成
- 通过一段本地的C代码将JDBC调用转化为ODBC调用(需在计算机上装好ODBC驱动程序)
- 优点:
- 容易去使用
- 可以很容易的去连接任何数据库
- 缺点:
- 性能下降(JDBC转换到ODBC)
- 需在计算机上装好ODBC驱动程序
- Native Driver(本地驱动程序)
- 也是如上所说将JDBC API转化为Native API进而能够进行数据的存取操作(需在计算机装好类似的驱动程序)
- 优点:
- 较上面的驱动程序有一些提升
- 缺点:
- 需在计算机装好类似的驱动程序
- 需要安装供应商的客户端库
- Network Protocol Driver(网络协议驱动程序)
- 驱动程序将JDBC访问转换成与数据库无关的标准网络协议(通常是HTTP或HTTPS送出),然后由中间件服务器将其转换成数据库专用的访问指令,完成对数据库的操作。(需在安装数据库管理系统的服务器端加装中间件,这个中间件负责所有存取数据库时必要的转换,该中间件服务器支持对多种数据库的访问)
- 优点:
- 不要求安装客户端的一些库。
- 缺点:
- 要求有网络
- 要求在中间层中完成特定于数据库的编码
- 驱动程序的维护昂贵
- Thin Driver('瘦’驱动程序)
- 使用该类驱动无需安装任何附加的软件(无论是本地计算机或是数据库服务器端),所有的存取数据库的操作都直接有JDBC驱动程序来完成,此类驱动程序能将JDBC调用转换成DBMS专用的网络协议,能够自动识别网络协议下的特殊数据库并能直接创建数据连接。
- 优点:
- 比其他的驱动程序有更好的性能。
- 该类驱动无需安装任何附加的软件
- 缺点:
- 驱动依赖于数据库
我们能够使用JDBC API可以在任何的关系型数据库中访问元数据,也就是指可以实现数据的增删查改,类似于Microsoft提供的ODBC。
为什么选择JDBC呢?
在JDBC出现之前,ODBC是广泛被用于对数据库的操作,然而它是用C语言编写的,便会带来一个不可以移植的毛病,同时也是不太安全的,这时就迫切需要一个api可以跨平台使用,所以JDBC应运而生,相比之下,个人觉得JDBC优势更大。
连接数据库步骤
- 注册驱动程序类(可选)
- 创建连接
- 生成SQL语句
- 执行查询
- 关闭连接
要将JAVA Application和Database连接起来,需要一个mysql-connector.jar文件(我直接使用maven仓库下载)。
一个简单的例子说明这个步骤:
package ink.kilig;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 一个用于连接MYSQL数据库的测试Demo
*/
public class ConnectDatabaseDemo {
private final String USERNAME= "root";
private final String PASSWORD = "19991214";
@Test
public void connectDatabase(){
try {
//1.注册驱动程序类
//Class.forName("com.mysql.cj.jdbc.Driver"); //可选
//2.生成连接 url=jdbc::mysql://连接地址+端口/数据库?附加参数
String URL = "jdbc:mysql://localhost:3306/corejava?serverTimezone=Hongkong";
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
//3.生成语句
Statement statement = connection.createStatement();
//4.执行查询
ResultSet resultSet = statement.executeQuery("select * from coursetable where Time=1");
while(resultSet.next()){
System.out.println(resultSet.getInt("Time")+" "+
resultSet.getString("Monday")+" "+
resultSet.getString("Tuesday"));
}
//关闭连接 释放资源
connection.close(); //这个try catch 可以换成带资源的,就不需要单独显式写出close语句
} catch (Exception e) {
e.printStackTrace();
}
}
}
一些关于DriverManager的使用细节可以查看java se8的api文档java 8
需要说明的是:
每一个Connect对象是可以创建多个Statement对象的。一个Statement对象可以用于多个不相关的命令和查询。但是一个Statement对象最多只能有一个打开的结果集(如果要同时处理多个结果集,建议使用组合查询)
浅谈预备语句
看上述的代码,如果我们直接写好SQL语句,且每一个参数都指定好,那么其可重用性就比较差,也就是说我们要查询其他的数据时,就要重新再写一个SQL语句,遇到短的SQL语句,这样的操作不会感到很大的压力,但是当你遇到比较长的查询语句时:
SELECT student.sname,student.sno FROM student,sc WHERE sc.sno=student.sno AND student.depart=xxxx
每次都要重写就显得有点多余了。
这时就需要一个可带宿主变量的查询语句,通过改变宿主变量就可以反复使用这个查询语句,从而提高效率。那么我们来看看它的使用方法吧:
SELECT sname,sno FROM student WHERE sno=?
在预备查询语句中,每一个宿主变量都用“?”来表示,当然,如果存在一个"?“以上的变量,在设置变量的值时应该注意一下”?"的位置。
请看例子:
@Test
public void prepareStaTest() {
String URL = "jdbc:mysql://localhost:3306/corejava?serverTimezone=Hongkong";
try (Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
String querySql = "select * from coursetable where Time=?";
PreparedStatement statement = connection.prepareStatement(querySql);
//用于绑定参数的值 第一个参数为位置,从1开始,第二个参数表示绑定的值
statement.setString(1, "3");
//绑定之后可以直接执行了
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getInt("Time") + " " +
resultSet.getString("Monday") + " " +
resultSet.getString("Tuesday"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
**提示:**通过连接字符串可能会存在SQL注入的危险,除非在必要的情况下(涉及到变量时才应使用预备语句)
上述的只是查询语句,如果要使用update等更新语句,也请查询api文档进行操作,具体也不再解释。
更新语句的一个例子(如插入一个数据):
@Test
public void prepareStaTest() {
String URL = "jdbc:mysql://localhost:3306/corejava?serverTimezone=Hongkong";
try (Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
String querySql = "insert into coursetable values (6,'语文','英语','数学','a','b','c','e')";
PreparedStatement statement = connection.prepareStatement(querySql);
int result = statement.executeUpdate();
System.out.println(result);
} catch (SQLException e) {
e.printStackTrace();
}
}