如果读者对此篇文章有不解可以查看小编JDBC分区下的文章哦,欢迎大家点赞与收藏!
目录
?事务
事务的讲解小编准备从一个故事进行讲起:
创建一个银行(数据库创建,张三:100000,小明:0)
?模拟银行交易(jdbc模拟)
突然发生意外了,程序收钱了,但没有转账给小明?
第一种情况(时间上有延迟,转账后几分钟到)
?第二种情况 程序内部出现问题(钱没了)
结论(记住)
解决办法(在实际开发中,把JDBC的自动提交机制关闭,改为手动提交,三步骤)
第一,先把事务改成手动提交(setAutoCommit(false))
第二,手动提交,关闭事务(commit())
第三步,出现问题,程序进行回滚(rollback())
完整代码
?事务
事务的讲解小编准备从一个故事进行讲起:
话说在很久很久以前发生这样一个故事,地主张三在银行门口打钱给自己儿子小明,自己账户上有100000元,小明没有钱,张三打了50000给儿子,然后就发生了下面这样的事。
创建一个银行(数据库创建,张三:100000,小明:0)
create table t_bank(
id int primary key auto_increment ,
u_name varchar(20) not null ,
money double(10,2)
-- 10是有效数子,2是小数的位数
);
insert into t_bank(u_name , money) value ("zhangsan",100000);
insert into t_bank (u_name,money) value ("xiaoming",0);
select * from t_bank;
?模拟银行交易(jdbc模拟)
package com.luosf.jdbc;
import java.sql.*;
/**
模拟银行转账
*/
public class Jdbc_Transfer {
public static void main(String[] args) {
transfer();
}
static void transfer(){
Connection conn = null;
PreparedStatement prestat = null;
ResultSet res = null;
try {
//1,创建驱动
Class.forName("com.mysql.jdbc.Driver");
//2,链接数据库
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3333/db_nhjc?charset=utf-8","root","root");
//3,获取预编译数据库操作对象
String sql = "update t_bank set money = ? where u_name = ? ";
//此时发送sql语句给DBMS,进行sql语句的编译
prestat = conn.prepareStatement(sql);
//张三给小明转账
prestat.setDouble(1,50000);
prestat.setString(2,"zhangsan");
int count = prestat.executeUpdate();//跟新数据库,当跟新完成后,count+1;
//小明账户到账
prestat.setDouble(1,50000);
prestat.setString(2,"xiaoming");
count += prestat.executeUpdate(); //再次更新,count+1,count=2
System.out.println(count == 2 ? "转账成功" : "转账失败");
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放资源
if (res != null){
try {
res.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (prestat != null){
try {
prestat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
这样就转账完成了
突然发生意外了,程序收钱了,但没有转账给小明?
第一种情况(时间上有延迟,转账后几分钟到)
张三给小明打电话,我钱打给你了,你看看,小明一看,我靠,明没钱这个月要吃土了!
实现
Thread.sleep(20000); //休息20秒,模拟断电了
看看
package com.luosf.jdbc;
import java.sql.*;
/**
模拟银行转账
*/
public class Jdbc_Transfer {
public static void main(String[] args) {
transfer();
}
static void transfer(){
Connection conn = null;
PreparedStatement prestat = null;
ResultSet res = null;
try {
//1,创建驱动
Class.forName("com.mysql.jdbc.Driver");
//2,链接数据库
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3333/db_nhjc?charset=utf-8","root","root");
//3,获取预编译数据库操作对象
String sql = "update t_bank set money = ? where u_name = ? ";
//此时发送sql语句给DBMS,进行sql语句的编译
prestat = conn.prepareStatement(sql);
//张三给小明转账
prestat.setDouble(1,50000);
prestat.setString(2,"zhangsan");
int count = prestat.executeUpdate();//跟新数据库,当跟新完成后,count+1;
Thread.sleep(20000); //休息20秒,模拟断电了
//小明账户到账
prestat.setDouble(1,50000);
prestat.setString(2,"xiaoming");
count += prestat.executeUpdate(); //再次更新,count+1,count=2
System.out.println(count == 2 ? "转账成功" : "转账失败");
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放资源
if (res != null){
try {
res.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (prestat != null){
try {
prestat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
?第二种情况 程序内部出现问题(钱没了)
String s = null;
s.toString();//创建空指针异常
package com.luosf.jdbc;
import java.sql.*;
/**
模拟银行转账
*/
public class Jdbc_Transfer {
public static void main(String[] args) {
transfer();
}
static void transfer(){
Connection conn = null;
PreparedStatement prestat = null;
ResultSet res = null;
try {
//1,创建驱动
Class.forName("com.mysql.jdbc.Driver");
//2,链接数据库
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3333/db_nhjc?charset=utf-8","root","root");
//3,获取预编译数据库操作对象
String sql = "update t_bank set money = ? where u_name = ? ";
//此时发送sql语句给DBMS,进行sql语句的编译
prestat = conn.prepareStatement(sql);
//张三给小明转账
prestat.setDouble(1,50000);
prestat.setString(2,"zhangsan");
int count = prestat.executeUpdate();//跟新数据库,当跟新完成后,count+1;
// Thread.sleep(20000); //休息20秒,模拟断电了
String s = null;
s.toString();//创建空指针异常
//小明账户到账
prestat.setDouble(1,50000);
prestat.setString(2,"xiaoming");
count += prestat.executeUpdate(); //再次更新,count+1,count=2
System.out.println(count == 2 ? "转账成功" : "转账失败");
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放资源
if (res != null){
try {
res.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (prestat != null){
try {
prestat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
?
结论(记住)
JDBC默认情况下是支持自动进行提交的,JDBC执行一条语句就提交一次。(自动提交:执行一条DML,就自动提交一次)
解决办法(在实际开发中,把JDBC的自动提交机制关闭,改为手动提交,三步骤)
进行完一个完整的事务后,全部再一起提交。
第一,先把事务改成手动提交(setAutoCommit(false))
?
?
应该在获取链接对象后,就关闭自动提交机制
//开启事务,将自动提交改变成手动提交
conn.setAutoCommit(false);
第二,手动提交,关闭事务(commit())
//当前面的代码都没有问题,能执行到这,commit()关闭事务,手动提交
conn.commit();
第三步,出现问题,程序进行回滚(rollback())
回滚:简单理解就是倒退,返回最初始的状态
//出现异常,保证安全性,程序进行回滚
try {
if (conn != null){
//防止conn出现空指针异常,先进行判断一下
conn.rollback();
}
}
完整代码
package com.luosf.jdbc;
import java.sql.*;
/**
模拟银行转账
*/
public class Jdbc_Transfer {
public static void main(String[] args) {
transfer();
}
static void transfer(){
Connection conn = null;
PreparedStatement prestat = null;
ResultSet res = null;
try {
//1,创建驱动
Class.forName("com.mysql.jdbc.Driver");
//2,链接数据库
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3333/db_nhjc?charset=utf-8","root","root");
//开启事务,将自动提交改变成手动提交
conn.setAutoCommit(false);
//3,获取预编译数据库操作对象
String sql = "update t_bank set money = ? where u_name = ? ";
//此时发送sql语句给DBMS,进行sql语句的编译
prestat = conn.prepareStatement(sql);
//张三给小明转账
prestat.setDouble(1,50000);
prestat.setString(2,"zhangsan");
int count = prestat.executeUpdate();//跟新数据库,当跟新完成后,count+1;
// Thread.sleep(20000); //休息20秒,模拟断电了
String s = null;
s.toString();//创建空指针异常
//小明账户到账
prestat.setDouble(1,50000);
prestat.setString(2,"xiaoming");
count += prestat.executeUpdate(); //再次更新,count+1,count=2
System.out.println(count == 2 ? "转账成功" : "转账失败");
//当前面的代码都没有问题,能执行到这,commit()关闭事务,手动提交
conn.commit();
} catch (Exception e) {
//出现异常,保证安全性,程序进行回滚
try {
if (conn != null){
//防止conn出现空指针异常,先进行判断一下
conn.rollback();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally {
//释放资源
if (res != null){
try {
res.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (prestat != null){
try {
prestat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
测试
?
?
|