前言
JDBC是Java语言中用于连接和操作不同类型数据库的一套标准API(应用程序接口)。
它定义了一组Java类和接口,可以通过这些类和接口来访问和处理数据库。
在JDBC中有几个核心的接口和类:
DriverManager
类:是JDBC的基础类之一,用于加载数据库驱动程序,并与数据库建立连接。Connection
接口:表示与特定数据库的连接。通过该接口,可以创建Statement
对象以执行SQL语句。Statement
接口:用于执行SQL语句,并可以返回结果集。ResultSet
接口:表示数据库返回的结果集。它提供了访问和处理查询结果的方法。PreparedStatement
接口:继承自Statement
接口,用于预编译SQL语句。它可以提高性能并防止SQL注入攻击。CallableStatement
接口:继承自PreparedStatement
接口,用于调用存储过程。
通过使用这些接口和类,开发人员可以在Java程序中连接到不同类型的数据库,执行SQL语句,获取查询结果,并进行数据操作和管理。
此外,根据具体的数据库类型,还需要使用与之相关的数据库驱动程序。每个数据库提供商都会提供适用于其数据库的JDBC驱动程序,开发人员需要将这些驱动程序添加到项目中以便与数据库进行连接。
JDBC
Java DataBase Connectivity
JDBC是Java程序用于连接不同类型数据库的一套规范。
实际是用Java定义的一套连接数据库时的接口的集合,不同的数据库对其进行了实现。
核心接口
- Connection
-
用于设置要连接的数据库的信息
-
数据库地址
-
用户名
-
密码
-
例如:
//1.加载连接数据库的驱动文件
Class.forName("com.mysql.cj.jdbc.Driver");
//2.定义连接信息(地址、账号、密码)
String url = "jdbc:mysql://localhost:3306/db_game?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
//连接指定数据库,返回值为连接对象
Connection conn = DriverManager.getConnection(url, username, password);
- PreparedStatement
- 预处理结果。用于执行SQL语句
例如:
//3.使用上一步返回的连接对象conn执行指定的sql语句,得到sql预处理对象
String sql = "select * from hero";
PreparedStatement pst = conn.prepareStatement(sql);
3.Result
- 结果集。用于保存执行了查询后的结果集。
例如:
//4.使用上一步返回的预处理对象pst执行查询的方法,得到查询后的结果集
ResultSet res = pst.executeQuery();
//5.循环读取查询到的结果集
while (res.next()) {
//取数据。get数据类型(字段名) 或 get数据类型(字段顺序) 用于获取读取到的一条记录中指定字段的值
int id=res.getInt("id");
String name = res.getString(2);
String sex = res.getString(3);
double price = res.getDouble(4);
Date createDate = res.getDate(5);
String position = res.getString(6);
//将读取出的数据赋值给一个Hero对象的属性
Hero hero = new Hero(id, name, sex, position, price, createDate);
System.out.println(hero);
}
以上的接口都来自于java.sql包中
JDBC具体使用
这里连接mysql,先在项目中导入连接的驱动包。
在项目中新建一个目录,可以命名为lib,将驱动包保存其中后,右键add as libray。
查询
核心方法
-
Class.forName(“class文件权限定名”)
- 加载某个class文件
-
Connection conn = DriverManager.getConnection(url, username, password)
- 连接指定数据,返回连接成功的对象Connection
-
PreparedStatement pst = conn.prepareStatement(sql)
- 预处理sql语句,返回处理后的对象
4.ResultSet res = pst.executeQuery()
- 执行查询,返回一个集合
-
res.next()
- 读取查询到的结果集
6.res.get数据类型(字段名或字段顺序)
- 读取查询到的某个字段的值
7.close()
- 关闭资源,释放资源
例如:
//1.加载连接数据库的驱动文件
Class.forName("com.mysql.cj.jdbc.Driver");
//2.定义连接信息(地址、账号、密码)
String url = "jdbc:mysql://localhost:3306/db_game?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
//连接指定数据库,返回值为连接对象
Connection conn = DriverManager.getConnection(url, username, password);
//3.使用上一步返回的连接对象conn执行指定的sql语句,得到sql预处理对象
String sql = "select * from hero"; PreparedStatement pst = conn.prepareStatement(sql);
//4.使用上一步返回的预处理对象pst执行查询的方法,得到查询后的结果集
ResultSet res = pst.executeQuery();
//5.循环读取查询到的结果集
while (res.next()) {
//取数据。get数据类型(字段名) 或 get数据类型(字段顺序) 用于获取读取到的一条记录中指定字段的值
int id=res.getInt("id");
String name = res.getString(2);
String sex = res.getString(3);
double price = res.getDouble(4);
Date createDate = res.getDate(5);
String position = res.getString(6);
//将读取出的数据赋值给一个Hero对象的属性
Hero hero = new Hero(id, name, sex, position, price, createDate);
System.out.println(hero);
}
//6.释放资源
res.close();
pst.close();
conn.close();
更新(增加、删除、修改)
核心方法
- Class.forName(“class文件权限定名”)
- 加载某个class文件
- Connection conn = DriverManager.getConnection(url, username, password)
- 连接指定数据,返回连接成功的对象Connection
- PreparedStatement pst = conn.prepareStatement(sql)
- 预处理sql语句,返回处理后的对象
- int i = pst.executeUpdate()
- 执行更新,返回受影响的行数
- pst.set数据类型(问号顺序,值)
- 给sql中指定的问号赋值
例如:
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.连接数据库
String url="jdbc:mysql://localhost:3306/db_game?severTimezone=Asia/Shanghai";
Connection conn = DriverManager.getConnection(url, "root", "root");
//3.定义sql对其预处理。使用?表示sql中的参数
String sql="insert into hero values(null,?,default,5000,now(),null)";
PreparedStatement pst = conn.prepareStatement(sql);
//4.使用预处理对象pst对?赋值 调用 set数据类型(index,param) 方法给第index个?赋值
param pst.setString(1,"xxx");
//5.调用数据更新的方法,返回值是受影响的行数
int i = pst.executeUpdate();
if(i!=0){
System.out.println("操作成功");
}else{
System.out.println("操作失败");
}
//6.释放资源
sc.close();
pst.close();
conn.close();
应用
注册,保证不重复
1.查询当前要注册的信息是否存在
- select * from 用户表 where 用户名=‘admin’
2.如果存在(能查询出数据)无法注册;如果不存在(不能查询出数据)才能注册
- insert into 用户表 values(‘admin’,‘123123’)
登录 admin 123123
- 如果能通过给定的用户名和密码查询到数据,说明输入正确;如果查询结果为空,说明用户名或密码有误。
- select * from 用户表 where 用户名=‘admin’ and 密码='123123
注意:登录时的SQL注入问题
- 在SQL语句中尽量不使用字符串拼接
例如:’ or 1=1 – 如果将这个字符串作为用户名输入时,会导致sql语句异常,查询出全部数据
-- 使用姓名和手机登录 如果能查询出结果则进入系统
-- 如果有一个条件不满足,查询结果为空
select * from employee where emp_name='aw' and emp_phone='123'
-- 王茂鑫 18523473566
select * from employee where emp_name='王茂鑫' and emp_phone='18523473566' -- "' or 1=1 -- "
select * from employee where emp_name='' or 1=1 -- ' and emp_phone=''
例子:
package login;
import java.sql.*;
/*
* 注册登录流程
* 注册:
* 1.查询当前要注册的用户名是否存在
* 存在则无法注册
* 2.不存在,执行添加
* 登录:
* 使用用户名和密码查询,如果查询结果为空,说明用户名或密码错误
* */
public class Test {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//register("xxxx", "sdfsdf");
login("' or 1=1 -- ","sdfsdf");
}
/*
* 注册的方法
* */
public static void register(String username, String password) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/db_game?serverTimezone=Asia/Shanghai";
Connection conn = DriverManager.getConnection(url, "root", "root");
//核心sql1:查询用户名是否存在
String sql = "select * from userinfo where username = ?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, username);
ResultSet res = pst.executeQuery();
//如果查询到数据,提前结束
if (res.next()) { //true==true true false==true false
System.out.println("该用户已存在");
return;
}
//核心sql2:添加用户
String sql2 = "insert into userinfo values(null,?,?)";
pst = conn.prepareStatement(sql2);
pst.setString(1, username);
pst.setString(2, password);
if (pst.executeUpdate() > 0) {
System.out.println("注册成功");
}
res.close();
pst.close();
conn.close();
}
public static void login(String username, String password) throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/db_game?serverTimezone=Asia/Shanghai";
Connection conn = DriverManager.getConnection(url, "root", "root");
//登录核心sql:根据用户名密码查询
String sql = "select * from userinfo where username =? and password=?";
PreparedStatement pst = conn.prepareStatement(sql);
/*pst.setString(1, username);
pst.setString(2, password);*/
ResultSet res = pst.executeQuery();
if (res.next()) {
System.out.println("登录成功");
} else {
System.out.println("用户名或密码错误");
}
res.close();
pst.close();
conn.close();
}
}
简化JDBC
DBUtil
定义数据库工具类
package com.hqyj.jdbc_plus.util;
import java.sql.*;
/*
* 数据库工具类
* 用于提取JDBC连接数据库时的公共代码
* //公共代码:
* //1.加载驱动
* //2.获取连接
* //3.释放资源
* */
public class DBUtil {
//静态代码块。在类加载时就执行,只执行一次
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.out.println("加载驱动异常" + e);
}
}
//定义常量保存连接数据库的地址、用户名和密码
private static final String URL = "jdbc:mysql://localhost:3306/db_emp? serverTimezone=Asia/Shanghai";
private static final String NAME = "root";
private static final String PWD = "root";
/** 获取连接对象 * */
public static Connection getConnection() {
Connection connection = null;
try {
connection = DriverManager.getConnection(URL, NAME, PWD);
} catch (SQLException e) {
System.out.println("获取连接异常" + e);
}return connection;
}
/** 释放资源 * */
public static void release(Connection conn, PreparedStatement pst, ResultSet res) {
try {
//非空判断防止空指针异常
if (res != null) {
res.close();
}
if (pst != null) {
pst.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
System.out.println("关闭异常" + e);
}
}
}
用法
package com.hqyj.jdbc_plus.dao;
import com.hqyj.jdbc_plus.entity.Employee;
import com.hqyj.jdbc_plus.util.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.Date;
import java.util.List;
/*
* dao层表示数据库访问层
* 该层中的类都是用于操作数据库
* 类名通常命名为 “实体类Dao” 如HeroDao StudentDao
*
* */
public class EmployeeDao {
//定义操作数据库时所需的接口
Connection conn; PreparedStatement pst; ResultSet res;
/** 查询所有 * 返回值为所有Employee对象的集合 */
public List<Employee> queryAll() {
//创建集合用于最终的返回值
List<Employee> list= new ArrayList<>();
try {
//1.加载驱动
//2.连接
conn = DBUtil.getConnection();
//3.构造sql对其预处理
pst = conn.prepareStatement("select * from employee");
//4.执行sql
res = pst.executeQuery();
//处理查询到的数据
while (res.next()) {
int id = res.getInt(1);
String name = res.getString(2);
String phone = res.getString(3);
Date date = res.getDate(4);
String dept = res.getString(5);
double salary = res.getDouble(6);
String email = res.getString(7);
//将读取到的数据保存为一个对象
Employee employee = new Employee(id, name, phone, date, dept, salary, email);
//将读取到的数据对象保存到集合中
list.add(employee);
}
}catch (SQLException e){
System.out.println("查询所有异常"+e);
}finally {
//5.关闭
DBUtil.release(conn, pst, res);
}
creturn list;
}
//根据id查询员工详细信息
//根据id查询员工详细信息
public Employee queryNo(int empId) {
Employee Employee = null;
try {
conn = DBUtil.getConnection();
pst = conn.prepareStatement("select * from employee where emp_No = ?");
pst.setInt(1, empId);
res = pst.executeQuery();
if (res.next()) {
int id = res.getInt(1);
String name = res.getString(2);
String phone = res.getString(3);
Date date = res.getDate(4);
String dept = res.getString(5);
double salary = res.getDouble(6);
String email = res.getString(7);
Employee = new Employee(id, name, phone, date, dept, salary, email);
}
} catch (SQLException e) {
System.out.println("查询异常!" + e);
} finally {
DBUtil.release(conn, pst, res);
}
return Employee;
}
//3.添加员工
public boolean insertEmp(String empName,String empPhone,double salary){
try{
conn = DBUtil.getConnection();
pst = conn.prepareStatement("insert into employee values(null,?,?,now(),default,?,null)");
pst.setString(1,empName);
pst.setString(2,empPhone);
pst.setDouble(3, salary);
return pst.executeUpdate() > 0;
}catch (SQLException e){
System.out.println("添加异常"+e);
}finally {
DBUtil.release(conn, pst, res);
}
return false;
}
/** 修改工资的方法 * */
public boolean updateSalary(int empNo,double salary){
try {
conn = DBUtil.getConnection();
pst =conn.prepareStatement("update employee set salary=? where emp_no=?");
pst.setDouble(1,salary);
pst.setInt(2,empNo);
return pst.executeUpdate()>0;
}catch (SQLException e){
System.out.println("修改异常");
}finally {
DBUtil.release(conn,pst,res);
}return false;
}
//5.删除员工
public boolean deleteEmp(int empNo){
try {
conn=DBUtil.getConnection();
pst=conn.prepareStatement("DELETE FROM employee WHERE emp_no=?");
pst.setInt(1,empNo);
return pst.executeUpdate() > 0;
}catch (SQLException e){
System.out.println("删除出错!"+e);
}finally {
DBUtil.release(conn, pst, res);
}
return false;
}
}
Main.java
package com.hqyj.jdbc_plus.service;
import com.hqyj.jdbc_plus.dao.EmployeeDao;
import com.hqyj.jdbc_plus.entity.Employee;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
EmployeeDao employeeDao = new EmployeeDao();
Scanner sc = new Scanner(System.in);
System.out.println("1.查询所有员工");
System.out.println("2.根据编号查询员工");
System.out.println("3.添加员工");
System.out.println("4.修改员工");
System.out.println("5.删除员工");
System.out.println("6.退出");
System.out.println("请输入: ");
switch (sc.nextInt()) {
case 1:
List<Employee> list = employeeDao.queryAll();
System.out.println("编号\t姓名");
for (Employee employee : list) {
System.out.println(employee.getEmpNo() + "\t" + employee.getEmpName());
}
break;
case 2:
//根据编号查询员工
System.out.println("请输入员工编号:");
int emoNo=sc.nextInt();
System.out.println(employeeDao.queryNo(emoNo));
break;
case 3:
System.out.println("请输入姓名:");
String empName=sc.next();
System.out.println("请输入电话号码:");
String empPhone=sc.next();
System.out.println("请输入工资:");
double s1=sc.nextDouble();
if(employeeDao.insertEmp(empName,empPhone,s1)){
System.out.println("添加成功!");
}else{
System.out.println("添加失败!");
}
break;
case 4:
//修改工资
System.out.println("请输入员工编号:");
int empNo=sc.nextInt();
System.out.println("输入工资:");
double salary=sc.nextDouble();
if(employeeDao.updateSalary(empNo,salary)){
System.out.println("更新成功!");
}else{
System.out.println("更新失败!");
}
break;
case 5:
System.out.println("请输入员工编号:");
int dempNo=sc.nextInt();
if(employeeDao.deleteEmp(dempNo)){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
break;
case 6:
break;
}
}
}
总结
学习JDBC(Java Database Connectivity)是与数据库进行交互的重要技能。以下是关于JDBC的一些总结要点:
-
JDBC是Java平台上与数据库通信的标准API。它提供了一组接口和类,使Java应用可以与各种数据库进行连接,并执行数据库操作。
-
JDBC的核心接口是
Connection
、Statement
和ResultSet
。Connection
表示与数据库的连接,Statement
用于执行SQL语句,ResultSet
表示查询结果集。 -
JDBC的开发步骤通常包括加载数据库驱动、建立连接、执行查询或更新操作、处理结果集和关闭连接。
-
加载数据库驱动是连接数据库的第一步。可以使用
Class.forName()
方法加载驱动类,也可以通过驱动提供的特定方法(例如DriverManager.registerDriver()
)加载驱动。 -
建立连接使用
DriverManager.getConnection()
方法,该方法接受数据库连接字符串、用户名和密码作为参数。 -
执行查询可以使用
Statement
或PreparedStatement
接口,它们提供了执行SQL语句的方法。PreparedStatement
是Statement
的子接口,支持预编译SQL语句,可以提高性能和安全性。 -
处理结果集可以使用
ResultSet
接口,它提供了访问查询结果的方法。通过调用ResultSet
的next()
方法逐行遍历结果集,并使用getXXX()
方法获取具体的数据。 -
在执行完数据库操作后,应及时关闭连接、释放资源。可以通过调用
close()
方法关闭连接和相关对象,以确保释放数据库资源并防止泄漏。 -
JDBC还支持事务管理,可以使用
Connection
的commit()
和rollback()
方法提交和回滚事务。 -
为了提高性能和安全性,可以使用连接池管理数据库连接,并使用PreparedStatement和批处理方法来执行批量操作。