分享

Java编程开发学习之JDBC

 quasiceo 2018-07-27
2017-11-03 11:52:44      0个评论    来源:ysflizi的专栏  
收藏   我要投稿

Java学习之JDBC

持久化

目前广泛使用的应该还是mysql,nosql。对于NoSQL目前我还没有太多的认识,长路漫漫,慢慢学习中…
在Java中,JDBC应该是被大家摒弃的,因为如果真的采用JDBC去写代码,太多模版代码,有点洁癖的程序猿估计都不想看到自己的代码冗余,会想方设法的去减少模版代码,这个时候就有太多的工具了,意图减少此类模板代码(其实主要的模版代码是建立connection,组装sql,获取结果集,组装POJO,顺便说明一下,有人主张划分VO,DTO,POJO,经过我自己写代码,有好处有不好的地方,看自己的偏好吧),spring jdbctemplate(技术应该已经过时)、hibernate、mybatis、JSR-220、spring data…东西太多了,我知道的太有限,但是估计大家都知道,这些框架,或者工具的简历都离不开JDBC,由此可见JDBC其实还是很重要的,虽然这些工具简化了数据库的操作,但是如果想知道为什么这么设计,了解JDBC你就知道了~~~

数据库框架选择

这个问题其实我在网上查了很久,翻了一下我的第一条查询纪录,大概是四月份,在两个月之前我就开始查了, 一直没找到合适的解释,不过我还是想要说说我自己的看法.

JDBC 大家都知道它是啥玩意,又各个厂商开发提供实现,Java SE制定了相关的规范 JPA JSR-220,在众多框架的发展之后,JCP意识到应该有一个规范了,于是JPA诞生了 hibernate 这个不用多说了,大家都懂 mybatis 好用,简单,学习成本低 spring data 目标在于对JPA再做一次减法

对于以上内容,估计大部分公司都会做出自己的选择,我也在网上咨询了很多扣扣群,问了群里的大神们自己对数据库框架的选型,其实貌似也没告诉我为什么。一下就是我对框架的看法:

对于这么多框架,其实主要使用的就是hibernate、mybatis。spring data的使用应该还比较少。我问了我很多同事,大家都说hibernate太重,其实功能强大为什么不重呢…mybatis大家可以定制sql,扪心自问,我们有多少数据库查询需要这么care数据库性能。如果我来制定数据库技术方案,我肯定优先使用spring data + JPA + hibernate,实在不行再采用spring + mybatis,原因如下:我自己做事情比较喜欢标准化,因为JPA是标准,而hibernate则很好的支持了JPA,spring data有效的减少了模版代码的产生,加上spring data 可以与批处理框架结合使用,因此我觉得使用它真的是不二之选

JDBC

大部分网上的资料对JDBC的介绍过于简单,只提及了JDBC都不算主要功能的功能。在我看来,JDBC分为以下几部分:

数据库驱动,大家熟悉的DriverManager Connection Statement(包含很多种,下文会依次介绍) ResultSet Transactions 异常 RowSet

驱动

为了获取链接,我们必须要有驱动,驱动其实就是数据库厂商为了适配JDBC而对自己的数据库客户端做的初始化而已,在JDBC 4.0之前我们需要这样初始化:

1
Class.forName("com.mysql.jdbc.Driver");

在JDBC 4.0以后我们将不在需要这行代码。
按照oracle的划分,数据库驱动分为四大类:

做接口映射的驱动,这种驱动把JDBC API映射到其他类型的数据库API 采用Java语言和JNI编写的驱动 采用一个中间的代理服务器,类似于阿里的中间件一样的东东 JDBC 直接跟数据库交互,最直接的方式

与其说oracle划分了四种类型,不如说oracle提供了四种方案,让我们可以选择。

Connection

对于数据库与业务之间,Connection是我们的主体部分,大部分异常处理其实都是这货给的。这里不得不说一句,Golang的多返回值是多么的好用呀,让异常都消失吧。在JDBC中获取链接的方式有两种,分别如下:

DriverManager: 相信众多初学者跟我一样,这个是我们第一个接触到的类,对于另一个我觉得可能大部分人应该不会太熟悉,这里就不再说他了。 DataSource: 其实这个接口是oracle提倡使用的接口,因为他提供了更多细节
1. 使用DriverManager

没什么好说的,我直接贴代码了~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static final String DB_URL = "jdbc:mysql://localhost:3308/database";
private static final String DB_USERNAME = "admin";
private static final String DB_PASSWORD = "admin";
public Connection getConnection() throws SQLException{
    Connection conn = null;
    Properties connectionProps = new Properties();
    connectionProps.put("user", DB_USERNAME);
    connectionProps.put("password", DB_PASSWORD);
    conn = DriverManager.getConnection(DB_URL, connectionProps);
    return conn;
}

2.采用DataSource获取Connection

DataSource接口由各个驱动器厂商实现,oracle把他们划分如下:

基本的DataSource,它产生的每一个Connection都互不干扰,没有池以及分布式事务的概念 支持连接池的DataSource 支持分布式事务的DataSource

oracle 规定,一个驱动至少实现一个基本的DataSource,在学习数据库的时候我相信大家肯定见过BaseicDataSouce这个东西,当时我看到的时候我也不明白,不过现在明白了,哈哈哈,在使用DataSource中其实比DriverManager更复杂,但是更实.

