JavaWeb后端入门1
一、前期准备
1、数据库的安装
此次测试使用的版本为mysql-5.5.62-win64
,下载链接如下
普通网络 | 北京电信 | 辽宁电信 |
---|
安装说明:点击查看
2、Java jdk安装
使用官网下载的jdk-15.0.2_windows-x64_bin
3、Eclipse安装
4、mysql的java驱动包
mysql驱动包为mysql-connector-java-5.1.7-bin.jar
点击下载
二、基本使用
2.1创建工程,引入jar包
2.2 JDBC开发步骤
加载驱动
获得链接
基本操作(创建操作对象、编写SQL、执行SQL)
释放资源
2.3代码实现(仅为演示,不标准)
SRC目录下新建包,新建类
package com.itheima.jdbc.demo1;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Test;
//JDBC入门程序
public class JDBCDemo1 {
@Test
public void demo1() throws Exception {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获得链接
Connection conn = DriverManager.getConnection("jdbc:mysql://IP:3306/数据库名", "数据库用户名", "数据库密码");
//3.基本操作 SQL语句
//3.1获取执行SQL语句的对象
Statement Statement = conn.createStatement();
//3.2编写SQL语句
String sql = "select * from user";
//3.3执行SQL
ResultSet rs = Statement.executeQuery(sql);
//3.4遍历结果集
while(rs.next()) {
System.out.print(rs.getInt("id")+" ");
System.out.print(rs.getString("username")+" ");
System.out.print(rs.getString("password")+" ");
System.out.print(rs.getString("nickname")+" ");
System.out.print(rs.getInt("age"));
System.out.println();
}
//4.释放资源
rs.close();
Statement.close();
conn.close();
}
}
三、JDBC的常用API
3.1 Drivermanager接口
作用有两个:注册驱动、获得连接
注册驱动:一般不使用这个API注册驱动,而是采取以下语句注册
代码语言:javascript代码运行次数:0运行复制Class.forName("com.mysql.jdbc.Driver");
获得连接:使用getconnection方法
代码语言:javascript代码运行次数:0运行复制Connection conn = DriverManager.getConnection("jdbc:mysql://IP:3306/数据库名", "user", "password");
如果为本地的数据库,且端口为3306,则localhost:3306可以省略,即url部分可以简化为jdbc:mysql:///数据库名
3.2 Connection接口
作用有两个:创建执行SQL语句的对象、管理事务
创建对象:createStatement( )方法、prepareCall( )方法、prepareStatement( )方法
Statement用来执行SQL语句、CallableStatement用来执行数据库中的存储过程、PrepareStatement用来执行SQL语句,预处理,解决SQL注入漏洞
管理事务:setAutoCommit方法、commit方法、rollback方法
3.3 Statement接口
作用:执行SQL语句、执行批处理
①执行SQL语句:execute方法、executeQuery方法、executeUpdate方法
boolean execute(string sql)查询、修改、添加、删除,返回true
ResultSet executeQuery(string sql)执行查询select语句
int executeUpdate(string sql)执行修改,添加,删除,返回修改的行数
②执行批处理语句:addBatch语句、clearBatch语句、executeBatch语句
3.4 ResultSet接口
**只有select查询才会有ReslutSet结果,
一般使用getxxx( )方法的重载
代码语言:javascript代码运行次数:0运行复制ResultSet rs = statement.executeQuery(sql);
rs.getint("age");
rs.getString("name");
四、资源回收
代码语言:javascript代码运行次数:0运行复制if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
五、增删改查(CRUD)、提取抽象类、从配置文件提取配置信息
5.1CRUD——增加
代码语言:javascript代码运行次数:0运行复制package com.itheima.jdbc.demo2;
/*IDBC的增删改查*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
public class JDBCDemo2 {
public void demo1() {
//1.定义
Connection conn = null;
Statement stmt = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://ip:3306/web_test3", "root", "password");
//执行操作:
//创建执行SQL语句的对象
stmt = conn.createStatement();
//编写SQL
String sql = "insert into user values (null,'eee','123','阿黄','21')";
//执行SQL
int num = stmt.executeUpdate(sql);
if(num>0) {
System.out.println("保存用户成功!");
}else {
System.out.println("失败!");
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
}
}
}
5.2 CRUD——修改
代码语言:javascript代码运行次数:0运行复制@Test
//修改操作的代码实现
public void Demo2() {
Connection conn = null;
Statement stmt = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://ip:3306/web_test3", "root", "password");
//执行操作
//创建对象
stmt = conn.createStatement();
//编写sql
String sql = "update user set password= 'abc',nickname='旺财' where id =5";
//执行SQL
int num = stmt.executeUpdate(sql);
if (num>0) {
System.out.println("修改信息成功!");
}else {
System.out.println("修改失败!");
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
}
}
5.3 CRUD——删除
代码语言:javascript代码运行次数:0运行复制@Test
//删除操作
public void Demo3() {
Connection conn = null;
Statement stmt = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://ip:3306/web_test3", "root", "password");
//执行操作
//获得对象
stmt = conn.createStatement();
//编写SQL
String sql = "delete from user where id = 6";
//执行SQL
int num = stmt.executeUpdate(sql);
if (num > 0 ) {
System.out.println("删除成功!");
}else {
System.out.println("删除失败");
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
}
}
5.4 CRUD——查询多条记录
代码语言:javascript代码运行次数:0运行复制@Test
//查询多条记录
public void Demo4() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://ip:3306/web_test3", "root", "password");
//执行操作
//创建执行SQL语句的对象
stmt = conn.createStatement();
//编写SQL
String sql = "select * from user";
//执行SQL
rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getInt("id")+ " "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname")+" "+rs.getInt("age"));
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
rs = null;
}
}
}
5.5 CRUD——查询一条记录
代码语言:javascript代码运行次数:0运行复制@Test
//查询一条记录
public void Demo5() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://ip:3306/web_test3", "root", "password");
//执行操作
//创建执行SQL语句的对象
stmt = conn.createStatement();
//编写SQL
String sql = "select * from user where id =4";
//执行SQL
rs = stmt.executeQuery(sql);
if (rs.next()) {
System.out.println(rs.getInt("id")+ " "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname")+" "+rs.getInt("age"));
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
rs = null;
}
}
}
5.6 提取抽象类
把数据连接、数据释放封装成一个类
新建一个utils包,包下新建一个JDBCUtils.java
类(下面程序的代码都是基于这个类)
package com.itheima.jdbc.utils;
/*JDBC工具类*/
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
*注册驱动的方法
**/
public static void loadDriver() {
try {
Class.forName(driverClassName);
} catch (ClassNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
/**
*获得链接的方法
**/
public static Connection getConnection() {
Connection conn=null;
try {
//将驱动注册
loadDriver();
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://ip:3306/web_test3", "root", "password");
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return conn;
}
/**
*资源释放的方法
**/
public static void release(Statement stmt,Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
}
public static void release(ResultSet rs,Statement stmt,Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
rs = null;
}
}
}
5.7 读取配置文件中的数据
将数据库ip、用户名、密码等数据写在配置文件中,这样当数据库发生改变时,不需要修改源代码即可实现。
①src目录下新建db.properties
文件,采用键值对的形式书写。
driverClassName=com.mysql.jdbc.Driver
url = jdbc:mysql://ip:3306/web_test3
username= root
password = 密码
②在 JDBCUtils.java
类中加入以下内容
public class JDBCUtils {
private static final String driverClassName;
private static final String url;
private static final String username;
private static final String password;
static {
//获取属性文件中的内容
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src/db.properties"));
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
driverClassName= properties.getProperty("driverClassName");
url= properties.getProperty("url");
username= properties.getProperty("username");
password= properties.getProperty("password");
}
六、SQL注入漏洞及解决
6.1代码演示
创建一个java类,命名为UserDao.java
package com.itheima.jdbc.demo4;
/*
* 基本登录功能
* */
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import com.itheima.jdbc.utils.JDBCUtils;
public class UserDao {
public boolean login(String username,String password) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//定义一个变量
boolean flag = false;
try {
//获得连接
conn = JDBCUtils.getConnection();
//完成登录功能
//创建执行SQL语句的对象
stmt = conn.createStatement();
//编写SQL语句
String sql = "select * from user where username= '"+username+"' and password = '"+password+"'";
//执行SQL语句
rs=stmt.executeQuery(sql);
if (rs.next()) {
//说明根据用户名和密码可以查询到这条记录
flag = true;
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
JDBCUtils.release(rs, stmt, conn);
}
return flag;
}
}
登录测试
代码语言:javascript代码运行次数:0运行复制package com.itheima.jdbc.demo4;
/*
* SQL注入漏洞
* */
import org.junit.Test;
public class JDBCDemo4 {
@Test
/*注入漏洞演示*/
public void demo1() {
UserDao userDao = new UserDao();
// boolean flag = userDao.login("aaa'or'1=1", "123123");
// boolean flag = userDao.login("aaa'-- ", "123123");
boolean flag = userDao.login("aaa'-- ", "123123");
if (flag) {
System.out.println("登陆成功!");
}else {
System.out.println("登陆失败!");
}
}
}
用户名为aaa' or ' 1=1
或者aaa' --
即使随意输入密码也会登录成功。
6.2解决方法
使用preparedstatement
方法, UserDao.java
改为:
public boolean login(String username,String password) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
boolean flag=false;
try {
//获得连接
conn = JDBCUtils.getConnection();
//编写SQL
String sql = "select * from user where username = ? and password = ?";
//预编译SQL
pstmt = conn.prepareStatement(sql);
//设置相关参数
pstmt.setString(1, username);
pstmt.setString(2, password);
//执行SQL
rs = pstmt.executeQuery();
if (rs.next()) {
//说明根据用户名和密码可以查询到这条记录
flag = true;
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
JDBCUtils.release(rs, pstmt, conn);
}
return flag;
}
}
七. PrepareStatement的CRUD操作
直接放代码
代码语言:javascript代码运行次数:0运行复制package com.itheima.jdbc.demo2;
/*JDBC的增删改查*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
public class JDBCDemo2 {
@Test
//查询一条记录
public void Demo5() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://43.226.152.21:3306/web_test3", "root", "Qq1991101313");
//执行操作
//创建执行SQL语句的对象
stmt = conn.createStatement();
//编写SQL
String sql = "select * from user where id =4";
//执行SQL
rs = stmt.executeQuery(sql);
if (rs.next()) {
System.out.println(rs.getInt("id")+ " "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname")+" "+rs.getInt("age"));
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
rs = null;
}
}
}
@Test
//查询多条记录
public void Demo4() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://43.226.152.21:3306/web_test3", "root", "Qq1991101313");
//执行操作
//创建执行SQL语句的对象
stmt = conn.createStatement();
//编写SQL
String sql = "select * from user";
//执行SQL
rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getInt("id")+ " "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname")+" "+rs.getInt("age"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
rs = null;
}
}
}
@Test
//删除操作
public void Demo3() {
Connection conn = null;
Statement stmt = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://43.226.152.21:3306/web_test3", "root", "Qq1991101313");
//执行操作
//获得对象
stmt = conn.createStatement();
//编写SQL
String sql = "delete from user where id = 6";
//执行SQL
int num = stmt.executeUpdate(sql);
if (num > 0 ) {
System.out.println("删除成功!");
}else {
System.out.println("删除失败");
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
}
}
@Test
//修改操作的代码实现
public void Demo2() {
Connection conn = null;
Statement stmt = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://43.226.152.21:3306/web_test3", "root", "Qq1991101313");
//执行操作
//创建对象
stmt = conn.createStatement();
//编写sql
// String sql = "update user set password= 'abc',nickname='旺财' where id =5";
String sql = "update user set password= 'abc',nickname='旺财' where id =5";
//执行SQL
int num = stmt.executeUpdate(sql);
if (num>0) {
System.out.println("修改信息成功!");
}else {
System.out.println("修改失败!");
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
}
}
@Test
//保存操作的代码实现
public void demo1() {
//1.定义
Connection conn = null;
Statement stmt = null;
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得链接
conn = DriverManager.getConnection("jdbc:mysql://43.226.152.21:3306/web_test3", "root", "Qq1991101313");
//执行操作:
//创建执行SQL语句的对象
stmt = conn.createStatement();
//编写SQL
String sql = "insert into user values (null,'eee','123','阿黄','21')";
//执行SQL
int num = stmt.executeUpdate(sql);
if(num>0) {
System.out.println("保存用户成功!");
}else {
System.out.println("失败!");
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
stmt = null;
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
conn = null;
}
}
}
}
八. JDBC的批处理操作
8.1 什么是批处理
之前进行JDBC操作的时候,都是一条SQL语句执行。使用批处理,可以将一批SQL一起执行。
8.2 基本使用方法
不使用PreparedStatement方法
代码语言:javascript代码运行次数:0运行复制public class JDBCDemo6 {
@Test
/*
*没有使用PreparedStatement方法
*
**/
public void demo1() {
Connection conn = null;
Statement stmt = null;
try {
//获得连接
conn = JDBCUtils.getConnection();
//创建执行批处理的对象:Statement
stmt = conn.createStatement();
//编写一批SQL语句
String sql1 = "create database test1";
String sql2 = "use test1";
String sql3 = "create table user(id int primary key auto_increment,name varchar(20))";
String sql4 = "insert into user values (null,'aaa')";
String sql5 = "insert into user values (null,'bbb')";
String sql6 = "insert into user values (null,'ccc')";
String sql7 = "update user set name = 'mmm' where id =2";
String sql8 = "delete from user where id =1";
//添加到批处理
stmt.addBatch(sql1);
stmt.addBatch(sql2);
stmt.addBatch(sql3);
stmt.addBatch(sql4);
stmt.addBatch(sql5);
stmt.addBatch(sql6);
stmt.addBatch(sql7);
stmt.addBatch(sql8);
//执行批处理
stmt.executeBatch();
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(stmt, conn);
}
}
}
使用 PreparedStatement方法
注意默认情况下MySQL的批处理是没有开启的,需要在url后面拼接一个参数 ?rewriteBatchedStatements=true
!!
public class JDBCDemo6 {
/*使用PreparedStatement插入*/
//默认情况下MySQL的批处理是没有开启的,需要在url后面拼接一个参数
@Test
public void demo2() {
//记录一下插入数据使用的时间
//开始时间
long begin = System.currentTimeMillis();
Connection conn = null;
PreparedStatement pstmt = null;
try {
//获得连接
conn = JDBCUtils.getConnection();
//编写SQL语句
String sql = "insert into user values (null,?)";
//预编译SQL
pstmt = conn.prepareStatement(sql);
for(int i=1;i<=10000;i++) {
pstmt.setString(1, "name"+i);
//添加到批处理
pstmt.addBatch();
//注意问题:一次性处理太多数据有可能会导致内存溢出
//执行批处理,每执行1000次,清除内存
if (i%1000 == 0) {
//执行批处理
pstmt.executeBatch();
//清空批处理
pstmt.clearBatch();
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(pstmt, conn);
}
long end = System.currentTimeMillis();
System.out.print("数据插入时间为(单位ms):");
System.out.println(end-begin);
}
}
九. 事务管理
9.1 事务的概念
事务指的是逻辑上的一组操作,组成这组操作各个逻辑单元要么全都成功,要么全都失败。
9.2 事务环境的准备
- 创建数据库和表
create database web_test4;
use web_test4;
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
insert into account values(null,'aaa',10000);
insert into account values(null,'bbb',10000);
insert into account values(null,'ccc',10000);
- 转账案例代码实现
package com.itheima.trasaction.demo1;
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.itheima.jdbc.utils.JDBCUtils;
/*
* 事务管理测试类
* */
public class TransactionDemo1 {
@Test
/*
* 完成转账案例
* */
public void demo1() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//获取连接
conn = JDBCUtils.getConnection();
//编写SQL
/*转账代码,一个账户扣钱,一个账户加钱:用aaa账号给 bbb账号转1000
* */
String sql = "update account set money = money +? where name = ?";
//预编译SQL
pstmt = conn.prepareStatement(sql);
//设置参数
pstmt.setDouble(1, -1000);
pstmt.setString(2, "aaa");
//执行SQL:扣除aaa账号1000
pstmt.executeUpdate();
/* ########################################################## */
//给bbb增加1000
pstmt.setDouble(1, 1000);
pstmt.setString(2, "bbb");
pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.release(pstmt, conn);
}
}
}
此时如果认为在###处增加一个错误,那么会发生以下情况:aaa的钱被转走了,但是bbb的钱没有增加
- 添加事务管理
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
import com.itheima.jdbc.utils.JDBCUtils;
/*
* 事务管理测试类
* */
public class TransactionDemo1 {
@Test
/*
* 完成转账案例
* */
public void demo1() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//获取连接
conn = JDBCUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//编写SQL
/*转账代码,一个账户扣钱,一个账户加钱:用aaa账号给 bbb账号转1000
* */
String sql = "update account set money = money +? where name = ?";
//预编译SQL
pstmt = conn.prepareStatement(sql);
//设置参数
pstmt.setDouble(1, -1000);
pstmt.setString(2, "aaa");
//执行SQL:扣除aaa账号1000
pstmt.executeUpdate();
/* #######################人为发生异常########################## */
int i =1/0;
/* ########################################################## */
//给bbb增加1000
pstmt.setDouble(1, 1000);
pstmt.setString(2, "bbb");
pstmt.executeUpdate();
//提交事务
connmit();
} catch (Exception e) {
//发生异常时回滚
try {
conn.rollback();
} catch (SQLException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JDBCUtils.release(pstmt, conn);
}
}
}
此时在在中间发生异常之后,aaa的钱也不会减少。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2021-04-07 ,如有侵权请联系 cloudcommunity@tencent 删除后端入门eclipsejdbcnull