前述:
前面我们介绍了Mysql数据库以及SQL语言,我们可以通过命令行或者第三方客户端工具来操作Mysql数据库。
然而,在实际的工作开发过程中,我们是需要整合、关联 java与数据库的,也就是通过 java来访问数据库。
那么,如何实现 java对数据库的访问呢?又是怎么做到 java可以对数据库访问的呢?
-- 让我们先来认识下JDBC,问题便豁然开朗 ...
一、认识JDBC(Java DataBase Connectivity:java数据库连接)
1.1 概述
JDBC是官方(sun公司)定义的一套操作所有关系型数据库的标准接口规范。
我们只需要调用JDBC接口中的方法即可实现访问数据库,但真正操作数据库的是各大数据库厂商根据JDBC接口规范提供的具体实现类,也就是数据库驱动。

- 综上,使用JDBC的好处:
- 程序员如果要开发访问数据库的程序,只需要会调用JDBC接口中的方法即可,不用关注类是如何实现的;
- 使用同一套Java代码,进行少量的修改就可以访问其他JDBC支持的数据库。
1.2 使用JDBC开发使用到的包
| 会使用到的包 | 说明 |
| java.sql | 所有与JDBC访问数据库相关的接口和类 |
| javax.sql | 数据库扩展包,提供数据库额外的功能。如:连接池 |
| 数据库的驱动 | 由各大数据库厂商提供,是对JDBC接口实现的类,需要额外去根据需要下载 |
1.3 JBDC的核心API
| 接口或类 | 作用 |
| DriverManager类 | 1) 管理和注册数据库驱动 2) 得到数据库连接对象 |
| Connection接口 | 一个连接对象,可用于创建Statement 和 PreparedStatement对象 |
| Statement接口 | 一个SQL语句对象,用于将SQL语句发送给数据库服务器 |
| reparedStatement接口 | 一个SQL语句对象,是Statement的子接口 |
| ResultSet接口 | 用于封装数据库查询的结果集,返回给客户端Java程序 |
1.4 java代码实现步骤

