事物:
一组相关的sql语句,要么同时成功,要么同时失败
jdbc也是默认事物自动提交
模拟:
账户:100001给100002转账1000
实现:
账户:sql1:100001 :update balance = balance-1000
账户:sql2:100002 :update balance = balance+1000;
sql1 和sql2保证要么同时成功。要么同时失败
在转账期间如果发生了异常,事务回滚,正常时事物提交
package com.hadwinling.day01;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Calendar;
import com.hadwinling.day01.util.JDBCUtil;
/*
* 事务操作
* 事务并发安全问题
* 多个事务同时操作某些数据,如果这些操作进行增删改的话,可能吹西安事务并发安全问题
* 并发的安全问题:脏读,不可重复读,泛读
*
* JDBC的事务控制
*方式1. 编程时事务管理
*方式2. JDBC的事务隔离级别
* TRANSACTION_NONE 0
* TRANSACTION_READ_UNCOMMITTED 1
* TRANSACTION_READ_COMMITTED 2(大部分数据库默认值)
* TRANSACTION_REPEATABLE_READ 4(mysql默认值)
* TRANSACTION_SERIALIZABLE 8
*
* 级别越高 ,安全性越高,性能越差
*/
public class JDBCDemo06 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement= null;
try {
connection =JDBCUtil.getConnection();
//取消事物自动提交
connection.setAutoCommit(false);
//定义sql执行语句
String sql = "update account set balance =balance-? where accountname = ? and password = ?";
preparedStatement =connection.prepareStatement(sql);
//扣款
preparedStatement.setDouble(1, 1000);
preparedStatement.setString(2, "100001");
preparedStatement.setString(3, "123456");
//
preparedStatement.executeUpdate();
//模拟发送灾难
chushiqing();
//增款
preparedStatement.setDouble(1, -1000);
preparedStatement.setString(2, "100002");
preparedStatement.setString(3, "654321");
//
preparedStatement.executeUpdate();
//提交事物
connection.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
if(connection!=null) {
try {
//回滚
connection.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}finally {
//关闭资源
JDBCUtil.close(connection, preparedStatement, null);
}
}
public static void chushiqing() {
//获取当前秒数,如果大于30,抛出异常
Calendar calendar = Calendar.getInstance();
int second = calendar.get(Calendar.SECOND);
if(second>30) {
//触发异常
System.out.println("完蛋了");
throw new RuntimeException("搞事情");
}
}
}