兄弟们,今日头条搜索
三线城市程序员老陈
关注我,我将持续不断推出视频教程。
Spring事务是对原生事务的封装,我们还是需要了解如果直接使用JDBC的话,如何实现事务。
我们将向blog表插入两条数据(两次更新操作)定义为一个原子性操作,所以我们是期望这两个操作能同时成功、或者同时失败的。
如果不使用事务,有可能会发生一个操作成功、另一个操作失败的情况,所以我们预期的原子性操作不成立。代码如下,可以看出因为执行过程中出现异常,导致最终只插入了一条数据,数据的完整性保护失败。
package org.maoge.jdbctran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* 原生JDBC事务使用实例
*/
public class JdbcTransactionDemo {
public static void main(String[] args) {
actionWithoutTransaction();
}
/**
* 未使用事务
*/
public static void actionWithoutTransaction() {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "Easy@0122";
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
String sql = "insert into blog(author,content,title)values(1,2,3)";
Statement stmt = conn.createStatement();
stmt.execute(sql);// 执行成功
int temp = 1 / 0;// 模拟抛出异常
stmt.execute(sql);// 未执行
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
如果使用事务的话,示例如下:
package org.maoge.jdbctran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 原生JDBC事务使用实例
*/
public class JdbcTransactionDemo {
public static void main(String[] args) {
actionWithTransaction();
}
/**
* 使用事务
*/
public static void actionWithTransaction() {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "Easy@0122";
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
conn.setAutoCommit(false);// 定义事务的起点
String sql = "insert into blog(author,content,title)values(1,2,3)";
Statement stmt = conn.createStatement();
stmt.execute(sql);// 没问题
int temp = 1 / 0;// 模拟抛出异常,导致回滚,所以上面的执行也回滚了
stmt.execute(sql);// 未执行
conn.commit();// 如果全部执行成功,则提交事务
} catch (Exception e) {
try {
conn.rollback();// 如果出现异常则回滚
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
分析上面的代码,就是我们在开始一个原子性操作之前(可能包含若干对数据库的操作),先开启事务,然后等几个操作都执行后再提交事务,此时对数据库的修改才生效;如果这中间发生异常,则执行回滚,则这些操作一个都不会生效。
从上面的示例中可以发现,几乎很多地方都是跟业务逻辑无关的代码,都是模板性质的代码,遵循如下结构:
try{
//开始事务
//执行具体操作
//提交事务
}catch(Exception e){
//回滚事务
//处理异常
}finally{
//释放资源
}
其中真正有意义的,只有具体操作部分,其他都是雷同的,所以可以封装起来。
那么如果不显示的指定conn.setAutoCommit(false);
,是什么情况呢。我们尝试下,可见默认情况下事务是自动提交的,也就是执行一个sql就自动提交事务了,所以默认情况下执行sql后更新马上就持久化到数据库了。
package org.maoge.jdbctran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 原生JDBC事务使用实例
*/
public class JdbcTransactionDemo {
public static void main(String[] args) {
testAutoCommit();
}
/**
* 使用事务
*/
public static void testAutoCommit() {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "Easy@0122";
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
System.out.println(conn.getAutoCommit());//输出true
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}