1. 导入数据库驱动jar包。如:mysql-connector-java-5.1.37-bin.jar
* 复制mysql-connector-java-5.1.37-bin.jar到项目的lib目录下
* 右键-->Add As Library添加jar包成库
2. 加载和注册数据库驱动。-- 告诉程序该使用哪一个数据库驱动jar包
* Class.forName(数据库驱动实现类) 如:Mysql的数据库驱动实现类 com.mysql.jdbc.Driver
/**
* com.mysql.jdbc.Driver源码
* java.sql.Driver接口,所有数据库厂商必须实现的接口,表示这是一个驱动
*/
public class Driver implements java.sql.Driver {
public Driver() throws sQLException {
}
static {
try {
DriverManager.registerDriver(new Driver()); //注册数据库驱动
}catch (SQLException var1){
throw new RuntimeException ("can't register driver! ");
}
}
}
注意:从JDBC3开始(或mysql5之后驱动),目前已经普遍使用的版本,可以不用注册驱动而直接使用。Class.forName这句话可以省略。
3. 获取数据库连接对象 Connection
* Connection conn = DriverManager.getConnection("jdbc:mysql://ip地址(域名):端口号/数据库名称[?参数名=参数值]", "用户名", "密码");
/** * DriverManager类中的静态方法 * // 通过连接字符串,用户名,密码来得到数据库的连接对象 * Connection getConnection (String url,String user, String password) * // 通过连接字符串,属性对象来得到连接对象 * Connection getConnection (String url,Properties info) */ /** Connection接口:数据库连接对象 功能: 1. 获取执行sql的对象 * Statement createStatement() * PreparedStatement prepareStatement(String sql) 2. 管理事务: * 开启事务:setAutoCommit(boolean autoCommit) //调用该方法设置参数为false,即开启事务 * 提交事务:commit() * 回滚事务:rollback() */
注意:
- 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称[?参数名=参数值]
- 不同的数据库连接的URL地址是不同的(如conn获取的就说mysql的地址对象),通用地址格式:
- 协议名:子协议:l服务器名或IP地址:端口号/数据库名[?参数=参数值]
- [?参数=参数值]:比如设置编码格式?characterEncoding=utf8
4. 定义sql语句
5. 获取执行sql语句的对象 Statement
* Statement stmt = conn.createStatement();
/**
* PreparedStatement:执行sql的对象
* 1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全性问题;
* 2. 解决SQL注入问题:使用PreparedStatement对象来解决;
* 3. 预编译的SQL:参数使用?作为占位符;
* 4. 给占位符?赋值
* 获取执行SQL的对象:
* PreparedStatement ps = Connection.prepareStatement(String sql)
* 方法: ps.setXxx(参数1,参数2)
* * 参数1:?的位置编号 从1 开始
* * 参数2:?的值
*
* Statement:用于发送SQL语句给服务器,获取执行SQL的对象
* Statement接口中的方法:
* 1. boolean execute(String sql):可以执行任意的sql(了解)
* //返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
* 2. int executeUpdate(String sql):执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
* //返回值:查询的结果集。
* 3. ResultSet executeQuery(String sql):执行DQL(select)语句
*
* ResultSet:结果集对象,封装查询结果
* 作用:用于遍历结果集,获取每一条数据记录
* 接口中的方法:
* boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
* getXxx(参数):获取数据
* 1. Xxx:代表数据类型 如:int getInt(), String getString()
* 2. 参数
* int:代表列的编号,从1开始。 如: getString(1)
* String:代表列名称。 如: getDouble("balance")
*/
6. 执行sql,接受返回结果(stmt.方法)
7. 处理结果
8. 释放资源 //释放资源一般写在finally代码块中,并需要判断对象是否为null
小贴士:PreparedStatement是Statement接口的子接口,继承于父接口中的所有方法,后期都会使用PreparedStatement来完成增删改查的所有操作
原因:① 可以有效防止SQL注入的问题,效率更高;
② 因为有预先编译的功能,SQL的执行效率更高。
1.5 常用数据类型转换表
| SQL类型 | JDBC对应方法 | 返回类型 |
| BIT(1) bit(n) | getBoolean() | boolean |
| TINYINT | getByte() | byte |
| SMALLINT | getShort() | short |
| INT | getlnt() | int |
| BIGINT | getLong() | long |
| CHAR,VARCHAR | getString() | String |
| Text(Clob) Blob | getClob getBlob() | Clob Blob |
| DATE | getDate() | java.sql.Date 只代表日期 |
| TIME | getTime() | java.sql.Timestamp同时有日期和时间 |
| TIMESTAMP | getTimestamp() | java.sql.Timestamp同时有日期和时间 |
- java.sql.Date、Time、Timestamp(时间戳),三个共同父类是:java.util.Date
二、抽取JDBC工具类
如果一个功能经常要用到,我们建议把这个功能做成一个工具类,可以在不同的地方重用。
JDBC就符合这样的要求,我们可以把一些共用的代码抽取出来,并通过获取配置文件资源的方式来让代码更具可重用性、可读性、可操作性。
- JDBCUtils工具类
抽取目的:简化书写,让代码更具可重用性、可读性、可操作性。
抽取分析:
- 抽取注册驱动;
- 抽取一个方法获取连接对象;
* 需求:不想传递参数(麻烦),还得保证工具类的通用性。
* 解决:配置文件
jdbc.properties
url=
user=
password=
driver=
3. 抽取一个方法释放资源。
代码实现:
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
/**
* 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块。
*/
static{
//读取资源文件,获取值。
try {
//1. 创建Properties集合类。
Properties pro = new Properties();
//获取src路径下的文件的方式--->ClassLoader 类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
//2. 加载文件
pro.load(new FileReader(path));
//3. 获取数据,赋值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//4. 注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return 连接对象
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
/**
* 释放资源
* @param stmt
* @param conn
*/
public static void closeSC(Statement stmt, Connection conn){
if( stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 释放资源
* @param stmt
* @param conn
*/
public static void closeRSC(ResultSet rs, Statement stmt, Connection conn){
if( rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
三、JDBC操作事务
之前我们已经使用Mysql的命令来操作事务,那么现在认识了JDBC后,如何通过JDBC来操作事务呢?
1.1 通过Connection对象来管理事务
Connection接口中有与事务相关的方法,可以通过这些方法来操作管理事务。
| 相关方法 | 操作 |
| void setAutoCommit(boolean autoCommit) | 调用该方法设置参数为false,表示关闭自动提交,即开启事务 |
| void commit() | 提交事务 |
| void rollback() | 回滚事务 |
1.2 开发步骤
- 获取连接:Connection conn = JDBCUtils.getConnection();
- 开启事务:conn.setAutoCommit(false);
- 获取执行sql对象:conn.prepareStatement(sql);
- 执行sql,返回结果;
- 提交事务/回滚事务;
- 关闭资源。
1.3 代码实现
public class JDBCAutoCommit {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
//1.获取连接
conn = JDBCUtils.getConnection();
//2.开启事务
conn.setAutoCommit(false);
//3.定义sql
String sql1 = "... ...";
String sql2 = "... ...";
//4.获取执行sql对象
pstmt1 = conn.prepareStatement(sql1);
pstmt2 = conn.prepareStatement(sql2);
//5.设置参数
... ...
//6.执行sql
pstmt1.executeUpdate();
// 手动制造异常
int i = 3/0;
pstmt2.executeUpdate();
//7.提交事务
conn.commit();
} catch (Exception e) {
try {
if(conn != null) {
//8.事务回滚
conn.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
//9.关闭资源
JDBCUtils.closeSC(pstmt1,conn);
JDBCUtils.closeSC(pstmt2,null);
}
}
}