搞清楚JDBC,一篇就够了

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

引言

各位掘友好,这次给大家归纳整理了JDBC相关知识。本文主要讲述JDBC的原理部分,其中穿插一些数据库的相关知识,另外还有SSM框架中POJO层,DAO层的理解与总结。

通过阅读这篇文章,大家能够快速理解并掌握JDBC的理论知识,并为日后系统地学习框架作一个小小的铺垫。

JDBC的起源

早期SUN公司想编写一套可以连接所有数据库的API,但是刚一开始就发现了问题,各个厂商的数据库服务器存在巨大的差异。后来SUN公司与数据库厂商们商议,最终,由SUN负责提供一套访问数据库的规范,以及连接数据库的协议标准,而各数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API。
SUN公司提供的规范就是JDBC,而各大厂商提供的可以访问其数据库的API称之为驱动。

这里只需记住一点,JDBC是接口,JDBC驱动实现了接口,没有驱动无法实现数据库连接。

简述

在讲解具体的方法前,我们应当知道一次完整的数据库操作是什么样的。

  1. 连接数据库
  2. 对数据库进行操作(CRUD)
  3. 关闭数据库连接

连接数据库

连接数据库需要的信息

  • 数据库的地址URL     jdbc:数据库://服务器ip

地址:端口号/数据库名?时区设置…

  • 数据库的用户名     默认用户名是root
  • 数据库的密码
  • 数据库的驱动 可在此网站中搜索并下载 对应的数据库驱动
    注意下载的版本要与自己使用的一致

以MySql为例
URL:jdbc:mysql://127.0.0.1:port/dbname?......
  注:127.0.0.1:数据库服务器所在的ip地址 即localhost (表示数据库服务器在本地)
    port:端口号,默认是3306
    dbname:要访问数据库的名称
8.0的驱动:com.mysql.cj.jdbc.Driver
5.x版本的数据库驱动:com.mysql.jdbc.Driver

Connnection对象 是java中用来表示数据库连接的对象

连接数据库的方法

步骤:
1.安装驱动(加载驱动类)Class.forName(driver)
2.获取数据库连接 DriverManager.getConnection(url,username,password) 返回Connection类型对象

操作数据库

相关的Java对象和常用方法

Statement对象(可能会出现sql注入的情况,不推荐):

sql语句对象

常用的方法:

  • execute(sql): 执行sql语句,返回是否执行成功,成功返回true,失败返回false
  • executeUpdate(sql): 执行sql语句(DML操作),返回成功数量
  • executeQuery(sql): 执行sql语句(查询),返回 从数据库中查询的数据集合(结果集)
  1. 当做数据库数据更新时(增加,修改,删除).使用executeUpdate()
  2. 当做查询操作的时候,使用executeQuery();

使用步骤:

//建立连接
Connection connection=...;
//获得语句处理对象
Statement statement=connection.createStatement();
//构建sql语句(通过拼接)
String sql=".......";
//执行语句
statement.executeUpdate(sql)/executeQuery(sql)...;
复制代码

PreparedStatement对象(推荐):

预编译的sql语句对象(可避免sql注入问题)

常用的方法:

  1. setString(参数位置 , 参数内容) setInt(参数位置 , 参数内容)…
  2. executeUpdate() 返回值是一个整数,指的是受影响的行数
  3. executeQuery() 返回ResultSet对象,用于存放数据库响应的查询结果

这里2、3的使用方法与与statement中的类似,区别在于有无sql参数

使用步骤:

//建立连接
Connection connection = …;
//构建sql语句
String sql="........";
//获得语句处理对象
PreparedStatement preparedStatement=connection.prepareStatement(sql);
//设置参数
preparedStatement.setString(...,...);
//执行语句
preparedStatement.executeUpdate()/executeQuery()...
复制代码

ResultSet对象

使用executeUpdate()进行数据查询后返回的结果集,是存储查询结果的对象。
结果集并不仅仅具有存储的功能,同时还具有操纵数据的功能,可以完成对数据的更新等。

