Understand JDBC, one article is enough

This article has participated in the "Newcomer Creation Ceremony" event to start the road of gold creation together.

introduction

Dear friends, this time I have summarized and sorted out JDBC-related knowledge for you. This article mainly describes the principle of JDBC, interspersed with some database related knowledge, as well as the understanding and summary of POJO layer and DAO layer in the SSM framework.

By reading this article, you can quickly understand and master the theoretical knowledge of JDBC, and make a small preparation for systematically learning the framework in the future.

Origin of JDBC

In the early days, SUN wanted to write a set of APIs that could connect to all databases, but found a problem at the very beginning. There are huge differences between database servers of various manufacturers. Later, SUN negotiated with the database vendors. In the end, SUN was responsible for providing a set of specifications for accessing the database and the protocol standard for connecting to the database, and each database vendor would follow the specifications of SUN and provide a set of APIs for accessing their own database servers.
The specification provided by SUN is JDBC, and the APIs provided by major manufacturers that can access their databases are called drivers.

Just remember one thing here , JDBC is an interface, the JDBC driver implements the interface, and the database connection cannot be realized without the driver.

Briefly

Before explaining the specific method, we should know what a complete database operation looks like.
which is

  1. Connect to the database
  2. Operate on the database (CRUD)
  3. close database connection

Connect to the database

Information required to connect to the database :

  • The address URL of the database jdbc:database://server ip

Address: port number/database name? Time zone setting…

  • The username for the database The default username is root
  • database password
  • The database driver can be searched and downloaded from this website . Please
    note that the downloaded version should be the same as the one you use.

以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

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

Guess you like

Origin juejin.im/post/7084033694578507789