JDBC事务自动提交机制
首先我们先来看一段代码:
package com.guisha.JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/**
* 方法描述
* @since: 1.0.0
* @param:
* @return:
* @author: Mr.cheng
* @date: 2021年1月6日 21点48分
*/
public class JDBCTest_03 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
InputStream input = JDBCTest_03.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//配置文件取值复制给新变量
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注册驱动
Class.forName(driver);
try {
//获取链接
conn = DriverManager.getConnection(url, user, password);
String sql = "UPDATE LOGINNAME SET NAMEPASS = ? WHERE NAME = ? ";
//获取数据库操作对象
ps = conn.prepareStatement(sql);
//添加sql数据
ps.setString(1,"guisha");
ps.setString(2,"Mrcheng");
//执行SQL语句,返回条数
int i = ps.executeUpdate();
System.out.println(i);
ps = conn.prepareStatement(sql);
ps.setString(1,"wuxin");
ps.setString(2,"wuxin");
int i1 = ps.executeUpdate();
System.out.println(i1);
} catch (SQLException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//关闭资源
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
代码中,我们更新2条数据,但是在 int i = ps.executeUpdate(); 这里会自动提交事务,可以理解为提交SQL语句对数据库修改
我们需要了解JDBC的事务是自动提交的,什么是自动提交?
1)只执行任意一条DML语句,则提交一次。JDBC默认的提交方式是自动提交,是JDBC默认的事务行为
2)在实际开发业务中,通常都是N条DML语句共同联合才能完成的,必须保证DML语句在一个事务中同时成功或者同时失败
我们来看一个小例子来验证以下JDBC的事务是否是自动提交机制!
两个人转账的小案例:
package com.guisha.JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/**
* 方法描述
* @since: 1.0.0
* @param:
* @return:
* @author: Mr.cheng
* @date: 2021年1月6日 21点48分
*/
public class JDBCTest_04 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
InputStream input = JDBCTest_04.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//配置文件取值复制给新变量
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注册驱动
Class.forName(driver);
try {
//获取链接
conn = DriverManager.getConnection(url, user, password);
String sql = "UPDATE center_cat SET user_baln = ? WHERE USER_NAME = ? ";
//获取数据库操作对象
ps = conn.prepareStatement(sql);
//添加sql数据
ps.setDouble(1,10000);
ps.setString(2,"小明");
//执行SQL语句,返回条数
int i = ps.executeUpdate();
System.out.println(i);
//自定义NullPointerException
String s = null;
s.toString();
ps.setString(1,"10000");
ps.setString(2,"王老头");
i += ps.executeUpdate();
System.out.println(i);
} catch (SQLException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//关闭资源
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
运行之后会出错,我们程序中定义的 NullPointerException

再查看数据库,数据库执行一半出现异常终止,小明资金共20000,现在能够看出来 小明明学转出的10000元消失不见了,这里就是每执行一条DML语句,事务会自动提交一次

现在我们设置是为手动开启和手动提交,如果中间出现错误,我们回滚数据
代码如下:
package com.guisha.JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/**
* 方法描述
* @since: 1.0.0
* @param:
* @return:
* @author: Mr.cheng
* @date: 2021年1月6日 21点48分
*/
public class JDBCTest_04 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
InputStream input = JDBCTest_04.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//配置文件取值复制给新变量
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注册驱动
Class.forName(driver);
try {
//获取链接
conn = DriverManager.getConnection(url, user, password);
//开启事务
conn.setAutoCommit(false);
String sql = "UPDATE center_cat SET user_baln = ? WHERE USER_NAME = ? ";
//获取数据库操作对象
ps = conn.prepareStatement(sql);
//第一次给?传值
ps.setDouble(1,10000);
ps.setString(2,"小明");
//执行SQL语句,返回条数
int i = ps.executeUpdate();
System.out.println(i);
// 自定义NullPointerException 用来终止正在执行的程序,用于演示JDBC事务自动提交机制的问题
// 想正常实执行代码,请删除自定义自定义NullPointerException异常
String s = null;
s.toString();
//第二次给?传值
ps.setString(1,"10000");
ps.setString(2,"王老头");
i += ps.executeUpdate();
System.out.println(i == 2 ? "转账成功!": "转账失败!");
//提交事务
conn.commit();
} catch (SQLException e) {
/ //数据回滚
if (conn !=null){
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//关闭资源
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
以上代码就算出错,数据会进行回滚,重点使用了conn.setAutoCommit(false)(手动开启事务)、conn.commit()(手动提交事务)和conn.rollback(手动回滚数据)
正常执行如下:
package com.guisha.JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/**
* 方法描述
* @since: 1.0.0
* @param:
* @return:
* @author: Mr.cheng
* @date: 2021年1月6日 21点48分
*/
public class JDBCTest_04 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
InputStream input = JDBCTest_04.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//配置文件取值复制给新变量
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注册驱动
Class.forName(driver);
try {
//获取链接
conn = DriverManager.getConnection(url, user, password);
//开启事务
conn.setAutoCommit(false);
String sql = "UPDATE center_cat SET user_baln = ? WHERE USER_NAME = ? ";
//获取数据库操作对象
ps = conn.prepareStatement(sql);
//第一次给?传值
ps.setDouble(1,10000);
ps.setString(2,"小明");
//执行SQL语句,返回条数
int i = ps.executeUpdate();
System.out.println(i);
//第二次给?传值
ps.setString(1,"10000");
ps.setString(2,"王老头");
i += ps.executeUpdate();
System.out.println(i == 2 ? "转账成功!": "转账失败!");
//提交事务
conn.commit();
} catch (SQLException e) {
if (conn !=null){
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//关闭资源
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
