今日新篇章
【JDBC】
【主要内容】
-
JDBC概述
-
使用JDBC完成添加操作
-
使用JDBC完成更新和删除
-
DBUtils的简单封装
-
使用JDBC完成查询
-
使用JDBC完成分页查询
-
常用接口详解
-
JDBC批处理
-
SQL注入问题
-
事务处理解决转账问题
-
连接池
-
使用反射对DBUtils再次的封装
-
BaseDAO的封装
【学习目标】
1. JDBC概述
1.1 什么是JDBC
JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。
1.2 JDBC的原理
早期SUN公司的天才们想编写一套可以连接天下所有数据库的API,但是当他们刚刚开始时就发现这是不可完成的任务,因为各个厂商的数据库服务器差异太大了。后来SUN开始与数据库厂商们讨论,最终得出的结论是,由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动!
JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。
当然还有第三方公司专门为某一数据库提供驱动,这样的驱动往往不是开源免费的!
1.3 程序员,JDBC,JDBC驱动的关系及说明
1.3.1 JDBC API
提供者:Sun公司
内容:供程序员调用的接口与类,集成在java.sql和javax.sql包中,如
DriverManager类 作用:管理各种不同的JDBC驱动
Connection接口
Statement接口
ResultSet接口
1.3.2 JDBC 驱动
提供者:数据库厂商
作用:负责连接各种不同的数据库
1.3.3 Java程序员
JDBC对Java程序员而言是API,对实现与数据库连接的服务提供商而言是接口模型。
1.3.4 三方关系
SUN公司是规范制定者,制定了规范JDBC(连接数据库规范)
数据库厂商微软、甲骨文等分别提供实现JDBC接口的驱动jar包
程序员学习JDBC规范来应用这些jar包里的类。
1.4 总结
简单地说,JDBC 可做三件事:与数据库建立连接、发送 操作数据库的语句并处理结果。
DriverManager :依据数据库的不同,管理JDBC驱动
Connection :负责连接数据库并担任传送数据的任务
Statement :由 Connection 产生、负责发送执行SQL语句
ResultSet:负责保存Statement执行后所产生的查询结果
2. JDBC操作数据库的步骤
2.1 总体步骤
-
加载一个Driver驱动
-
创建数据库连接(Connection)
-
创建SQL命令发送器Statement
-
创建SQL
-
通过Statement发送SQL命令并得到结果
-
处理SQL结果(select语句)
-
关闭数据库资源
ResultSet
Statement
Connection
2.2 详细步骤
2.2.1 加载驱动
加载JDBC驱动是通过调用方法java.lang.Class.forName(),下面列出常用的几种数据库驱动程序加载语句的形式 :
Class.forName("oracle.JDBC.driver.OracleDriver");//使用Oracle的JDBC驱动程序
Class.forName("com.microsoft.JDBC.sqlserver.SQLServerDriver");//使用SQL Server的JDBC驱动程序
Class.forName("com.ibm.db2.JDBC.app.DB2Driver");//使用DB2的JDBC驱动程序
Class.forName("com.mysql.jdbc.Driver");//使用MySql的JDBC驱动程序
2.2.2 创建数据库连接
与数据库建立连接的方法是调用DriverManager.getConnection(String url, String user, String password )方法
Connection conn=null;
String url="jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&charsetUnicode=UTF8";
String user="root";
String password="123456";
conn = DriverManager.getConnection(url, user, password);
2.2.3 创建Statement并发送命令
Statement对象用于将 SQL 语句发送到数据库中,或者理解为执行sql语句
有三种 Statement对象:
Statement:用于执行不带参数的简单SQL语句;
PreparedStatement(从 Statement 继承):用于执行带或不带参数的预编译SQL语句;
CallableStatement(从PreparedStatement 继承):用于执行数据库存储过程的调用。
2.2.4 处理ResultSet结果
ResultSet对象是executeQuery()方法的返回值,它被称为结果集,它代表符合SQL语句条件的所有行,并且它通过一套getXXX方法(这些get方法可以访问当前行中的不同列)提供了对这些行中数据的访问。
ResultSet里的数据一行一行排列,每行有多个字段,且有一个记录指针,指针所指的数据行叫做当前数据行,我们只能来操作当前的数据行。我们如果想要取得某一条记录,就要使用ResultSet的next()方法 ,如果我们想要得到ResultSet里的所有记录,就应该使用while循环。
ResultSet对象自动维护指向当前数据行的游标。每调用一次next()方法,游标向下移动一行。
初始状态下记录指针指向第一条记录的前面,通过next()方法指向第一条记录。循环完毕后指向最后一条记录的后面。
2.2.5 关闭数据库资源
作为一种好的编程风格,应在不需要Statement对象和Connection对象时显式地关闭它们。关闭Statement对象和Connection对象的语法形式为:
public void close() throws SQLException
用户不必关闭ResultSet。当它的 Statement 关闭、重新执行或用于从多结果序列中获取下一个结果时,该ResultSet将被自动关闭。
注意:要按先ResultSet结果集,后Statement,最后Connection的顺序关闭资源,因为Statement和ResultSet是需要连接是才可以使用的,所以在使用结束之后有可能其他的Statement还需要连接,所以不能先关闭Connection。
3. 准备工作
3.1 创建数据并创建student表
3.2 创建项目
3.3 创建lib目录并引入MYSQL驱动包
3.4 把lib包引入项目环境
4. 使用JDBC完成添加操作
4.1 步骤
Ø 加载MySQL的JDBC驱动
Ø 建立数据的连接
Ø 创建SQL命令的发送器
Ø 编写SQL
Ø 使用SQL命令发送器发送SQL命令并得到结果
Ø 处理结果
Ø 关闭数据库资源
4.2 代码
package com.bjpowernode.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Test01Add {
// 驱动器路径
private static final String DRIVER = "com.mysql.jdbc.Driver";
//连接数据库地址
private static final String URL = "jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF8";
//数据库用户名
private static final String USER_NAME = "root";
//数据库密码
private static final String USER_PASSWORD = "123456";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 加载JDBC访问Oracle的驱动
Class.forName(DRIVER);
// 建立和数据库的连接
Connection conn = DriverManager.getConnection(URL, USER_NAME, USER_PASSWORD);
// 创建SQL命令发送器
Statement stmt = conn.createStatement();
// 使用SQL命令发送器发送SQL命令并得到结果
String sql = "insert into student values(1,'小刚',32,'男','湖北省武汉市')";
int n = stmt.executeUpdate(sql);
// 处理结果
if (n > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
// 关闭数据库资源
stmt.close();
conn.close();
}
}
4.3 URL详解
4.3.1 为什么要定义URL
Java和MySQL是厂商的,Java程序和MySQL数据库此时不在同一个进程下,此时Java程序需要向MySQL发送请求。
4.3.2 如何发送请求呢?
jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF-8
使用URL的方式发送
jdbc 主协议
mysql 子协议
localhost MySQL服务器的地址,如果服务器就是我自己的主机,那么定义localhost就可以了
3306 MySQL服务器的端口号
whpowernode MySQL数据库服务器的数据库名称
useUnicode=true Java和MySQL交互使用Unicode编码
useSSL=false Java和MySQL交互不使用安全层协议
characterEncoding=UTF-8 Java和MySQL交互的编码方式为UTF-8 【如果不设置会有乱码的】
4.4 查看数据库
4.4.1 一个URL由哪些部分组成
Ø 协议://服务器主机:端口/服务器路径?查询参数
Ø 协议 jdbc:mysql:
Ø 服务器主机 localhost
Ø 端口 3306
Ø 服务器路径 whpowernode
Ø 参数useUnicode=true&useSSL=false&characterEncoding=UTF8
5. 使用JDBC完成更新和删除
5.1 步骤
Ø 加载MySQL的JDBC驱动
Ø 建立数据的连接
Ø 创建SQL命令的发送器
Ø 编写SQL
Ø 使用SQL命令发送器发送SQL命令并得到结果
Ø 处理结果
Ø 关闭数据库资源
5.2 修改代码
package com.bjpowernode.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Test02Update {
// 驱动器路径
private static final String DRIVER = "com.mysql.jdbc.Driver";
//连接数据库地址
private static final String URL = "jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF8";
//数据库用户名
private static final String USER_NAME = "root";
//数据库密码
private static final String USER_PASSWORD = "123456";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 加载Oracle的JDBC驱动
Class.forName(DRIVER);
// 建立数据的连接
Connection conn=DriverManager.getConnection(URL, USER_NAME, USER_PASSWORD);
// 创建SQL命令的发送器
Statement stat=conn.createStatement();
// 编写SQL
String sql="update student set name='小明',age=23,sex='女',address='武汉' where id=1";
// 使用SQL命令发送器发送SQL命令并得到结果
int res=stat.executeUpdate(sql);
// 处理结果
if(res>0){
System.out.println("修改成功");
}
else{
System.out.println("处理失败");
}
// 关闭数据库资源
stat.close();
conn.close();
}
}
5.3 删除代码
package com.bjpowernode.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Test03Delete {
// 驱动器路径
private static final String DRIVER = "com.mysql.jdbc.Driver";
//连接数据库地址
private static final String URL = "jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF8";
//数据库用户名
private static final String USER_NAME = "root";
//数据库密码
private static final String USER_PASSWORD = "123456";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 加载Oracle的JDBC驱动
Class.forName(DRIVER);
// 建立数据的连接
Connection conn=DriverManager.getConnection(URL, USER_NAME, USER_PASSWORD);
// 创建SQL命令的发送器
Statement stat=conn.createStatement();
// 编写SQL
String sql="delete from student where id=1";
// 使用SQL命令发送器发送SQL命令并得到结果
int res=stat.executeUpdate(sql);
// 处理结果
if(res>0){
System.out.println("删除成功");
}
else{
System.out.println("删除失败");
}
// 关闭数据库资源
stat.close();
conn.close();
}
}
6. DBUtils的简单封装
6.1 为什么要封装
从我们上面的代码大家可以看到,每一次写我们创建一个连接,创建一个发送SQL的对象,最后还要关闭,那么我们可以考虑把这重复的代码提取出来!
6.2 创建DBUtils封装代码
package com.bjpowernode.utils;
import java.io.Closeable;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtils {
// 驱动器路径
private static final String DRIVER = "com.mysql.jdbc.Driver";
// 连接数据库地址
private static final String URL = "jdbc:mysql://localhost:3306/whpowernode?useUnicode=true&useSSL=false&characterEncoding=UTF8";
// 数据库用户名
private static final String USER_NAME = "root";
// 数据库密码
private static final String USER_PASSWORD = "123456";
/**
* 静态加载驱动程序
*/
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* @return 连接对象
*/
public static Connection getConn() {
try {
return DriverManager.getConnection(URL, USER_NAME, USER_PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
System.out.println("创建连接对象异常");
}
return null;
}
/**
* 关闭资源
*/
public static void close(AutoCloseable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
6.3 创建上面的工具类对象前面的代码进行改造
package com.bjpowernode.jdbc;
import com.bjpowernode.utils.DBUtils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Test01Add {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection conn = DBUtils.getConn();
// 创建SQL命令发送器
Statement stmt = conn.createStatement();
// 使用SQL命令发送器发送SQL命令并得到结果
String sql = "insert into student values(1,'小刚',32,'男','湖北省武汉市')";
int n = stmt.executeUpdate(sql);
// 处理结果
if (n > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
// 关闭数据库资源
DBUtils.close(stmt);
DBUtils.close(conn);
}
}
7. 使用JDBC完成查询
7.1 循环向student表里面插入20条数
package com.bjpowernode.jdbc;
import com.bjpowernode.utils.DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random;
public class Test01Add20 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection conn = DBUtils.getConn();
// 创建SQL命令发送器
Statement stmt = conn.createStatement();
// 使用SQL命令发送器发送SQL命令并得到结果
Random random=new Random();
for (int i = 1; i <=20 ; i++) {
Integer id=i;
String name="小明"+i;
int age=random.nextInt(100);
String sex=random.nextBoolean()?"男":"女";
String address="武汉"+i;
String sql = "insert into student values("+i+",'"+name+"',"+age+",'"+sex+"','"+address+"')";
int n = stmt.executeUpdate(sql);
// 处理结果
if (n > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
}
// 关闭数据库资源
DBUtils.close(stmt);
DBUtils.close(conn);
}
}
7.2 查询
package com.bjpowernode.jdbc;
import com.bjpowernode.utils.DBUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test04Query {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection conn = DBUtils.getConn();
// 创建SQL命令发送器
Statement stmt = conn.createStatement();
// 编写SQL
String sql="select * from student";
// 使用SQL命令发送器发送SQL命令并得到结果
ResultSet rs=stmt.executeQuery(sql);
// 处理结果
while(rs.next()){
int id=rs.getInt(1);
String name=rs.getString(2);
int age=rs.getInt(3);
String sex=rs.getString(4);
String address=rs.getString(5);
System.out.println(id+" "+name+" "+age+" "+sex+" "+address);
}
// 关闭数据库资源
DBUtils.close(rs);
DBUtils.close(stmt);
DBUtils.close(conn);
}
}
8. 使用JDBC完成分页查询
package com.bjpowernode.jdbc;
import com.bjpowernode.utils.DBUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test05QueryForPage {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection conn = DBUtils.getConn();
// 创建SQL命令发送器
Statement stmt = conn.createStatement();
int pageNum=2; //页码
int pageSize=5;//每页显示的条数
// 编写SQL
String sql="select * from student limit "+(pageNum-1)*pageSize+","+pageSize;
// 使用SQL命令发送器发送SQL命令并得到结果
ResultSet rs=stmt.executeQuery(sql);
// 处理结果
while(rs.next()){
int id=rs.getInt(1);
String name=rs.getString(2);
int age=rs.getInt(3);
String sex=rs.getString(4);
String address=rs.getString(5);
System.out.println(id+" "+name+" "+age+" "+sex+" "+address);
}
// 关闭数据库资源
DBUtils.close(rs);
DBUtils.close(stmt);
DBUtils.close(conn);
}
}