目录
一,JDBC介绍
1.1概念
JDBC(Java DataBase Connectivity) :Java数据库连接技术:具体讲就是通过Java连接广泛的数据库,并对表中数据执行增、删、改、查等操作的技术。
1.2本质
JDBC本质上也是一种发送SQL操作数据库的client技术,只不过需要通过Java编码完成。
JDBC是规范(接口)不是实现(类)
Java Application | ||
|| | ||
JDBC接口 | ||
|| | ||
Oracle提供JDBC实现 | SQLServer提供JDBC实现 | MySQL提供JDBC实现 |
如果不同的数据库,我们的方法不统一,不利于程序管理,所以规范一套接口规范,让不同的数据库厂商实现,在Java程序中统计调用接口的方法即可。
1.3 JDBC API
JDBC API 是一系列的接口,它统一和规范了应用程序和数据库的连接,执行SQL语句,并到得到返回结果等各类操作,相关类和接口在Java.sql与Javax.sql包中。
1.4JDBC技术相关接口
作用:JDBC要通过Java代码操作数据库,JDBC中定义了操作数据库的各种接口和类型:
接口 | 作用 |
---|---|
Driver | 驱动接口,定义建立链接的方式 |
DriverManager | 工具类,用于管理驱动,可以获取数据库的链接 |
Connection | 表示Java与数据库建立的连接对象(接口) |
PreparedStatement | 发送SQL语句的工具 |
ResultSet | 结果集,用于获取查询语句的结果 |
二,编码
2.1JDBC开发步骤
1. 注册驱动 - 加载Driver类
2. 获取链接 - 得到 Connection
3.执行增删改查 - 发送SQL给MySQL执行(1,获取数据库操作对象 2,执行sql语句3,处理查询结果集)
4. 释放资源 - 关闭相关连接
2.2JBDC入门程序
前置工作
新建Directory libs-》复制jar包-》添加到Library
package com.amber.jdbc;
import com.mysql.jdbc.Driver;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class Jdbc01 {
public static void main(String[] args) throws SQLException {
//1,注册驱动
Driver driver = new Driver();
//2,得到连接
//(1) jdbc:mysql:// 规定好表示协议,通过 jdbc 的方式连接 mysql
//(2) localhost 主机,可以是 ip 地址
//(3) 3306 表示 mysql 监听的端口
//(4) amber_db02 连接到 mysql dbms 的哪个数据库
//(5) mysql 的连接本质就是socket 连接
String url = "jdbc:mysql://localhost:3306/amber_db02";
//将 用户名和密码放入到 Properties 对象
Properties properties = new Properties();
//说明 user 和 password 是规定好,后面的值根据实际情况写
properties.setProperty("user", "root");// 用户
properties.setProperty("password", "hsp"); //密码
Connection connect = driver.connect(url, properties);
//3. 执行 sql
String sql = "insert into actor values(null, 'amber', '女', '2004-11-11', '110')";
//String sql = "update actor set name='Jack' where id = 1";修改id为1的人的名字
//String sql = "delete from actor where id = 1";删除id为1的一行
//statement 用于执行静态 SQL 语句并返回其生成的结果的对象
Statement statement = connect.createStatement();
int rows = statement.executeUpdate(sql);// 如果是 dml 语句,返回的就是影响行数
//返回是1,表示插入成功,0则失败
System.out.println(rows > 0 ? "成功" : "失败");
//4. 关闭连接资源
statement.close();
connect.close();
}
}
2.3 获取数据库连接 5 种方式
2.3.1 方式 1
//获取Driver实现类对象
Driver driver = new Driver();
2.3.2 方式2
//使用反射加载Driver类(动态加载,更灵活,减少依赖性)
Class clazz = Class.forName("com.musql.jdbc.Driver");
Driver driver = (Driver)clazz.newInstance();
2.3.3 方式3
//使用DriverManager替换Driver
public void connect03() throws IllegalAccessException, InstantiationException, ClassNotFoundException, SQLException {
//使用反射加载 Driver
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) aClass.newInstance();
//创建 url 和 user 和 password
String url = "jdbc:mysql://localhost:3306/amber_db02";
String user = "root";
String password = "hsp";
DriverManager.registerDriver(driver);//注册 Driver 驱动
Connection connection = DriverManager.getConnection(url, user, password);
}
2.3.4 方式4
//使用 Class.forName 自动完成注册驱动,简化代码,推荐使用
@Test
public void connect04() throws ClassNotFoundException, SQLException {
//在加载 Driver 类时,完成注册
/*
源码:
1. 静态代码块,在类加载时,会执行一次.
2. DriverManager.registerDriver(new Driver());
3. 因此注册 driver 的工作已经完成
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
*/
//使用反射加载了 Driver 类
Class.forName("com.mysql.jdbc.Driver");
//创建 url 和 user 和 password
String url = "jdbc:mysql://localhost:3306/amber_db02";
String user = "root";
String password = "hsp";
Connection connection = DriverManager.getConnection(url, user, password);
}
2.3.5 方式5
// 在方式 4 的基础上改进,增加配置文件,让连接 mysql 更加灵活
@Test
public void connect05() throws IOException, ClassNotFoundException, SQLException {
//通过 Properties 对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properites"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
Class.forName(driver);//建议写上
Connection connection = DriverManager.getConnection(url, user, password);
}
}
配置文件
三,JDBC API
3.1ResultSet(结果集)
3.1.1基本介绍
1、表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
2.ResultSet对象保持一个光标指向其当前的数据行。最初,光标位于第一行之前
3.next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回
false,因此可以在while循环中使用循环来遍历结果集
3.1.2 ResultSet常用方法
方法声明 | 作用 |
boolean next() | 游标下移,判断该行是否有结果 |
xx getXx(int index) | 获取该行结果中某个字段的数据,index为编号,index从1开始 |
xx getXx(String name) | 获取改行结果中某个字段的数据,name为字段名 |
package com.amber.ResultSet_;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date;
import java.util.Properties;
public class resultSet_ {
public static void main(String[] args) throws Exception {
//通过 Properties 对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properites"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);//建议写上
//2. 得到连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到 Statement
Statement statement = connection.createStatement();
//4. 组织 SqL
String sql = "select id, name , sex, borndate from actor";
ResultSet resultSet = statement.executeQuery(sql);//(执行给定的SQL语句,该语句返回单个ResultSet对象)
//5. 使用 while 取出数据
while(resultSet.next()){
// next方法 让光标向后移动,如果没有更多行,则返回 false
int id = resultSet.getInt(1); //获取该行的第 1 列
// int id1 = resultSet.getInt("id"); 通过列名来获取值, 推荐
String name = resultSet.getString(2);//获取该行的第 2 列
String sex = resultSet.getString(3);
Date date = resultSet.getDate(4);
System.out.println(id + "\t" + name + "\t" + sex + "\t" + date);
}
//6. 关闭连接
resultSet.close();
statement.close();
connection.close();
}
}
3.2 Statement
3.2.1基本介绍
1.Statement对象 用于执行静态SQL语句并返回其生成的结果的对象
2.在连接建立后,需要对数据库进行访问,执行 命名或是SQL语句,可以通过
- Statement [存在SQL注入]
- PreparedStatement [预处理]
- CallableStatement[存储过程]
3. Statement对象执行SQL语句,存在SQL注入风险 SQL Injection
4.SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库。
5.要防范SQL注入,只要用 PreparedStatement(从Statement扩展而来)取代 Statement就可以了。
3.2.2 SQL注入示例
-- 演示 sql 注入
-- 创建一张表
CREATE TABLE admin ( -- 管理员表
NAME VARCHAR(32) NOT NULL UNIQUE, pwd VARCHAR(32) NOT NULL DEFAULT '') CHARACTER SET utf8; -- 添加数据
INSERT INTO admin VALUES('tom', '123');
-- 查找某个管理是否存在
SELECT *
FROM admin
WHERE NAME = 'tom' AND pwd = '123'
-- SQL
-- 输入用户名 为 1' or
-- 输入万能密码 为 or '1'= '1
SELECT *
FROM admin
WHERE NAME = '1' OR' AND pwd = 'OR '1'= '1'
package com.amber.Statement_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
public class statement_ {
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
Scanner scanner = new Scanner(System.in);
//让用户输入管理员名和密码
System.out.print("请输入管理员的名字: "); //next(): 当接收到 空格或者 '就是表示结束
String admin_name = scanner.nextLine(); //如果希望看到 SQL 注入,这里需要用 nextLine
System.out.print("请输入管理员的密码: ");
String admin_pwd = scanner.nextLine();
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properites"));
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
String sql = "select name , pwd from admin where name ='" + admin_name + "' and pwd = '" + admin_pwd + "'";
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()) { //如果查询到一条记录,则说明该管理存在
System.out.println("恭喜, 登录成功");
} else {
System.out.println("对不起,登录失败");
}
//关闭连接
resultSet.close();
statement.close();
connection.close();
}
}
3.3 PreparedStatement
3.3.1基本介绍
1.PreparedStatement执行的 SQL语句中的参数用问号(?)来表示,调用PreparedStatement对象的 setXxx()方法来设置这些参数.setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值
2.调用 executeQuery(),返回ResultSet对象
3.调用executeUpdate():执行更新,包括增、删、修改
3.3.2PreparedStatement常用方法
方法声明 | 作用 |
int executeUpdate(String sql) | 可执行增,删,改,返回执行受到影响的行数 |
ResultSet executeQuery(String sql) | 执行SQL查询,并返回ResultSet对象 |
boolean execute(String sql) | 可执行任何SQL语句,返回一个布尔值,表示是否返回ResultSet 。(只有执行查询才为true) |
优点
1,不再使用+拼接SQL语句,减少语法错误
2,有效的解决了SQL注入问题
3,大大减少了编译次数,效率较高
3.3.3预处理-查询
package com.amber.Preparedstatement_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
public class preparedststement_ {
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(System.in);
//让用户输入管理员名和密码
System.out.print("请输入管理员的名字: "); //next(): 当接收到 空格或者 '就是表示结束
String admin_name = scanner.nextLine(); // 如果希望看到 SQL 注入,这里需要用 nextLine
System.out.print("请输入管理员的密码: ");
String admin_pwd = scanner.nextLine();
//通过 Properties 对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properites"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);//建议写上
//2. 得到连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到 PreparedStatement
//3.1 组织 SqL , Sql 语句的 ? 就相当于占位符
String sql = "select name , pwd from admin where name =? and pwd = ?";
//3.2 preparedStatement 对象实现了 PreparedStatement 接口的实现类的对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//3.3 给 ? 赋值
preparedStatement.setString(1, admin_name);//1表示第一个问号
preparedStatement.setString(2, admin_pwd);
//4. 执行 select 语句使用 executeQuery
// 如果执行的是 dml(update, insert ,delete) 用executeUpdate()
// 这里执行 executeQuery ,不要再写 sql,以上的SQL与prepareStatement关联
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) { //如果查询到一条记录,则说明该管理存在
System.out.println("恭喜, 登录成功");
} else {
System.out.println("对不起,登录失败");
}
//关闭连接
resultSet.close();
preparedStatement.close();
connection.close();
}
}
3.3.4 预处理-dml
dml:数据库增删改
添加
package com.amber.Preparedstatement_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
public class preparedststement_ {
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(System.in);
//让用户输入管理员名和密码
System.out.print("请输入管理员的名字: "); //next(): 当接收到 空格或者 '就是表示结束
String admin_name = scanner.nextLine(); // 如果希望看到 SQL 注入,这里需要用 nextLine
System.out.print("请输入管理员的密码: ");
String admin_pwd = scanner.nextLine();
//通过 Properties 对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properites"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);//建议写上
//2. 得到连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到 PreparedStatement
//3.1 组织 SqL , Sql 语句的 ? 就相当于占位符
//查询
// String sql = "select name , pwd from admin where name =? and pwd = ?";
//第四步使用ResultSet resultSet = preparedStatement.executeQuery();
//添加记录
String sql = "insert into admin values (?,?)";
//3.2 preparedStatement 对象实现了 PreparedStatement 接口的实现类的对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//3.3 给 ? 赋值
preparedStatement.setString(1, admin_name);//1表示第一个问号
preparedStatement.setString(2, admin_pwd);
//4. 执行 dml 语句使用 executeUpdate
int rows = preparedStatement.executeUpdate();
System.out.println(rows > 0 ? "执行成功" : "执行失败");
//关闭连接
preparedStatement.close();
connection.close();
}
}
修改
package com.amber.Preparedstatement_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
public class preparedststement_ {
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(System.in);
//让用户输入管理员名和密码
System.out.print("请输入管理员的名字: "); //next(): 当接收到 空格或者 '就是表示结束
String admin_name = scanner.nextLine(); // 如果希望看到 SQL 注入,这里需要用 nextLine
System.out.print("请输入管理员的新密码: ");
String admin_pwd = scanner.nextLine();
//通过 Properties 对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properites"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);//建议写上
//2. 得到连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到 PreparedStatement
//3.1 组织 SqL , Sql 语句的 ? 就相当于占位符
//修改记录
String sql = "update admin set pwd =? where name = ?";
//3.2 preparedStatement 对象实现了 PreparedStatement 接口的实现类的对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//3.3 给 ? 赋值
preparedStatement.setString(1, admin_pwd);//1表示第一个问号
preparedStatement.setString(2, admin_name);
//4. 执行 dml 语句使用 executeUpdate
int rows = preparedStatement.executeUpdate();
System.out.println(rows > 0 ? "执行成功" : "执行失败");
//关闭连接
preparedStatement.close();
connection.close();
}
}
删除
package com.amber.Preparedstatement_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
public class preparedststement_ {
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(System.in);
//让用户输入管理员名和密码
System.out.print("请输入要删除的管理员的名字: "); //next(): 当接收到 空格或者 '就是表示结束
String admin_name = scanner.nextLine(); // 如果希望看到 SQL 注入,这里需要用 nextLine
//通过 Properties 对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properites"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
//1. 注册驱动
Class.forName(driver);//建议写上
//2. 得到连接
Connection connection = DriverManager.getConnection(url, user, password);
//3. 得到 PreparedStatement
//3.1 组织 SqL , Sql 语句的 ? 就相当于占位符
//删除记录
String sql = "delete from admin where name = ?";
//3.2 preparedStatement 对象实现了 PreparedStatement 接口的实现类的对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//3.3 给 ? 赋值
preparedStatement.setString(1, admin_name);//1表示第一个问号
//4. 执行 dml 语句使用 executeUpdate
int rows = preparedStatement.executeUpdate();
System.out.println(rows > 0 ? "执行成功" : "执行失败");
//关闭连接
preparedStatement.close();
connection.close();
}
}
总结
3.4 JDBCUtils
3.4.1 JDBCUtils
package com.amber.jdbc.utils;
//这是一个工具类,完成 mysql 的连接和关闭资源
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
//定义相关的属性(4 个), 因为只需要一份,因此,我们做出 static
private static String user; //用户名
private static String password; //密码
private static String url; //url
private static String driver; //驱动名
//在 static 代码块去初始化
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properites"));
//读取相关的属性值
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
} catch (IOException e) {
//在实际开发中,我们可以这样处理
// 1. 将编译异常转成 运行异常
// 2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
throw new RuntimeException(e);
}
}
public static Connection getConnection(){
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
// 1. 将编译异常转成 运行异常
// 2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
throw new RuntimeException(e);
}
}
//关闭相关资源
/*
1. ResultSet 结果集
2. Statement 或者 PreparedStatement
3. Connection
4. 如果需要关闭资源,就传入对象,否则传入 null
*/
public static void close(ResultSet set, Statement statement, Connection connection) {
//判断是否为 null
try {
if (set != null) {
set.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
//将编译异常转成运行异常抛出
throw new RuntimeException(e);
}
}
}
3.4.2 JDBCUtilsDML
package com.amber.jdbc.utils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JDBCUtils_Use {
@Test
public void testDML() {//insert , update, delete
//1. 得到连接
Connection connection = null;
//2. 组织一个 sql
String sql = "update actor set name = ? where id = ?";
// 测试 delete 和 insert
//3. 创建 PreparedStatement 对象
PreparedStatement preparedStatement = null;
try {
connection = JDBCUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
//给占位符赋值
preparedStatement.setString(1, "哒哒哒");
preparedStatement.setInt(2, 3);
//执行
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭资源
JDBCUtils.close(null, preparedStatement, connection);
}
}
}
3.4.3 JDBCUtils查询
package com.amber.jdbc.utils;
import org.junit.Test;
import java.sql.*;
public class JDBCUtils_Use {
@Test
public void testDML() {//insert , update, delete
//1. 得到连接
Connection connection = null;
//2. 组织一个 sql
String sql = "select *from actor";
// 测试 delete 和 insert ,自己玩. PreparedStatement preparedStatement = null;
//3. 创建 PreparedStatement 对象
PreparedStatement preparedStatement = null;
ResultSet set = null;
try {
connection = JDBCUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
//执行,得到结果集
set = preparedStatement.executeQuery();
//遍历该结果集
while(set.next()){
int id = set.getInt("id");
String name = set.getString("name");
String sex = set.getString("sex");
Date borndate = set.getDate("borndate");
String phone = set.getString("phone");
System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭资源
JDBCUtils.close(set, preparedStatement, connection);
}
}
}
四, 事务
基本介绍
1.JDBC程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
2.JDBC程序中为了让多个SQL语句作为一个整体执行,需要使用事务
3.调用 Connection 的 setAutoCommit(false)可以取消自动提交事务
4.在所有的SQL语句都成功执行后,调用Connection的commit();方法提交事务
5. 在其中某个操作失败或出现异常时,调用Connection的rollback();方法回
滚事务
批处理
基本介绍
1.当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
2.JDBC的批量处理语句包括下面方法:
addBatch():添加需要批量处理的SQL语句或参数
executeBatch():执行批量处理语句;
clearBatchQ:清空批处理包的语句
3.JDBC连接MySQL时,如果要使用批处理功能,请再url中加参数?rewriteBatchedStatements=true
4.批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减
少运行次数,效率大大提高