JDBC
JDBC简介
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
我们安装好数据库之后,我们的应用程序也是不能直接使用数据库的,必须要通过相应的数据库驱动程序,通过驱动程序去和数据库打交道。其实也就是数据库厂商的JDBC接口实现,即对Connection等接口的实现类的jar文件。
JDBC + Oracle + Eclipse
简介
我们安装的 XE 版本里面就有自带的 Oracle 的官方 JDBC jar 包,位置是:app\oracle\product\11.2.0\server\jdbc\lib
有三个
- ojdbc5:与jdk1.5 对应的
- ojdbc6:与jdk1.6 对应的
- ojdbc6_g:jdk1.6 的编译版本
我们随便选择一个就可以了,文档jdk是11 ,Oracle 是之前有上传过资源 11g XE 版本的
外部JAR包加载到我们项目
-
在我们的Java 项目下面建立一个文件夹 放入这些外部 jar 包 一般文件名是lib【与src同级】
-
然后在右键项目名,选择Build Path,如图选择
-
选择 labiries – 》 ModulePath — 》 Add JARS 选择你创建的lib下面的jar包 —》 应用 确定关闭
-
然后就能看到 lib 同级目录下有个 Referenced Libraries【应用库】 这样就把jdbc引入到你的库里面了
认识结构
这个Jar包下面全是和数据库有关的类,接口等。它和Java.sql 以及 Javax.sql 三者一起来操作数据库 ,这个JDBC 就是一个 java程序操作数据库的中间件,也叫做JDBC驱动
Java程序借助JDBC连接数据库
Java API
JDBC API主要位于JDK中的java.sql包中(之后扩展的内容位于javax.sql包中),主要包括(斜体代表接口,需驱动程序提供者来具体实现):
- DriverManager:负责加载各种不同驱动程序(Driver),并根据不同的请求,向调用者返回相应的数据库连接(Connection)。
- Driver:驱动程序,会将自身加载到DriverManager中去,并处理相应的请求并返回相应的数据库连接(Connection)。
- Connection:数据库连接,负责与进行数据库间通讯,SQL执行以及事务处理都是在某个特定Connection环境中进行的。可以产生用以执行SQL的Statement。
- Statement:用以执行SQL查询和更新(针对静态SQL语句和单次执行)。
- PreparedStatement:用以执行包含动态参数的SQL查询和更新(在服务器端编译,允许重复执行以提高效率)。
- CallableStatement:用以调用数据库中的存储过程。
- SQLException:代表在数据库连接的建立和关闭和SQL语句的执行过程中发生了例外情况(即错误)。
步骤
1.加载数据库驱动
在编程中要连接数据库,必须先装载特定厂商的数据库驱动程序,不同的数据库有不同的装载方法。如:
-
装载MySql驱动:Class.forName(“com.mysql.jdbc.Driver”);
-
装载Oracle驱动:Class.forName(“oracle.jdbc.driver.OracleDriver”);
2.创建数据库连接:Connection接口
创建数据库连接要用该接口来操作
Connection conn = DriverManager.getConnection(String url,String username,String userpasswd);
- DriverManager类下面的方法
getConnection()
会返回一个Connection
数据库连接对象,它的参数不固定,最常用d就是这三个 - url:数据库服务的地址一般都是固定写法
- Oracle:
jdbc:oracle:thin:@ip地址:端口号(1521):XE
- MySql:
jdbc:mysql://ip地址:端口号(3306)/数据库
【好像5.7之后 8.0 需要写时区】jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC
- SqlServer:
jdbc:microsoft:sqlserver://ip地址:端口号;DatabaseName = databasename
- Oracle:
- username:连接的数据库用户
- userpasswd:数据库用户密码
3.创建sql执行器:Statement 接口
Statement st = conn.createStatement();
4.执行sql
5.处理返回的结果集或者别的操作
有两个常用方法,excuteQuery() 和 excuteUpdata() ,第一个返回结果集,用的是查询sql语句,第二个用增、删、改 的更新语句, 返回整型数据, 大于0则执行成功,否则失败。
一般如果是查询的话返回的都是结果集 ResultSet
,后面有详细介绍。有个 next()
方法,返回值是 布尔类型 ,用它去取数据。
6.释放数据库连接资源
释放数据库连接的时候按照先入栈后出栈的顺序去写,然后每个关闭的时候都会有异常,而且还要去做非空判断,不然容易报空指针异常错误。
举例
package com.bigdata.jdbcdemo.oracle;
import java.sql.*;
public class demoSelect {
public static void main(String[] args) {
/**
* 加载驱动
* 创建连接
* 建立Statement sql执行对象
* 执行sql
* 处理返回结果
* 释放数据库资源
*/
// 先声明 最后关闭的时候好关闭
Connection conn = null;
Statement ste = null;
ResultSet rs = null;
try {
// 类找不到异常
Class.forName("oracle.jdbc.OracleDriver");
// sql异常
conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:XE", "SCOTT", "lzyft1030");
ste = conn.createStatement();
String sql = "SELECT ENAME,JOB,SAL FROM EMP";
rs = ste.executeQuery(sql);
System.out.println("姓名\t工作\t工资");
while (rs.next()) {
System.out.println(rs.getString("ENAME")+"\t"+rs.getString("JOB")+"\t"+rs.getInt(3));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 做不为null判断 防止NPE【NullPointerException】
try {
if (ste != null) {
ste.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
常用接口
Connection接口
Class.forName("oracle.jdbc.OracleDriver");
Connection conn = DriverManager.getConnection(...);
Statement接口
用于执行静态SQL语句并返回它所生成结果的对象。
三种Statement类:
Statement:
由createStatement
创建,用于发送简单的SQL语句(不带参数的Sql,可以做Sql组合)。
Statement st = conn.createStatement();
String sql = "delete from tablename where id = "5" + "..." "; // 不能有占位符 ?可以组合 所以安全性不高 字符串组合的话 网上改一下字符串或者后面跟别的东西 直接坏起来
int code = st.excuteUpdate(sql);
ResultSet rst = st.excuteQuery(sql);
PreparedStatement :
继承自Statement
接口,由prepareStatement
创建,用于发送含有一个或多个参数【占位符】的SQL语句。PreparedStatement
对象比Statement
对象的效率更高,并且可以防止SQL注入,所以我们一般都使用PreparedStatement
。
【注意接口和创建方法之间的不同:PreparedStatement pst = conn.prepareStatement(sql);
】
CallableStatement:
继承自PreparedStatement
接口,由方法prepareCall
创建,用于调用存储过程。
常用Statement方法:
execute(String sql)
:运行语句,返回是否有结果集executeQuery(String sql)
:运行select语句,返回ResultSet
结果集。executeUpdate(String sql)
:运行insert/update/delete
操作,返回更新的行数。addBatch(String sql)
:把多条sql语句放到一个批处理中。executeBatch()
:向数据库发送一批sql语句执行。
ResultSet接口
ResultSet提供检索不同类型字段的方法,常用的有:
getString(int index)、getString(String columnName)
:获得在数据库里是varchar、char等类型的数据对象。getFloat(int index)、getFloat(String columnName)
:获得在数据库里是Float类型的数据对象。getDate(int index)、getDate(String columnName)
:获得在数据库里是Date类型的数据。getBoolean(int index)、getBoolean(String columnName)
:获得在数据库里是布尔类型的数据getObject(int index)、getObject(String columnName)
:获取在数据库里任意类型的数据。
ResultSet还提供了对结果集进行滚动的方法:
next()
:移动到下一行,返回布尔值previous()
:移动到前一行absolute(int row)
:移动到指定行beforeFirst()
:移动resultSet的最前面。afterLast()
:移动到resultSet的最后面。
ResultSetMetaData
用于返回结果集的元数据,ResultSet 的子类,一般方法原型都是ResultSet 的 ,使用的时候可以查看API 去使用
举例
连接和关闭数据库的工具类
package com.bigdata.jdbcdemo.oracle;
import java.sql.*;
public class DBConnection {
private static Connection conn = null;
/**
* 创建Oracle 数据库连接
*/
public static Connection getConnectOracle(){
try {
Class.forName("oracle.jdbc.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:XE","SCOTT","123");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 释放资源
*/
public static void closeAll(ResultSet rst, PreparedStatement pst, Connection conn) {
try {
if (rst != null) {
rst.close();
}
if (pst != null) {
pst.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
具体练习
package com.bigdata.jdbcdemo.oracle;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
public class PreparedStatementTest {
public static void main(String[] args) {
PreparedStatement pst = null;
ResultSet rst = null;
ResultSetMetaData rstmd = null;
Connection conn = DBConnection.getConnectOracle();
String sql = "select ename,job,sal from emp where deptno = ?";
try {
pst = conn.prepareStatement(sql);
pst.setInt(1, 10);
rst = pst.executeQuery();
while (rst.next()) {
System.out.println(rst.getString(1)+"\t"+rst.getString("JOB")+"\t"+rst.getInt(3));
}
rstmd = rst.getMetaData();
System.out.println("列数:"+rstmd.getColumnCount());
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBConnection.closeAll(rst, pst, conn);
}
}
}
Sql 到 Java 数据类型映射
SQL类型 | Java类型 |
---|---|
CHAR | java.lang.String |
VARCHAR | java.lang.String |
LONGVARCHAR | java.lang.String |
NUMERIC | java.math.BigDecimal |
DECIMAL | java.math.BigDecimal |
BIT | boolean |
TINYINT | byte |
SMALLINT | short |
INTEGER | int |
BIGINT | long |
REAL | float |
FLOAT | double |
DOUBLE | double |
BINARY | byte[] |
VARBINARY | byte[] |
LONGVARBINARY | byte[] |
DATE | java.sql.Date |
TIME | java.sql.Time |
TIMESTAMP | java.sql.Timestamp |
BLOB | java.sql.Blob |
CLOB | java.sql.Clob |
Array | java.sql.Array |
REF | java.sql.Ref |
Struct | java.sql.Struct |
注:这种类型匹配不是强制性标准,特定的JDBC厂商可能会改变这种类型匹配。例如Oracle中的DATE类型是包含时分秒,而java.sql.Date仅仅支持年月日。
Date转换
java.sql.Date
Date d = new Date(1900 + year, 1+month, day);
- int类型的参数
PreParedStatement()
中的 sql 的 Date 类型 不可直接 to_date() 需要用这个 Date 对象去传入
Oracle 的类型 Date
to_date(日期字符串,'格式');
:按格式 字符串转日期to_char(date,'格式');
:日期转字符串按格式add_month(date,正负数字);
:加间日期月份last_day(date);
:日期的最后一条date + interval ‘正负数字’ year/month(数字位数,默认2位)
:给日期按后面的year 或 month 加减数字【±】
用配置文件连接数据库
创建一个文件
创建文件,最好放在同连接数据库的类同级目录下,一般文件命名:date.properties
,格式要写成固定的
classDriver = oracle.jdbc.OracleDriver
url = jdbc:oracle:thin:@127.0.0.1:1521:XE
username = scott
userpasswd = 123
创建类
java.util
下面有个键值对集合,Hashtable的子类 Preperties
用InputStream
对象读取文件数据
InputStream is = 当前类名.class.getResourceAsStream("data.properties");
Prepareties p = new Prepareties();
p.load(is);
p.getProperty(key);// 取得键值
示例代码
package com.bigdata.jdbcdemo.oracle;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class DBConnectByFile {
// 输入流读取配置文件 用当前类取得资源流 参数是配置文件的相对路径
private static InputStream is = DBConnectByFile.class.getResourceAsStream("oracleConn.properties");
private static Properties properties = new Properties();
/**
* @return 返回驱动
*/
public static String getDriverClass() {
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
return properties.getProperty("classDriver");
}
/**
* @return 返回url
*/
public static String getUrl() {
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
return properties.getProperty("url");
}
/**
* @return username
*/
public static String getUserName() {
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
return properties.getProperty("username");
}
/**
* @return password
*/
public static String getPassword() {
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
return properties.getProperty("password");
}
public static Connection getConnection () {
Connection conn = null;
try {
Class.forName(getDriverClass());
conn = DriverManager.getConnection(getUrl(), getUserName(), getPassword());
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void closeAll(ResultSet rst, PreparedStatement pst, Connection conn) {
try {
if (rst != null) {
rst.close();
}
if (pst != null) {
pst.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// public static void main(String[] args) {
// Connection conn = getConnection();
// System.out.println(conn != null);
// }
}
rst.close();
}
if (pst != null) {
pst.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// public static void main(String[] args) {
// Connection conn = getConnection();
// System.out.println(conn != null);
// }
}