结果集读取数据的方法是getXXX(),如getString(参数)。
参数可以是整型表示第几列(是从1开始的),也可以是列名,返回对应的数据类型的值。
如果对应那一列为null,XXX是对象的话返回null,如果XXX是数字类型,如Float等则返回0,boolean返回false。

XXX可以代表的类型有:基本数据类型如整型(int),布尔型(Boolean),浮点型(Float,Double)等,另外还包括一些特殊的类型,如日期类型(java.sql.Date),时间类型(java.sql.Time),时间戳类型 (java.sql.Timestamp)等。

  1. 基本的ResultSet

这种ResultSet起到的作用就是查询结果的存储,只能读取一次,不能够来回的滚动读取。
这种结果集的创建方式如下:

Statement st = connection.CreateStatement 
ResultSet rs = st.excuteQuery(sql); 
复制代码

如果获得这样一个结果集,只能调用它的next()方法,逐个读取数据。

  1. 可滚动的ResultSet

这个类型支持前后滚动取得纪录next()、previous(),回到第一行first(),同时还支持要去的ResultSet中的第几行 absolute(int n),以及移动到相对当前行的第几行relative(int n),要实现这样的ResultSet在创建Statement时用如下的方法。

Statement st = connection. createStatement (int resultSetType, int resultSetConcurrency) 
ResultSet rs = st.executeQuery(sql) 
复制代码

其中
resultSetType 是设置 ResultSet 对象的类型可滚动,或者是不可滚动:

  • ResultSet.TYPE_FORWARD_ONLY 只能向前滚动
  • ResultSet.TYPE_SCROLL_INSENSITIVE
  • ResultSet.TYPE_SCROLL_SENSITIVE

后面两个方法都能够实现任意的前后滚动,支持结果集backforward ,random ,last ,first 等操作, 二者的区别在于前者对数据库中数据做出的修改是不敏感的,而后者对于修改敏感。(session暂且不讲)

resultSetConcurency 是设置 ResultSet 对象能否被修改,取值如下:

  • ResultSet.CONCUR_READ_ONLY 设置为只读类型的参数。
  • ResultSet.CONCUR_UPDATABLE 设置为可修改类型的参数。

例如:

Statement st = conn.createStatement(Result.TYPE_SCROLL_INSENITIVE,ResultSet.CONCUR_READ_ONLY); 
ResultSet rs = st.excuteQuery(sqlStr) ; 
复制代码

用这个 Statement 执行的查询语句得到的就是可滚动的 ResultSet 。

POJO层

之所以考虑在这篇文章讲述POJO,是因为我希望能提供给大家一个更大的视野,不仅仅局限于JDBC,初步认识整个后端开发框架。本人笔力有限,路过的大佬请不吝赐教。若有什么问题,可在评论区讨论交流。

什么是POJO

Plain Ordinary Java Object 即简单Java对象,POJO的内在含义是指那些没有从任何类继承,没有实现任何接口,也没有被其他框架侵入的Java对象。

简而言之,POJO可以看作是与数据库中的表相映射的Java对象

一个POJO持久化以后就是PO(persistent object),可以把数据库中一条记录作为一个PO对象处理,多个记录可以用PO的集合表示。

POJO的意义

使开发者专注于业务逻辑和脱离框架的单元测试。因为它的简单和灵活,使得POJO能够任意扩展,从而胜任多个场合,让一个模型贯穿多个层

在此之前还没接触这个掘友可能暂时无法体会其中的好处,日后我会陆续发一些文章,帮助大家理解。

POJO与PO区别

POJO是由new创建,由GC回收。但是PO对象是insert数据库创建,由数据库delete删除,持久对象生命周期和数据库密切相关。持久对象往往只能存在一个Connection中,Connection关闭后,持久对象就不存在了

如何去写

POJO已经说完了,我们回归JDBC,有了上面的铺垫,具体应该怎么操作相信大家心里已经有答案。

我们可以将数据库中的每张数据表对应一个Java实体类(POJO),实体类的属性 对应 数据表的字段,让数据库表中的数据暂存在实体类对象中。

