JDBC 基本操作
- JDBC(Java DataBase Connectivity) 是有一些接口和类构成的API
- JDBC是J2SE的一部分, 又java.sql; javax.sql包组成。
- 应用程序层 是有我们开发人员开发的代码
- JDBC层 - 主要是一些接口, 定义了一个规则, 定义了一些方法, 没有实现。
- Driver - Driver就是各个产商实现JDBC接口所以开发的jar包。 Driver一般是由各个数据库产商开发的。
- 注册驱动(只做一次)
- 建立连接(Connection)
- 创建执行SQL语句(Statement, PreStatement)
- 执行语句
- 处理执行结果(ResultSet)
- 释放资源
一、DriverManager.registerDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
jdbc是使用桥的模式进行连接的 在编译时需要导入对应的libDriverManager就是管理数据库驱动的一个类,java.sql.Driver就是一个提供注册数据库驱动的接口,而com.microsoft.sqlserver.jdbc.SQLServerDriver()是java.sql.Driver接口的一个具体实现。
二、System.setProperty("jdbc.drivers", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
通过系统的属性设置注册驱动 如果要注册多个驱动, 则把驱动用冒号分隔,在连接时JDBC会按顺序搜索,直到找到第一个能成功连接指定URL的驱动程序。
System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver:com.oracle.jdbc.Driver");为什么直接设置一个系统属性就可以了呢?这是因为在DriverManager内的内部会有一个方法去获取这个值, 如果有 那么就使用这种方法, 如果没有就继续使用其他的方法 比如第一种 或者第三种。
第一种与第二种注册的方法看起来更加的直接与好理解。第三种方法是通过Class把类先装载到java的虚拟机中,并没有创建Driver类的实例。第二种与第三种方法可以脱离jdbc的驱动进行编译,第一种方法不可以的,它一定要有jdbc的驱动才可以通过编译,这样对我们的程序就有很多的不好之处,为程序换数据库会带来麻烦。我们通过Driver类的源码可以了解到,Driver类中就有一个静态的代码块,只要我们执行了Driver类中的静态代码块,并把驱动的实例放入到Drivers的一个数组列表中,我们再调用方法registerDrever就相当于又向drivers列表中放了一次driver驱动,虽然这并不影响我们程序,但是这样做实在是没有必要,还会影响程序的运行。所以推荐使用第三种方法来注册驱动。第三中的好处在于能够在编译时不依赖于特定的JDBC Driver库,也就是减少了项目代码的依赖性,而且也很容易改造成从配置文件读取JDBC配置,从而可以在运行时动态更换数据库连接驱动。
//创建连接String url = "jdbc:mysql://localhost:3306/jdbc";String user = "root";String password = "";Connection conn = DriverManager.getConnection(url, user, password);
JDBC:子协议:子名称//主机名:端口/数据库名称?属性名=属性值&属性名2=属性值2&...
mysql的url: jdbc:mysql://localhost:3306/jdbc (没有子协议)
jdbc:mysql:///jdbc
useUnicode=true&characterEncoding=GBK
//创建SQL语句
//执行SQL语句并接受返回的数据 返回的数据是一种类似二维数组的结果
String exeSql = "SELECT CAPEX_MTRC, CAPEX_REGN FROM USER";
//建议sql不要选取表中所有的行, 只需选中需要的行就可以了
ResultSet rs = st.executeQuery(exeSql);
2.4 处理执行结果(ResultSet)
//处理执行结果while(rs.next()){System.out.println(rs.getString(CAPEX_MTRC) + "\t" + rs.getString(CAPEX_REGN ) + "\r" +rs.getObject(3));}rs.next() 会定位到当前的一行数据, 然后通过getObject(index)来获取指定列的值。 rs.next()每次都会移到的下一行数据
rs.close();st.close();conn.close();数据库连接Connection是非常稀缺的资源, 用完后必须马上释放, 如果Connection不能及时正确的关闭将导致系统宕机。 Connection的使用原则是尽量晚创建, 尽量早释放。
Create/update/delete 要使用Statement的executeUpdate(sql)方法 , 它返回的是被影响的行数。
- 没有sql注入问题
- Statement会是数据库频繁编译SQL, 可能造成数据库缓冲区溢出。
- 数据库和驱动可以对PreparedStatement进行优化(只有在相关联的数据库连接没有关闭的情况下有效)
推荐使用列名: select BUD_FISC_YR_NM, BUD_PER_NM, BUD_YR_MTH_NR, ESDW_CRT_TS from CORE.BUD_RT;
不推荐使用*: select * from CORE.BUD_RT;
3. ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
返回的结果集对数据库中的的数据变动是不敏感的。可以这么认为,当拿到结果集时,已经把数据库库中满足条件的所有记录都取了出来,放在缓存中,如果此时有另一个线程将数据库中的数据更改了,也不会影响这个结果集中的数据,因为它用的是缓存中的。
ResultSet.TYPE_SCROLL_SENSITIVE
与此对应,它返回的结果集是敏感的,那么是不是意味着拿到结果集后,数据库中的数据变化都会反映到结果集中呢?不是这样的,这里此时拿到的结果集只是某种条件的记录的id,当打印结果集中数据的时候,根据id再临时到数据库中取,那么对于拿到结果集后,数据库中的数据被更新了(update),肯定是会被反映到结果集上的,但是对于插入(insert)操作,由于新插入的记录的id并没有被结果集缓存,所以不会反映到结果集中,对于删除操作(delete),因为数据库中的删除操作只是对被删除的记录做一个标记,使之不被被检索到,实际的数据并没有被删除,而实际缓存的 是id的实际偏移,所以删除操作也不会被反映到结果集上。
package com.jdbc.base;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
publicclass CRUD{
publicstaticvoid main(String[] args) throws ClassNotFoundException, SQLException
{
create();
find();
delete();
System.out.println("------------------after deleted----------------------------");
find();
}
staticvoid create() throws ClassNotFoundException, SQLException{
String url = "jdbc:vertica://shr3-vrt-dev.houston.hp.com:5433/shr3_vrt_dev";
String userName = "srvc_esdw_etl_dev";
String password = "but.han.545!";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Class.forName("com.vertica.jdbc.Driver");
conn = DriverManager.getConnection(url, userName, password);
String sql = "insert into CORE.BUD_RT (BUD_FISC_YR_NM, BUD_PER_NM, ESDW_CRT_TS) values ('2021' ,'Current', '2016-01-23 03:08:22')";
ps = conn.prepareStatement(sql);
ps.executeUpdate();
//rs.close();
ps.close();
conn.close();
}
staticvoid find() throws ClassNotFoundException, SQLException{
String url = "jdbc:vertica://shr3-vrt-dev.houston.hp.com:5433/shr3_vrt_dev";
String userName = "srvc_esdw_etl_dev";
String password = "but.han.545!";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Class.forName("com.vertica.jdbc.Driver");
conn = DriverManager.getConnection(url, userName, password);
String sql = "select BUD_FISC_YR_NM, BUD_PER_NM, BUD_YR_MTH_NR, ESDW_CRT_TS from CORE.BUD_RT";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("BUD_FISC_YR_NM") + "\t" + rs.getString("BUD_YR_MTH_NR") + "\t" + rs.getTimestamp("ESDW_CRT_TS"));
}
rs.close();
ps.close();
conn.close();
}
staticvoid delete() throws SQLException, ClassNotFoundException{
String url = "jdbc:vertica://shr3-vrt-dev.houston.hp.com:5433/shr3_vrt_dev";
String userName = "srvc_esdw_etl_dev";
String password = "but.han.545!";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Class.forName("com.vertica.jdbc.Driver");
conn = DriverManager.getConnection(url, userName, password);
String sql = "delete from CORE.BUD_RT where BUD_FISC_YR_NM in('2018', '2021')";
ps = conn.prepareStatement(sql);
intcount = ps.executeUpdate();
System.out.println(count + " records are deleted.");
//rs.close();
ps.close();
conn.close();
}
}
上面例子可以运行成功, 但是呢 它有很多问题:
1. 代码的冗余 有很多重复的代码
2. 如果连接数据库的用户名 密码改了, 上面方法都要改动
3. 注册驱动只需要注册一次就行了, 但是上面个每个方法都会注册一次。
解决方法: 使用工具类来执行一些公用的方法
package com.jdbc.base;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//这个工具类,不需要继承所以定义出 final。 当然也可以不定义成final 这样别人可能会在你的代码的基础做一步的修改
//同样,也不需要创建对象,所以构造函数私有 不会创建对象
publicfinalclass JdbcUtils {
//用户名,密码 URL 也需要提取出来,这样如果密码发生了改变,只需要改这一个地方就可以了
//而且一般不需要被人来直接使用这些变量,定义出私有的保护起来而且对以后的演化会很好,
privatestatic String url = "jdbc:vertica://shr3-vrt-dev.houston.hp.com:5433/shr3_vrt_dev";
privatestatic String userName = "srvc_esdw_etl_dev";
privatestatic String password = "but.han.545!";
private JdbcUtils() {
}
//z注册驱动只需要一次就可以了,不然数据库每次操作都注册一次会很浪费资源,所以把注册驱动放到工具类中
//静态代码块只会在类被装载到虚拟时执行一次,所以这个很适合装载驱动
//这个已经不能在在工具类中处理,需要抛出去,让上层处理
static{
try {
Class.forName("com.vertica.jdbc.Driver");
} catch (ClassNotFoundException e) {
thrownew ExceptionInInitializerError(e);
}
}
/*catch (ClassNotFoundException e) {
// Could not find the driver class. Likely an issue
// with finding the .jar file.
System.out.println("Could not find the JDBC driver class.");
e.printStackTrace();
return; // Exit. Cannot do anything further.
}*/
//创建连接也可以放到工具类这样 这样以后每次获取连接的时候都通过工具类来获取
//且参数是私有的,所以放到工具来中最好
publicstatic Connection getConnection() throws SQLException{
return DriverManager.getConnection(url, userName, password);
}
// 释放资源也可以放到工具类中
publicstaticvoid free(ResultSet rs, Statement st, Connection conn)
{
try{
if (rs != null)
rs.close();
} catch(SQLException e){
e.printStackTrace();
} finally {
try{
if (st != null)
st.close();
} catch(SQLException e){
e.printStackTrace();
} finally {
if(conn != null)
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
使用JdbcUtils类修改CRUD代码
package com.jdbc.base;
importjava.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
publicclass CRUD {
publicstaticvoid main(String[] args) throws SQLException {
read();
}
staticvoid create() throws SQLException {
Connectionconn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "insert into CORE.BUD_RT (BUD_FISC_YR_NM, BUD_PER_NM, ESDW_CRT_TS) values ('2021' ,'Current', '2016-01-23 03:08:22')";
intcount = st.executeUpdate(sql);
System.out.println(count + " records inserted into table.");
} finally {
JdbcUtils.free(rs, st, conn);
}
}
stati cvoid delete() throws SQLException {
Connectionconn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "delete from CORE.BUD_RT where BUD_FISC_YR_NM = 2020";
intcount = st.executeUpdate(sql);
System.out.println(count + " records deleted.");
} finally {
JdbcUtils.free(rs, st, conn);
}
}
staticvoid update() throws SQLException {
Connectionconn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "update CORE.BUD_RT set BUD_PER_NM = 'test' where BUD_FISC_YR_NM = '2014'";
intcount = st.executeUpdate(sql);
System.out.println(count + " records updated.");
} finally {
JdbcUtils.free(rs, st, conn);
}
}
staticvoid read() throws SQLException {
Connectionconn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select BUD_FISC_YR_NM, BUD_PER_NM, BUD_YR_MTH_NR, ESDW_CRT_TS from CORE.BUD_RT";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("BUD_FISC_YR_NM") + "\t" + rs.getString("BUD_PER_NM") + "\t"
+ rs.getInt("BUD_YR_MTH_NR")+ "\t" + rs.getDate("ESDW_CRT_TS"));
}
} finally {
JdbcUtils.free(rs, ps, conn);
}
}
}
这个时候类看起来就好多了。 但实际上任然有很多地方需要进一步优化。
JDBC 基本操作的更多相关文章
- JDBC基本操作
前言:什么是JDBC 维基百科的简介: Java 数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提 ...
- Java学习路线教程之JDBC基本操作
为了帮助大家熟练应用JDBC编程,接下来,在本节将通过一个综合案例来讲解JDBC的基本操作,确保大家能够深刻理解JDBC的增.删.改.查,灵活利用JDBC完成对数据库的各项操作. 1. 创建一个Jav ...
- 10.1(java学习笔记)JDBC基本操作(连接,执行SQL语句,获取结果集)
一.JDBC JDBC的全称是java database connection java数据库连接. 在java中需要对数据库进行一系列的操作,这时就需要使用JDBC. sun公司制定了关于数据库操作 ...
- Spring学习记录(十四)---JDBC基本操作
先看一些定义: 在Spring JDBC模块中,所有的类可以被分到四个单独的包:1.core即核心包,它包含了JDBC的核心功能.此包内有很多重要的类,包括:JdbcTemplate类.SimpleJ ...
- JDBC 基本操作: CRUD
Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可. Statement对象的executeUpdate方法,用于向 ...
- JDBC基本操作示例
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import ...
- JDBC基本操作介绍
一 .JDBC主要的API介绍 JDBC为开发人员提供了一套标准的API,都是由JAVA语言编写的类和接口.用于连接数据库和执行SQL语句.JDBC也是JAVA核心类库的一部分,位于Java.sql包 ...
- 通过JDBC进行简单的增删改查(以MySQL为例)
目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操作 (1)定义记录的类(可选) (2)连接的获取 ( ...
- 【转载】通过JDBC对MySQL数据库的增删改查
通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操 ...
随机推荐
- Boom.TV完成350万美元融资,目标直指VR电竞直播
3D在线电竞直播平台Boom.tv刚刚宣布已经完成350万美元的融资,该平台旨在让观众在任何设备以任意视角观看电竞比赛,并将支持VR版本. 这家位于美国加州红木城的初创公司成立于2015年,由Gupt ...
- QWord2vec:word2vec移植版+GUI
序 Word2Vec原生是不支持Windows的,索性就用Qt移植了一下. 大概做了下面几件事. ①替换LinuxAPI的pthread为QThread. ②取消了posix_memalign(),内 ...
- TYVJ P1103 多项式输出 Label:模拟 有点儿坑
描述 一元 n 次多项式可用如下的表达式表示: f(x)=an*x^n+an-1*x^n-1+...+a1*x+a0,an<>0其中,ai*a^x 称为i次项,ai称为i次项的系数.给出 ...
- 4分钟apache自带ab压力测试工具使用: 2015.10.4
2015.10.44分钟apache自带ab压力测试工具使用:win8.1 wampserver2.5 -Apache-2.4.9-Mysql-5.6.17-php5.5.12-64b 可以参考一下部 ...
- NOI 题库 2753
2753 走迷宫 描述 一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走:有的格子是空地,可以走.给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到).只能在水平方向或垂直 ...
- JSON value
JSON values can be: A number (integer or floating point) A string (in double quotes) A Boolean (true ...
- javaweb之框架标签(day1 框架标签的使用)
框架标签 <frameset> --rows:按照行进行划分<frameset rows='80,*'> --rows:按照列进行划分<frameset cols='80 ...
- 延迟加载图片插件LazyLoad.js的使用方法
我们常常会见到很多网页的图片并不是一打开页面就全部加载的,而是浏览到当前的图片位置才显示出来.这是怎么实现出来的呢? 其实这就是目前较为流行的“延迟加载”(Lazy Load)技术,灵感来自Matt ...
- 李洪强iOS经典面试题130
绘图与动画 CAAnimation的层级结构 CAPropertyAnimation是CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类:CABasicAnimatio ...
- ubuntu su Authentication failure
这个问题产生的原因是由于ubtun系统默认是没有激活root用户的,需要我们手工进行操作,在命令行界面下,或者在终端中输入如下命令: sudo passwd Password:你当前的密码 Enter ...