JDBC
JDBC介绍
Java Database Connectivity
Java规定的数据库连接接口,SUN公司提供,为了简化程序员操作数据库的过程。
SUN公司要求数据库提供商,按照JDBC API接口规范,完成对应Java程序的数据连接操作,
规范jar包,并且提供对应的操作方法。
JDBC接口中核心的内容:
java.sql.*
javax.sql.*
JDBC连接数据库所需的必要条件
1.确定连接的数据库所在网络地址和对应操作哪一个数据库,这里需要使用一个符合JDBC规范的URL
jdbc:mysql://localhost:3306/tbName
含义:
jdbc:目前操作数据库的主协议
mysql:主协议
localhost:数据库服务器所在的网络地址
3306:数据库默认端口号
tbName:当前URL连接操作对应数据库是哪一个
JDBC是第三方提供的内容,所以要获取对应的jar包
2.用户名
3.密码
JDBC连接MySQL数据库
1.导入jar包
在项目根目录创建lib目录,放入对应jar包,引入依赖
2.加载驱动
Java程序只是规定了接口规范,但是没有实现
数据库连接需要使用JDBC对应驱动
3.准备必要的参数连接数据库
4.获取数据库连接
5.关闭资源
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
/*
1.加载驱动
*/
Class.forName("com.mysql.jdbc.Driver");
/*
准备必要的数据
*/
String url = "jdbc:mysql://localhost:3306/wcc?useSSL=true";
String user = "root";
String password = "10086";
/*
3.获取数据库连接
*/
Connection connection = DriverManager.getConnection(url,user,password);
System.out.println(connection);
/*
4.关闭资源
*/
connection.close();
}
}
//显示结果
//com.mysql.jdbc.JDBC4Connection@7dc36524
如何导入jar包
打开IDEA
点击左上角的File ==> Project Structure
点击左边栏中的 Modules
之后,点击Dependencies
点击最右边的 + 号,选择第一个 JAR
然后选择导入的jar包路径,然后选择该jar包
就OK了
JDBC核心API
class java.sql.DriverManager 驱动管理类
static java.sql.Connection getConnection(String url,String user,String password);
这里是根据对应的数据库连接URL,对应的user用户名和密码,获取数据库连接对象
interface java.sql.Connection 数据库连接接口
java.sql.Statement createStatement();
获取数据库SQL语句搬运工对象,从Java程序搬运SQL语句到数据库中,同时Statement也是一个资源对象
java.sql.PrepareStatement prepareStatement(String sql);
获取SQL语句[预处理]搬运工对象,Java程序的eSQL语句,在创建PrepareStatement对象时
将SQL语句交给数据库预处理操作,可以解决一定的[SQL语句注入问题],同时提高一定的效率,
PrepareStatement也是一个资源对象
interface java.sql.Statement 数据库SQL语句搬运工对象
int executeUpdate(String sql);
执行数据库修改数据,insert,update,delete...返回值时int类型,是当前SQL语句搬运到数据库执行
之后,数据库运行对于当前操作受到影响的行数
java.sql.ResultSet executeQuery(String sql);
执行数据库查询语句,select操作,执行的结果是一个java.sql.ResultSet结果集对象,当前操作never null
interface java.sql.PrepareStatement 数据库SQL语句[预处理]搬运工对象
PreparedStatement extends java.sql.Statement
int executeUpdate();
执行数据库修改数据,insert,update,delete...处理的SQL语句是在创建PrepareStatement对象过程预处理的SQL语句,返回值时int类型,是当前SQL语句搬运到数据库执行
java.sql.ResultSet executeQuery();
setXXX(int index,XXX value);
PreparedStatement预处理的SQL是可以带有参数的,这里是对于SQL语句参数进行赋值操作,这里有指定的操作下标,和对应的数据,数据类型繁多
interface java.sql.ResultSet 数据库结果集接口
XXX getXXX(int columnIndex);
根据查询结果中字段所处的位置下标获取对应的数据,XXX是指定类型
XXX getXXX(String fieldName);
根据查询结果中字段所处的字段名获取对应的数据,XXX是指定类型
boolean next();
判断当前查询结果集中是否还有可以遍历操作的数据,如果没有,或者当前结果集中式无数据情况,Empty Set,直接返回false
Statement操作SQL语句
Statement插入SQL数据操作
public class StatementTest {
@Test
public void testInsert(){
Statement statement = null;
Connection connection = null;
//加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/wcc?useSSL=true";
String user = "root";
String password = "131477";
//获取数据库连接
connection = DriverManager.getConnection(url,user,password);
//准备statement对象
statement = connection.createStatement();
//准备SQL语句
String sql = "insert into wcc.student (age,name) values (22,'jkkkkk')";
int affectedRows = statement.executeUpdate(sql);
System.out.println("影响的行数:" + affectedRows);
statement.close();
connection.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
//显示结果:
//影响的行数:1
Statement修改SQl数据操作
@Test
public void testUpdate(){
try {
Statement statement = null;
Connection connection = null;
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//准备必要的连接数据
String url = "jdbc:mysql://localhost:3306/wcc?useSSL=true";
String user = "root";
String password = "131477";
//获取数据库连接
connection = DriverManager.getConnection(url,user,password);
//获取Statement对象
statement = connection.createStatement();
//准备sql语句
String sql = "update wcc.student set age = 10086 where name = 'wcc'";
//执行sql语句
int affectedRows = statement.executeUpdate(sql);
System.out.println("影响到的行数:" + affectedRows);
connection.close();
statement.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
//显示结果:
//影响到的行数:1
JDBC高级
Statement查询SQL数据操作
// 查询指定的一个数据行,转换成对应的User对象
@Test
public void testSelectOne() {
ResultSet resultSet = null;
Statement statement = null;
Connection connection = null;
User user1 = null;
try {
// 1. 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2. 准备必要的连接数据
String url = "jdbc:mysql://localhost:3306/nzgp2001?useSSL=true";
String user = "root";
String password = "123456";
// 3. 获取数据库连接
connection = DriverManager.getConnection(url, user, password);
// 4. 准备SQL语句
String sql = "select * from nzgp2001.user where id = 1";
// 5. 获取Statement对象
statement = connection.createStatement();
// 6. 执行SQL语句
resultSet = statement.executeQuery(sql);
// 7. ResultSet结果集对象解析过程
while (resultSet.next()) {
// 通过指定的字段获取对应的数据
int id = resultSet.getInt("id");
String userName = resultSet.getString("userName");
String password1 = resultSet.getString("password");
user1 = new User(id, userName, password1);
System.out.println(user1);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 7. 关闭资源
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
JDBC工具类封装
需要完成的内容:
1.数据库连接对象java.sql.Connection获取过程
2.关闭资源
JDBC工具类
1.所有的方法都是static修饰的静态方法
2.需要考虑自动加载过程,完成一些必要数据的自动处理
url
driver
user
password
3.所需数据库连接条件保存到文件中
4.关闭方法提供多种多样组合方法
# 当前JDBC连接所需的驱动
driverClass=com.mysql.jdbc.Driver
# 数据库连接符合JDBC规范的url
url=jdbc:mysql://localhost:3306/nzgp2001?useSSL=true
# 用户名
user=root
# 密码
password=123456
package util;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
/**
* JDBC工具类,负责数据库连接对象和数据库资源关闭
*
* @author Anonymous 2020/3/24 10:08
*/
public class JdbcUtil {
// 静态成员变量,保存一些必要的数据
private static String url = null;
private static String user = null;
private static String password = null;
// 利用static修饰的静态代码块完成文件字段自动读取和驱动自动加载过分
static {
try {
// Properties实现类,里面的数据保存形式都是键值对形式
Properties properties = new Properties();
// 使用字节输入流,加载对应db.properties,数据保存到Properties对象中
properties.load(new FileInputStream("./src/db.properties"));
// 从Properties读取对应的数据
String driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
// 完整驱动加载
Class.forName(driverClass);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 返回数据库连接对象,连接失败返回null
*
* @return java.sql.Connection 数据库连接对象
*/
public static Connection getConnection() {
Connection connection = null;
try {
// 通过DriverManager驱动管理类,使用必要参数获取数据库连接
connection = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/*
以下三个方法实际上都是执行同一个方法,使用这种方式
1. 简化代码结构
2. 规范化所有的操作
*/
/**
* 处理数据库操作对应的资源问题
*
* @param connection java.sql.Connection 数据库连接对象
*/
public static void close(Connection connection) {
close(connection, null, null);
}
/**
* 处理数据库操作对应的资源问题
*
* @param connection java.sql.Connection 数据库连接对象
* @param statement java.sql.Statement 数据库SQL语句搬运工对象
*/
public static void close(Connection connection, Statement statement) {
close(connection, statement, null);
}
/**
* 处理数据库操作对应的资源问题
*
* @param connection java.sql.Connection 数据库连接对象
* @param statement java.sql.Statement 数据库SQL语句搬运工对象
* @param resultSet java.sql.ResultSet 数据库查询结果集对象
*/
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
PreparedStatement的使用
PreparedStatement插入数据SQL完成
@Test
public void testInsert() {
User user = new User(10, "逗比匿名君", "123456");
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
// 获取数据库连接
connection = JdbcUtil.getConnection();
// 准备SQL语句
// ? 表示SQL语句参数占位符!!!
String sql = "insert into nzgp2001.user(id, userName, password) VALUE (?,?,?)";
// 预处理SQL语句,获取PreparedStatement对象
preparedStatement = connection.prepareStatement(sql);
// SQL语句赋值操作,SQL语句参数是从1开始
preparedStatement.setObject(1, user.getId());
preparedStatement.setObject(2, user.getUserName());
preparedStatement.setObject(3, user.getPassword());
// 使用PreparedStatement执行SQL语句
int affectedRows = preparedStatement.executeUpdate();
System.out.println("affectedRows:" + affectedRows);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(connection, preparedStatement);
}
}
PreparedStatement修改数据SQL完成
@Test
public void testUpdate() {
User user = new User(10, "逗比匿名君", "航海中路彭于晏");
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil.getConnection();
String sql = "update user set userName = ?, password = ? where id = ?";
preparedStatement = connection.prepareStatement(sql);
// 赋值SQL语句参数
preparedStatement.setObject(1, user.getUserName());
preparedStatement.setObject(2, user.getPassword());
preparedStatement.setObject(3, user.getId());
int affectedRows = preparedStatement.executeUpdate();
System.out.println("affectedRows:" + affectedRows);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(connection, preparedStatement);
}
}
PreparedStatement删除数据SQL完成
@Test
public void testDelete() {
int id = 7;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil.getConnection();
String sql = "delete from user where id = ?";
preparedStatement = connection.prepareStatement(sql);
// 赋值参数
preparedStatement.setObject(1, id);
int affectedRows = preparedStatement.executeUpdate();
System.out.println("affectedRows:" + affectedRows);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(connection, preparedStatement);
}
}
PreparedStatement查询数据SQL完成
@Test
public void testSelectOne() {
int id = 10;
User user = null;
ResultSet resultSet = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil.getConnection();
String sql = "select * from user where id = ?";
preparedStatement = connection.prepareStatement(sql);
// 赋值参数
preparedStatement.setObject(1, id);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
String userName = resultSet.getString("userName");
String password = resultSet.getString("password");
user = new User(id, userName, password);
}
if (user != null) {
System.out.println(user);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(connection, preparedStatement, resultSet);
}
}
@Test
public void testSelectAll() {
List<User> list = new ArrayList<>();
ResultSet resultSet = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil.getConnection();
String sql = "select * from user";
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
int id = resultSet.getInt("id");
String userName = resultSet.getString("userName");
String password = resultSet.getString("password");
list.add(new User(id, userName, password));
}
for (User user : list) {
System.out.println(user);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(connection, preparedStatement, resultSet);
}
}
BaseDao封装
需求
1. 完成通用的更新方法,满足insert,update,delete操作
2. 完成通用的查询方法,满足select
问题
1. 数据库连接对象获取[解决]
2. 资源关闭[解决]
3. PreparedStatement参数赋值过程【未解决】
a. 参数个数
PreparedStatement预处理SQL语句?有多少个
b. 赋值顺序‘
参数传入方式和顺序问题
4. 查询结果集解析过程【未解决】
a. 返回值是一个List<目标数据类型>集合
b. 返回值是一个Object数组
元数据
三种元数据:
数据库元数据
通过java.sql.Connection获取对应的元数据
SQL语句元数据
通过java.sql.PreparedStatement获取对应的元数据
数据库结果集元数据
通过java.sql.ResultSet获取对应的元数据
关键字:MetaData
重点:
1.SQL语句元数据,参数元数据其中的参数个数,对应?占位符个数
2.结果集元数据中的字段个数,和对应当前字段下标的字段名字
BeanUtils使用
BeanUtils提供了对于符合JavaBean规范的实体类进行赋值,取值,拷贝操作的一系列方法,可以自动完成数据类型转换,方便开发者在数据交互中使用。
三个方法(都是静态方法):
1.赋值指定成员变量对应数据
a.符合JavaBean规范的类对象
b.指定成员变量的名字
c.Object类型数据用于赋值成员变量
2.取值指定成员变量的数据
a.符合JavaBean规范的类对象
b.指定成员变量的名字,返回值是对应当前成员百年来的数据类型
3.拷贝符合JavaBean规范的两个对象数据
a.符合JavaBean规范的目标类对象
b.符合JavaBean规范的目标数据源对象
4. 真香方法,从Map双边对联中匹配赋值数据到符合JavaBean规范的类对象
a. 符合JavaBean规范的类对象
b. Map双边队列
package com.qfedu.c_testbeanutils;
import com.qfedu.a_statement.User;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
/**
* BeanUtils测试
*
* @author Anonymous 2020/3/24 15:09
*/
public class Demo1 {
@Test
public void testSetProperty()
throws InvocationTargetException, IllegalAccessException {
User user = new User();
// 给符合JavaBean规范的指定成员变量赋值操作
BeanUtils.setProperty(user, "id", "123");
BeanUtils.setProperty(user, "userName", "骚磊");
BeanUtils.setProperty(user, "password", 123456);
System.out.println(user);
}
@Test
public void testGetProperty()
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
User user = new User(1, "骚磊", "2344567");
System.out.println(BeanUtils.getProperty(user, "id"));
System.out.println(BeanUtils.getProperty(user, "userName"));
System.out.println(BeanUtils.getProperty(user, "password"));
}
@Test
public void testCopyProperties() throws InvocationTargetException, IllegalAccessException {
User user = new User(1, "骚磊", "2344567");
User user1 = new User();
System.out.println("before:" + user1);
BeanUtils.copyProperties(user1, user);
System.out.println("after:" + user1);
}
// populate
@Test
public void 真香() throws InvocationTargetException, IllegalAccessException {
HashMap<String, Integer> map = new HashMap<>();
map.put("userName", 100);
map.put("location:", 1);
map.put("password", 1111);
map.put("id", 2);
User user = new User();
System.out.println("before:" + user);
BeanUtils.populate(user, map);
System.out.println("after:" + user);
}
}
通用更新方法实现
分析:
完成通用的更新方法,update,insert,delete操作
权限修饰符:public
返回值类型:int 当前SQL语句参数,数据库受到影响的行数
方法名:update
形式参数列表:
1. String sql语句
指定执行的SQL语句 update insert delete。。。
2. SQL语句可能需要参数
SQL有可能没有参数,有可能多个参数,而且参数类型都不一样!!!
a. Object...
Object类型的不定长参数
b. Object[]
所有对应当前SQL语句的参数都存储在Object类型数组中
(String sql, Object[] parameters)
方法声明:
public int update(String sql, Object[] parameters)
/**
* 通用的更新方法,需要参数是SQL语句和对应当前SQL语句的Object类型参数数组
*
* @param sql String类型的SQL语句,需要执行的方法
* @param parameters 对应当前SQL语句的参数列表。Object类型数组
* @return SQL语句执行数据库受到影响的行数
*/
public int update(String sql, Object[] parameters) {
int affectedRows = 0;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtil.getConnection();
preparedStatement = connection.prepareStatement(sql);
/*
获取SQL语句参数个数!!!通过SQL语句元数据获取(ParameterMetaData)
*/
int parameterCount = preparedStatement.getParameterMetaData().getParameterCount();
/*
parameterCount 参数个数不能为0
parameters != null 参数数组不为null,因为存在当前方法没有参数,数组传入null
parameterCount == parameters.length 参数个数和传入的Object类型参数数容量一致
*/
if (parameterCount != 0 && parameters != null && parameterCount == parameters.length) {
for (int i = 0; i < parameters.length; i++) {
/*
SQL语句参数下标从1开始
数组数据下标从0开始
*/
preparedStatement.setObject(i + 1, parameters[i]);
}
}
// 执行SQL语句
affectedRows = preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(connection, preparedStatement);
}
return affectedRows;
}
通用查询方法实现
分析:
完成通用的查询方法,select操作
权限修饰符:
public
需要声明泛型
T ==> Type
返回值类型:
List<指定数据类型>
方法名:
query
形式参数列表:
1. String sql语句
指定执行的SQL语句 Select语句
2. SQL语句可能需要参数
SQL有可能没有参数,有可能多个参数,而且参数类型都不一样!!!
a. Object...
Object类型的不定长参数
b. Object[]
所有对应当前SQL语句的参数都存储在Object类型数组中
3. 告知当前SQL语句出现的查询结果对应数据类型是哪一个
Class<T> cls
a. 泛型T
用于数据类型约束,传入哪一个类的.class当前T对应的就是哪一个类
b. Class 反射对应的Class类对象
为所欲为!!!
有了对应类的.class字节码文件对应Class对象。可以通过反射为所欲
为
(String sql, Object[] parameters, Class<T> cls)
方法声明:
public <T> List<T> query(String sql, Object[] parameters, Class<T> cls)
/**
* 通用的查询方法,查询cls指定数据类型,返回值是一个List集合
*
* @param sql Select SQL语句
* @param parameters 对应当前SQL语句的参数
* @param cls 指定数据类型,同时提供Class对象,便于里用反射操作,约束泛型类型
* @param <T> 泛型占位符
* @return 指定数据类型的List集合,如果集合中不存在数据 size() == 0 返回null
*/
public <T> List<T> query(String sql, Object[] parameters, Class<T> cls) {
ResultSet resultSet = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
List<T> list = new ArrayList<>();
try {
connection = JdbcUtil.getConnection();
preparedStatement = connection.prepareStatement(sql);
/*
获取SQL语句参数个数!!!通过SQL语句元数据获取(ParameterMetaData)
*/
int parameterCount = preparedStatement.getParameterMetaData().getParameterCount();
/*
parameterCount 参数个数不能为0
parameters != null 参数数组不为null,因为存在当前方法没有参数,数组传入null
parameterCount == parameters.length 参数个数和传入的Object类型参数数容量一致
*/
if (parameterCount != 0 && parameters != null && parameterCount == parameters.length
for (int i = 0; i < parameters.length; i++) {
/*
SQL语句参数下标从1开始
数组数据下标从0开始
*/
preparedStatement.setObject(i + 1, parameters[i]);
}
}
// 执行SQL语句,得到结果集对象
resultSet = preparedStatement.executeQuery();
// 结果集元数据
ResultSetMetaData metaData = resultSet.getMetaData();
// 字段个数
int columnCount = metaData.getColumnCount();
while (resultSet.next()) {
// 根据Class类型创建对象,对象的类型是T类型
T t = cls.getConstructor().newInstance();
for (int i = 1; i <= columnCount; i++) {
// 获取字段名
String fieldName = metaData.getColumnName(i);
// 获取对应字段数据
Object value = resultSet.getObject(fieldName);
// 给符合JavaBean规范的实现类,指定成员变量fieldName,赋值value
BeanUtils.setProperty(t, fieldName, value);
}
list.add(t);
}
} catch (SQLException | NoSuchMethodException | InstantiationException
| IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(connection, preparedStatement, resultSet);
}
// 判断结果,如果List中没有存储数据,返回null
return list.size() != 0 ? list : null;
}