JDBC
一、引言
1.1 如何操作数据
使用客户端工具访问数据库,需要手工建立链接,输入用户名和密码登陆,编写SQL语句,点击执行,查看操作结果(结果集或受影响行数)。
1.2实际开发中,会采用客户端操作数据库吗?
在实际开发过程中,当用户的数据发生改变时,不会通过客户端操作执行SQL语句,因为操作量过大,无法保证效率和正确性。
二、JDBC (JAVA DATABASE CONNECTIVITY)
2.1 什么是JDBC?
JDBC(Java DataBase Connectivity) JAVA 连接数据库,可以使用Java语言连接数据库完成CRUD操作
2.2 JDBC核心思想
JAVA 中定义了访问数据库的而接口,可以为多种关系型数据库提供了统一的访问方式
由数据库厂商提供数据库驱动实现类(Driver驱动)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sz7KqPgm-1585619491326)(C:\Users\fanhu\AppData\Roaming\Typora\typora-user-images\1585381106311.png)]](https://i-blog.csdnimg.cn/blog_migrate/6c7ecec0797470d6e2c8f48b0e249249.png)
2.2.1 MySQL 数据库驱动
- mysql-connector-java-5.1.x 适用于5.x版本
- mysql-connector-java-8.0.x 适用于8.x 版本
2.2.2 JDBC API
JDBC 是由多个接口和类进行功能实现
| 类型 | 全限定名 | 简介 |
|---|---|---|
| class | java.sql.DriverManage | 管理多个数据库驱动类,提供了获取数据库连接的方法 |
| interface | java.sql.Connection | 代表一个数据库连接(当Connection不是NULL时,标识已连接一个数据) |
| interface | java.sql.Statement | 发送SQL语句到数据库的工具 |
| interface | java.sql.ResultSet | 保存SQL查询语句的结果数据(结果集) |
| class | java.sql.SQLException | 处理数据库应用程序时所发生的异常 |
2.3 环境搭建
1.在项目中创建一个lib文件夹用于存放jar文件
2.将jar包放输入lib文件夹下
3.将lib文件夹作为library
三、JDBC开发步骤[重点]
3.1 注册驱动
使用Class.forName(“com.mysql.jdbc.Driver”)手动加载字节码文件到JVM中
Class.forName("com.mysql.jdbc.Driver");
3.2 连接数据库
- 通过DriverManager.getConnection(url,user,password) 获得数据库连接对象
- URL:jdbc:mysql://主机名(ip):端口号/数据库名
- user:用户名
- password:密码
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8","root","123");
3.3 获取发送SQL的对象
通过Connection对象获得Statement对象,用于对数据库进行通用访问的
Statement statement = connection.createStatement();
3.4执行SQL语句
编写SQL语句,并执行,接收执行后的数据
int result = statement.executeUpdate("update stu set student_name='李敢敢',sex='女' where
student_id = 'S1003'");
3.5处理结果
接收并处理操作结果
if(result > 0){
System.out.println("执行成功");
}
3.6释放资源
遵循的是先开后关的原则,释放过程中用到的资源连接
statement.close()
connection.close()
3.7综合案例
综合六步:实现增删改
public class BasicJDBC {
public static void main(String[] args) {
try {
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 连接数据库
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf-8","root","root");
// 获取发送SQL对象
Statement statement = connection.createStatement();
// 编写SQL语句,执行SQL语句(返回受影响行数)
String sql = "";
int i = statement.executeUpdate(sql);
//处理数据
if(i>0){
System.out.println("执行成功");
}
//释放资源
statement.close();
connection.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
四、ResultSet(结果集)
在执行查询SQL后,存放查询到的查询结果集数据
4.1接收结果集
ResultSet rs = statement.executeQuery(sql)
Result rs =statement.executeQuery("");
4.2 遍历ResultSet中的数据
ResultSet以表(Table)结构进行临时结果的存储,需要通过JDBC API将其中的数据进行依此获取
- 数据行指针:初始位置在第一行数据前,没调用依此boolean next()方法,ResultSet中指针向下移动一行,结果true,表示当前行有数据
- rs.getXxx(“列名”); 根据列名获得数
- rs.getXxx(“整数下标”);根据列的编号舒徐获得!从1开始
boolean next() throws SQLException;//判断rs结果集中下一行是否有数据
4.2.1遍历方法
int getInt(int columnIndex) throws SQLException;// 获取当前行的第N列的int值
int getInt(String columnLabel) throws SQLException;//获得当前行column
4.3综合案例
对stu表所有数据进行遍历
4.3.1根据列的名称进行遍历
public class TestDql {
public static void main(String[] args) {
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获得连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companyDB?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
//3.获得SQL执行对象
Statement statement = connection.createStatement();
//4.执行SQL语句
String sql = "select * from `Student`";
ResultSet resultSet = statement.executeQuery(sql);
//5.对结果集进行处理
while(resultSet.next()){ // 判断结果集中是否有下一行!
// 根据列名获取当前行的每一列数据
String id= (String)resultSet.getObject("student_id");
String name = (String)resultSet.getObject("student_name");
String sex = (String)resultSet.getObject("sex");
Date borndate = resultSet.getDate("borndate");
String phone = (String)resultSet.getObject("phone");
Integer gradeid = (Integer)resultSet.getObject("GradeId");
System.out.println(id+"\t"+name+"\t"+sex+"\t"+borndate.toString()+"\t"+phone+"\t"+gradeid);
}
//6.释放资源
resultSet.close();
statement.close();
connection.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
4.3.2根据列的编号获取
public class BasicJDBC {
public static void main(String[] args) {
try {
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 连接数据库
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
// 获取发送SQL对象
Statement statement = connection.createStatement();
// 编写SQL语句,执行SQL语句(返回受影响行数)
String sql = "";
int i = statement.executeUpdate(sql);
//处理数据
if(i>0){
System.out.println("执行成功");
}
//释放资源
statement.close();
connection.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
五、常见的错误
- java.lang.ClassNotFoundException 找不到类 或者 没有导入jar包
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unkonen colum ‘列名’ 与SQL语句相关的错误(表名 列名 书写错误 、约束错误、插入的值是String类型,但是没有加单引号)
- com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry ‘S1003’ for key ‘PRIMARY’ 原因:主键值已经存在!更改要插入的主键值
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unknown column ‘password’ in
- 可能输入的值的类型不对,确定插入元素时,对应的值的类型是否争取
六、综合案例登陆
6.1创建表
- 创建一张用户表User
- id:主键 自增长
- username 字符串类型 非空
- password 字符串类型 非空
- phone 字符串类型 11为
- 插入两条数据
6.2实现登录
- 通过控制台,用户输入用户名和密码
- 用户输入的用户名和密码作为参数,编写SQL语句
- 如果查询到用户,则用户存在,提示登陆成功,反之,提示失败
七、SQL注入问题
7.1什么是SQL注入
当用户输入的数据中有SQL关键字或语法时,并且参与了SQL语法的编译,导致SQL语句编译后条件结果为true时
7.2 如何避免SQL注入
由于编写的SQL语句,是在用户输入数据后,整合后再编译成SQL语句。所以为了避免SQL注入的问题,使得SQL语句再用户输入数据前,SQL语句已经完成编译,成为了完整的SQL语句,在进行填充数据。
八、PreparedStatement[重点]
PreparedStatement接口继承了Statement接口,执行SQL语句的方法没有区别!
8.1 PreparedStatement 的应用
作用:1.预编译SQL语句,效率高!
2.安全,可以避免SQL注入
3.可以动态的填充数据,执行多个同构的SQL语句
8.1.1参数标记
//1.预编译SQL语句
PreparedStatement pstms = connection.prepareStatement(sql);
8.1.2 动态参数绑定
pstmt.setXxx(下标,值); 参数下标是从1开始,为指定占位符下标绑定值
//2.为占位符下标赋值
pstm.setString(1,username)
pstm.setString(2,password)
九、综合练习
9.1创建数据库、表
数据库 Account
- 创建一张表Account,有以下列
- cardId:字符串,主键
- password:字符串,非空
- username,字符串,非空
- balance:小数,非空
- phone:字符串,非空
9.2.创建项目通过JDBC实现功能
创建AccountSystem类,完成下列功能
- 开户:控制台输入所有的账户信息,使用PreparedStatement添加至t_account表
- 存款:控制台输入卡号、密码、存储金额进行修改
- 取款:输入卡号、密码、取款金额
- 转账:输入卡号、密码、对方卡号、转账金额进行修改
- 修改密码:控制台输入卡号、密码、在输入新密码进行修改
- 注销:控制台输入卡号、密码,删除对应的账户信息
创建表
CREATE DATABASE if not exists Account CHARACTER SET utf8;
USE Account;
CREATE TABLE t_account(
`cardId` VARCHAR(20) PRIMARY KEY not null,
`password` varchar(20) not null,
`balance` DOUBLE NOT NULL,
`phone` varchar(11)
)charset=utf8;
try-catch ctrl+alt+t
代码格式化 ctrl+alt+L
快速定位异常处: F2
package com.qfedu.jdbc.t4;
import java.sql.*;
import java.util.Scanner;
public class AccountSystem {
Scanner scanner = new Scanner(System.in);
private static Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
static {
// 1.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
// 2.创建数据库连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/Account?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
// 开户
public void regiter(){
System.out.println("请输入卡号:");
String cardId = scanner.next();
System.out.println("请输入密码");
String password = scanner.next();
System.out.println("请输入用户名");
String username = scanner.next();
System.out.println("请输入存款金额");
String balance = scanner.next();
System.out.println("请输入预留手机号码:");
String phone = scanner.next();
try {
//3.创建Preparement
String sql ="insert into `t_account`(`cardId`,`password`,`username`,`balance`,`phone`) values(?,?,?,?,?)";
preparedStatement = connection.prepareStatement(sql);
//4.为占位符赋值
preparedStatement.setString(1,cardId);
preparedStatement.setString(2,password);
preparedStatement.setString(3,username);
preparedStatement.setString(4,balance);
preparedStatement.setString(5,phone);
//5.执行SQL语句
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("开户成功");
}else{
System.out.println("开户失败");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if(preparedStatement!=null){
preparedStatement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 更新
public void saveMoney(){
System.out.println("请输入卡号:");
String cardId = scanner.next();
System.out.println("请输入密码:");
String pasword = scanner.next();
System.out.println("请输入存款金额");
double money = scanner.nextDouble();
if(money > 0){
//存款操作
String sql = "update t_account set balance = balance + ? where cardId=? and password=?";
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setDouble(1,money);
preparedStatement.setString(2,cardId);
preparedStatement.setString(3,pasword);
// 执行,接收返回结果
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("存款成功");
}else{
System.out.println("存款失败!用户名和密码请核对!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}else{
System.out.println("您输入的金额不正确");
}
}
// 取款
public void takeMoney(){
System.out.println("请输入卡号:");
String cardId = scanner.next();
System.out.println("请输入密码:");
String password = scanner.next();
System.out.println("请输入取款金额");
double money = scanner.nextDouble();
if(money > 0){
String sql = "select balance from t_account where cardId=? and password=?";
try {
preparedStatement =connection.prepareStatement(sql);
preparedStatement.setString(1,cardId);
preparedStatement.setString(2,password);
resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
double balance = resultSet.getDouble(1);
if(money<=balance){
//取款成功
String sql2="update t_account set balance = balance-? where cardId=? and password=?";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.setDouble(1,money);
preparedStatement.setString(2,cardId);
preparedStatement.setString(3,password);
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("取款成功!");
}else{
System.out.println("取款失败!");
}
}else{
System.out.println("余额不足!");
}
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}else{
System.out.println("输入金额有误!");
}
}
// 转账
public void transferAccountS() {
System.out.println("请输入转账方卡号:");
String cardId = scanner.next();
System.out.println("请输入转账方密码:");
String pasword = scanner.next();
System.out.println("请输入转账金额");
double money = scanner.nextDouble();
System.out.println("请输入接收方卡号:");
String cardId2 = scanner.next();
// 确定转账金额大于0
if(money > 0){
// 查询转账方是否存在
String sql = "select balance from t_account where password=? and cardId=?";
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,pasword);
preparedStatement.setString(2,cardId);
resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
// 账号密码存在
double aDouble = resultSet.getDouble(1);
// 判断转账金额是否小于银行卡金额
connection.setAutoCommit(false);
if(aDouble >= money){
// 关闭事务的自动提交
// 减钱
String sql2="update t_account set balance = balance-? where password=? and cardId=?";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.setDouble(1,money);
preparedStatement.setString(2,pasword);
preparedStatement.setString(3,cardId);
int num1 = preparedStatement.executeUpdate();
// 加钱
String sql3="update t_account set balance = balance+? where cardId=?";
preparedStatement = connection.prepareStatement(sql3);
preparedStatement.setDouble(1,money);
preparedStatement.setString(2,cardId2);
int num2 = preparedStatement.executeUpdate();
if(num1>0 && num2>0){
System.out.println("转账成功!");
}else {
System.out.println("转账失败");
}
connection.commit();
}else{
System.out.println("余额不足");
}
}else{
System.out.println("账号或密码不存在");
}
} catch (SQLException e) {
try {
if(connection!=null){
connection.rollback();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
try {
connection.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 转账金额是否小于卡内余额
//
}else{
System.out.println("转账金额输入有误");
}
}
// 关闭Connection
public void closeConnection(){
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 修改密码
public void changePassword() {
System.out.println("请输入卡号:");
String cardId = scanner.next();
System.out.println("请输入密码:");
String password = scanner.next();
String sql = "select * from t_account where cardId=? and password=?";
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,cardId);
preparedStatement.setString(2,password);
ResultSet resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
System.out.println("用户名密码正确");
System.out.println("请输入新密码:");
String newPassword = scanner.next();
System.out.println("请再次输入新密码:");
String newRewardPassword = scanner.next();
if(newPassword.equals(newRewardPassword)){
String sql1 ="update t_account set password=? where cardId=?";
preparedStatement = connection.prepareStatement(sql1);
preparedStatement.setString(1,newRewardPassword);
preparedStatement.setString(2,cardId);
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("修改成功");
}else{
System.out.println("修改失败");
}
}else{
System.out.println("两次密码输入不一致,修改失败!");
}
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
// 注销
public void writeOff() {
System.out.println("请输入卡号:");
String cardId = scanner.next();
System.out.println("请输入密码:");
String password = scanner.next();
String sql = "select * from t_account where cardId=? and password=?";
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,cardId);
preparedStatement.setString(2,password);
boolean execute = preparedStatement.execute();
if(execute){
System.out.println("是否一定要注销此账号? 1.是 2.否");
int result = scanner.nextInt();
if(result==1){
// 确认注销
String sql1 ="delete from t_account where cardId=?";
preparedStatement =connection.prepareStatement(sql1);
preparedStatement.setString(1,cardId);
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("销户成功!");
}else{
System.out.println("销户失败!");
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
package com.qfedu.jdbc.t4;
import java.util.Scanner;
public class TestAccount {
public static void main(String[] args) {
AccountSystem as = new AccountSystem();
Scanner in = new Scanner(System.in);
System.out.println("欢迎进入此系统");
int choice = 0;
do{
System.out.println("1、开户 2、存款 3、取款 4、转账 5、修改密码 6、注销 0、退出");
System.out.println("请选择");
choice = in.nextInt();
switch (choice){
// 开户
case 1:
as.regiter();
break;
// 存款
case 2:
as.saveMoney();
break;
// 取款
case 3:
as.takeMoney();
break;
// 转账
case 4:
as.transferAccountS();
break;
// 修改密码
case 5:
as.changePassword();
break;
// 注销
case 6:
as.writeOff();
break;
case 0: as.closeConnection();return;
default:
System.out.println("暂无此功能");
return;
}
}while(choice!=0);
}
}
本文详细介绍了Java数据库连接(JDBC)的基本概念、环境搭建、核心API及开发步骤,包括使用PreparedStatement避免SQL注入,以及通过综合案例展示账户系统功能实现。
533

被折叠的 条评论
为什么被折叠?