这样做的话,不必每次都访问数据库拿到想要的数据,直接通过对象获取即可

dao层

Dao(Data access object),即数据访问层。封装了一些对数据库的操作,具体可到某个表、某个实体的增删改查,映射到某个java对象(POJO)。

为什么dao这一层

一个庞大的项目一定是分层的,如MVC模式。这么做是为了降低各层的耦合度,使得各个层职责边界清晰,便于对后续代码进行维护扩展,同时也是为了整个团队提高开发效率。

如何使用

而实际操作上,我们可以写一个接口,用来处理程序和数据库之间的交互,把具体的操作业务放在接口的实现类中。
可以调用此接口来进行数据的处理,而不用关心此接口的具体实现类是哪个类,结构清晰。

三种实现方式

这里为大家介绍三种实现JDBC的方式,供大家参考。

1.0

JDBC的原理部分和需要用的一些对象方法都已经说完,将其组合运用起来就是我们JDBC的1.0版本。

2.0

在1.0版本的基础上,我们做些改进。
可以将连接数据库的参数信息放在properties配置文件中,以键值对的形式(key=value)存放。 同时,引入static代码块,通过Properties和文件流,初始化参数。
这么一来,可以提高代码的利用率,每次修改只需更改对应的参数就行了。
注意properties文件格式:

  1. 不可有空格
  2. 未写完之前不允许回车

3.0

3.0版本,我们可以更进一步。借助第三方工具,使用连接池,如Apache开发的DBCP2,hibernate工作组维护的C3P0,还有阿里巴巴的druid等等,帮助我们自动管理数据库的连接和释放。
需要注意的是,使用第三方工具时,要严格按照其规定格式。例如,在使用druid时,properties文件参数名key是固定的

使用连接池的好处

  1. 数据库资源得到重用
  2. 减少数据库连接建立和释放的资源开销,提高系统响应速度,降低I/O开销
  3. 进行统一的数据库管理,减少JVM垃圾,减少数据库的过载

数据库的进阶操作

事务处理

学习事务处理之前,首先得了解数据库的ACID特性

  • 原子性:事务可以看做一个不可再分的整体事务中的操作要么都发生,要么都不发生
  • 一致性:事务一旦完成,所有的数据需要保持一致
  • 隔离性:多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
  • 持久性:事务的操作最终会持久化到数据库中

随着业务场景不断复杂,单一操作已经不能满足我们的需求,需要将多个操作或者命令一起执行。
这就要求所有命令全部成功执行才意味着该事务的成功,任何一个命令的失败都意味着该事务失败(例如:转账)

那么具体该如何操作呢?请接着往下看

  1. 执行sql语句之前需设置事务手动提交
    connection.setAutoCommit(false);
    此时,使用executeUpdate() 等语句,数据并未持久化
  2. 经判定后 事务执行成功 提交事务
    connection.commit();
    若事务执行出现异常,数据需要回滚
    connection.rollback();
  3. 当本次操作结束后,为防止影响后续操作,还需将事务的提交方式设置为自动提交
    connection.setAutoCommit(true);

前辈们已经写好了方法,我们只要会用就行了。

Batch 批处理

当我们要进行大量的DML操作时,我们可以使用批处理
这样的话,可以减少资源的浪费,一次执行多条sql语句,提高效率,缩短sql语句执行时间

别忘了,每当执行完一次批处理,就清空批处理

步骤\语句 Statement PreparedStatement
添加(不宜添加太多,防止内存溢出) statement.addBatch( sql ) preparedStatement.addBatch()
执行(批处理执行后,会返回int[ ]) statement.executeBatch() preparedStatement.executeBatch()
清空 statement.clearBatch() preparedStatement.clearBatch()

END

希望各位掘友看完这篇文章后,有所收获。有什么问题的话,可以在评论区留言。如果觉得文章写得还不错的话,就给个赞呗,您动动手指就是对我莫大的鼓励!

猜你喜欢

转载自juejin.im/post/7084033694578507789