2.1 部署Baseic DataSource
创建一个DataSource 类实例 设置属性 使用JNDI注册DataSource实例
创建数据源并且设置属性
1
2
3
4
BasicDatabaseSource  ds = BasicDatabaseSource();
ds.setServerName("server");
ds.setDatabaseName("database");
ds.setDescription("description");
使用JNDI
1
2
Context ctx = new InitialContext();
ctx.bind("jdbc/sty", ds);  

在学习之前,觉得JNDI到底是什么,其实花点时间,就知道了,道理很简单,反正Java EE容器做了。

获取数据源
1
2
3
4
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/sty");
Connection conn = ds.getConnection("server", "database");

使用DatabaseSource 解决了数据库url的硬编码,当然有很多方式可以解除硬编码,除此之外,DatabaseSource一般会和ConnectionPoolDataSrouce配合食用。类似的,Datasource还和XADataSource一起使用,实现分布式事务。

2.2 部署Pooled DataSource

部署Pooled DataSource比Basic DataSource稍微复杂一些(分布式也是类似),不过都是模版话的配置,学习成本并不高。
之前提到过,Polled DataSource与基本的DataSource是配合使用的,意味着我们需要部署两个类。下面假设我们有两个类,第一个类是我们的池实现类:

1
2
3
class PooledDataSource implements javax.sql.ConnectionPoolDataSource{
    // implements here
}

第二个类如下:

1
2
3
class FastDataSource implements javax.sql.DataSource{
    // adapt ConnectionPoolDataSource here
}

为什么采用这样的方式,其实去看看JDBC的接口就可以了。
下面就是使用它们的时候了,首先我们注册我们的连接池类:

1
2
3
4
5
6
7
8
PooledDataSource pds = new PooledDataSource();
pds.setServerName("pds");
pds.setDatabaseName("database");
pds.setPortNumber(3800);
pds.setDescription("Polled DataSource");
Context ctx = new InitialContext();
ctx.bind("jdbc/pool/datasource", pds);

现在设置我们的另一个类:

1
2
3
4
5
FastDataSource fds = new FastDataSource();
fds.setDescription("produces pooled connections to COFFEEBREAK");
fds.setDataSourceName("jdbc/pool/fastCoffeeDB");
Context ctx = new InitialContext();
ctx.bind("jdbc/fastDatasource", fds);  

使用数据源:

1
2
ctx = new InitialContext();
ds = (DataSource)ctx.lookup("jdbc/fastCoffeeDB");      
2.3 部署分布式事务 DataSource

与池比较类似,我们有两个类:

1
2
3
4
5
6
7
class XATransactionalDataSource implements javax.sql.XADataSource{
    // implements here
}
class TransactionalDataSource implements javax.sql.DataSource{
    // adapt here
}

部署如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
XATransactionalDataSource xads = new XATransactionalDataSource();
xads.setServerName("xads");
xads.setDatabaseName("database");
xads.setPortNumber(9040);
xads.setDescription("Distributed transactions DataSource");
Context ctx = new InitialContext();
ctx.bind("jdbc/xa/xads", xads);
TransactionalDataSource tds = new TransactionalDataSource();
tds.setDescription("suibianla");
tds.setDataSourceName("jdbc/xa/xads");
Context ctx = new InitialContext();
ctx.bind("jdbc/ds", ds);

使用如下:

1
2
3
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/ds");
Connection con = ds.getConnection();   

Statement

按照API的划分,Statement分为三大类:

Statement PreparedStatement CallableStatement

这部分比较简单,再次就不在介绍了,以后有时间的话再来完善。

ResultSet

ResultSet 按照功能被划分为三类,这里直接使用它们的定义介绍了:

TYPE_FORWARD_ONLY:最简单,功能最单一,类似于c++里面的强项迭代器 TYPE_SCROLL_INSENSITIVE:次之,类似于c++里面的双向迭代器 TYPE_SCROLL_SENSITIVE:有双向迭代器的功能,并且和底层数据库保持连接,如果的层数据库发生变化,他会更新内存

按照是否能修改的层数据库划分为两类:

CONCUR_READ_ONLY CONCUR_UPDATABLE

读取ResultSet的时候有有一个概念需要介绍,那就是Cursor,翻译成光标感觉不太好,下文就直接沿用Cursor这个单词,当调用Collection.commit的时候ResultSet对象会自动关闭,有时候我们的需求可能并不是这样,这时候我们需要设置另一个属性,ResultSet提供了这个属性,描述如下:

HOLD_CURSORS_OVER_COMMIT:ResultSet 的cursor不会被关闭。 CLOSE_CURSORS_AT_COMMIT:如果追求性能的话,建议采用这种方式。

Transactions

事务的主要功能是把数据库操作划分成一个单元,这个单元可以看作是原子的,其中事务也有不同的等级划分,这里直接摘抄一个表格:

事务隔离等级 是否会话 读取的脏数据 幂等读取 幻觉的读取
TRANSACTION_NONE 不适用 不适用 不适用 不适用
TRANSACTION_READ_COMMITTED 支持 不允许 允许 允许
TRANSACTION_READ_UNCOMMITTED 支持 允许 允许 允许
TRANSACTION_REPEATABLE_READ 支持 不允许 不允许 允许
TRANSACTION_SERIALIZABLE 支持 不允许 不允许 不允许

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多