1.事务解释-注意以下示例代码,都是最简的。不规范。
当1给2转账10块:
数据库实现思路如下:先给1减去10,再给2加上10。
那么问题来了:
当1减去10执行成功以后,在给2加钱的时候出错了。
最终造成结果是:
1少了10快,2的钱却没有变。因此,总钱少了10快。
2.没有事务,正常执行的示例
package tran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
//实现的业务是:1给2转10块钱
public class Account {
private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql连接驱动,无需改
private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
private static String jdbcuser = "root"; // 数据库用户名
private static String jdbcpwd = "root"; // 数据库密码
private static Connection conn;
public static PreparedStatement ps;
public static void main(String[] args) {
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驱动利用驱动地址,数据库用户名,密码创建连接
ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=1;");
ps.executeUpdate();
ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=2;");
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
}
}
}
3.没有事务,过程中出错示例
package tran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
//最终的执行结果是:从id 1的用户里减去了10块钱,但是并没有给2加上。
//造成的结果是:总金额少了10块。
public class Account {
private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql连接驱动,无需改
private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
private static String jdbcuser = "root"; // 数据库用户名
private static String jdbcpwd = "root"; // 数据库密码
private static Connection conn;
public static PreparedStatement ps;
public static void main(String[] args) {
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驱动利用驱动地址,数据库用户名,密码创建连接
ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=1;");
ps.executeUpdate();
int i=1/0;//就是这里
ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=2;");
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭资源
}
}
}
4.解决方案-事务
package tran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Account {
private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql连接驱动,无需改
private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
private static String jdbcuser = "root"; // 数据库用户名
private static String jdbcpwd = "root"; // 数据库密码
private static Connection conn;
public static PreparedStatement ps;
public static void main(String[] args) {
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驱动利用驱动地址,数据库用户名,密码创建连接
conn.setAutoCommit(false);// 设置不自动提交
ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=1;");
ps.executeUpdate();
int i = 1 / 0;
ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=2;");
ps.executeUpdate();
conn.commit();// 如果上面的执行都没问题,再提交。
} catch (Exception e) {
try {
conn.rollback(); //回滚
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
// 关闭资源
}
}
}
5.扩展-保存点
使用场景:
1给2转钱,转完给他们发短信。
以下是模拟。
package tran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
public class Account {
private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql连接驱动,无需改
private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
private static String jdbcuser = "root"; // 数据库用户名
private static String jdbcpwd = "root"; // 数据库密码
private static Connection conn;
public static PreparedStatement ps;
static Savepoint sp;
public static void main(String[] args) {
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驱动利用驱动地址,数据库用户名,密码创建连接
conn.setAutoCommit(false);// 设置不自动提交
ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=1;");
ps.executeUpdate();
ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=2;");
ps.executeUpdate();
sp = conn.setSavepoint();
// 发送短信业务
// 模拟业务出错
int i = 1 / 0;
conn.commit();// 如果上面的执行都没问题,再提交。
} catch (Exception e) {
if(sp!=null){//只简单说明,实际还要判断conn是不是null
try {
conn.rollback(sp);
conn.commit();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
} finally {
// 关闭资源
}
}
}