文章目录
What JDBC? 从数据库连接方式说起
三种数据库连接方式
- 命令行形式
- 图形化IDE
- 应用程序编程接口(API)
流行数据库的数据库种类
- Oracle
- IBM DB2
- MySQL
- Microsoft SQL Server
- …
类型如此之多的数据库对于Java应用程序的访问带来哪些影响呢?
- 开发角度:学习难度大,开发一套应用程序,需要了解所有流行的数据库。
- 可迁移性:当该程序从一个数据库迁移到另一套数据库时,应用框架的数据库访问部分便必须要修改。
如何解决这种不变呢?
- 提供统一的编程接口,应用程序仅需对该接口负责,而不需要了解底层数据库的差异。
- 这些差异由该接口负责处理屏蔽掉,我们使用接口的时候,就像面向同一个数据库,不论我们真实情况下是使用的MySQL还是SQL Server。
- 这种统一的接口设计又一次显示出抽象的设计模式。* 而用于Java应用程序访问数据库的统一的编程接口就被称为JDBC,也即:Java DataBase Connectity。
- 对于应用程序开发者而言,JDBC与一般的jar包没有什么不同。
- 对于不同的数据库厂商而言,JDBC是在实现一个数据库时,所必须遵循的一种规范,就像浏览器厂商必须要支持HTML协议规范一样。当然如果你是数据库开发厂商,你也可以选择不支持O(∩_∩)O。
理解了JDBC的体系架构,就知道了差异的屏蔽是如何实现的
- JDBC API:负责和Java应用程序的通信。
- JDBC Driver API:和具体的数据库建立连接,一般由数据库厂商提供。
所以JDBC的优势呼之欲出
- 简单、开发快捷:面向统一的编程接口进行应用程序的开发
- 移植性:对于不同的数据库而言
- 框架:基于JDBC之上的框架
JDBC这么好,我也想用
- JDBC jar包已经集成在JDK中,不需要下载。
- JDBC驱动程序,在Oracle官网下载,完成后将jar包包含到java工程中即可。
在Java程序中使用JDBC
JDBC API了解一哈
Driver和DriverManager
- Driver是一个借口,定义了驱动程序所需要实现的功能,是对驱动程序的抽象;通过操作Driver对象,即可实现对各个驱动程序的操作。
- DriverManager是Driver的管理类。
- Class.forname(driverName)
- getConnection(url, user, psw)
- JDBC URL
- 协议
- 子协议 -> Driver Manager据此知道通过哪个驱动程序建立到数据库的连接。
- 子名称:主机ip、port、数据库名。
Connection、Statement、ResultSet、SQLException
- Connection对象
- 代表到数据库的一条物理连接
- Statement对象
- SQL的容器,在该容器中可以承载sql语句,并可以执行增删改查等常用功能。
- executeQuery(sql) -> ResultSet,表示查询到的行数据
- select
- executeUpdate(sql) -> int值,表示该更改影响了多少行
- insert、delete、update
- ResultSet对象:
- 代表一个由行和列组成的二元表
- 其中有一个光标的概念:初始时位于第一行的前端(并不是第一条记录,而是当该RS对象进行next方法后,该光标才可以定位到第一条记录)
- next(),previous():前一行、后一行
- beforeFirst()、afterLast():第一行之前、最后一行之后
- absolute():定位光标到具体的某一行
- getXXX(ColumnName/Index):通过列名或者列标号(从0开始)定位某一列
Java应用程序中使用JDBC的基本步骤
-
加载驱动程序
Class.forName()
-
创建连接
DriverManager.getConnection()
-
执行SQL语句
- Statement/PreStatement对象的相应方法
-
获取结果集
- sql语句执行后返回:ResultSet对象/int值
-
清理资源:connection、statement/preStatement、ResultSet
- 要在finally块内执行,防止因为之前的操作出现异常资源无法清理的状况出现
- 数据库连接是很珍贵的运行时资源,如果在数据库服务完成后服务器没有主动关闭该条连接,那么数据库不会主动关闭,除非等到连接超时,这个时间一般是8个小时。
- 清理资源的方式是调用各自的close()方法,不过在执行该方法时首先要判定该方法的执行主体是否为null,否则会抛出空指针异常。
JDBC应用时遇到的一些问题
数据太多导致内存溢出异常
- 过滤条件太弱,导致一次查询过多的数据行
- 读取数据表中所有的数据
- 解决方式:
- 每次读取一部分
- 游标:允许客户端每次部分读取数据库,由数据库支持
- 游标的使用:
- 开启数据库游标:
DB_URL = DB_URL + “useCursorFetch=true”
- 使用PreparedStatement替代Statement对象:
pstmt.setFetchSize(10)
- 开启数据库游标:
数据库存储大字段内容
- 博客、图片
- 可能一条记录读取就会导致JVM内存溢出
- 解决方式
- 流方式读取数据库
- 使用临时文件缓存
InputStream in = rs.getBinaryStream("colName");
FileOutputStream out = new FileOutputStream(
new File("filename")
);
int temp = 0;
while( (temp=in.read()) != -1 ) {
out.write(temp);
}
in.close();
//try...catch...省略
* 每次读取流数据的一行,写入到文件中,知道该列数据读取完毕
数据库大量插入数据
- 效率很低:因为每插入一条数据,就发送一条SQL语句
- 解决办法:批处理方式
- Statement相关方法:
- addBatch()
- executeBatch()
- clearBatch()
- sql语句不是每条都提交到数据库中执行,而是缓存到一个Batch单元中,只有当executeBatch()方法执行时才会整体提交到数据库执行。这样就做到了传输一次,批处理很多sql语句。
- clearBatch()将Batch单元中当前的所有sql语句清空,应当在执行完executeBatch()后调用。
数据库中文编码
-
数据库编码级别
- mysql数据库在以下四个级别设置了编码规则,可通过命令行或者IDE在数据库建立的时候就指定
- server < database < table < colomn
- 级别低的会被高级别的规则覆盖
-
JDBC编码,在应用程序中设置
DB_URL = DB_URL + characterEncoding=utf8
-
项目编码、web页面编码