1、JDBC中的事务
最简单的事务的概念的总结
在一个方法中,同时存在多条更新类语句(insert delelte update),那么这些语句需要以整体方式执行,要么都成功,要么都失败,不可以拆分执行。
举一个很简单的例子,A和B两个人,A从B中购买东西,A需要向B支付一定的费用,假如A、B各有9000元,A需要向B支付5000元,B需要收入5000元,这两个操作就包含在一个事务之中,两个操作需要以整体方式执行,不可以拆分,要么都成功,要么都失败,绝不允许只有A支付了,B没有收到的这样的情况。
事务的四个特性
1、一致性:
事务在执行前后,数据的大小总和保持不变。
也就是在上面的例子中的A在支付前后,A和B的总金额都是18000,绝对不允许在这个事务执行之后,这个数据的总和发生改变。
2、原子性
构成事务的语句,以整体方式执行,要么都成功,要么都失败。
3、持久性
事务做出的改变,一经确认,具有永久时效性,不可以再撤回。
4、隔离性
事务执行期间,涉及的数据暂时处于锁定的状态,其他事务不能处理.
事务的隔离性在数据库底层是通过锁机制完成的.
隔离性就好比java线程中的两个线程不可以同时去修改一个数据,必须加上互斥锁这样的锁,才能保证隔离性。
2、JDBC中采用事务的方式来执行sql语句
我们假定有两个人,“武松”和“西门吹雪”两个人做生意,后者需要向前者支付5000元,假定两个人都有9000,我们在这里偷偷的给武松的金钱的数据类型大小,设置成4位的,也就是不会超过9999,意思就是,就算收到了5000,也不会加进来称为自己的钱,那么这个时候,我们再看西门吹雪是不是成功支付了,还是没有成功呢?我们根据事务的原子性和一致性,也知道,是不会成功的,具体看一下代码:
先看一下和数据库有关的DBUtils类:
package com.neusoft.system.db;
import java.sql.*;
//资源文件解析器
import java.util.ResourceBundle;
public class DBUtils
{
//1.定义驱动串---整个驱动jar包中,核心类的路径
private static String driver=null;
//2.定义链接串---数据库所在的位置及名称
private static String url=null;
private static String userName=null;
private static String password=null;
/**
* 静态块
* 在类被第一次加载入内存时候,执行,以后不再执行
*/
static
{
System.out.println("run static .......");
try
{
//获取资源文件解析器实例
ResourceBundle bundle=ResourceBundle.getBundle("DBOPtions");
//从资源文件获取数据
driver=bundle.getString("DRIVER");
url=bundle.getString("URL");
userName=bundle.getString("USERNAME");
password=bundle.getString("PASSWORD");
//3.加载驱动
Class.forName(driver);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
/**
* 当一个类中所有的成员(属性和方法)都是static,那么此时构造器应该私有
*/
private DBUtils() {}
public static Connection getConnection()throws Exception
{
//4.创建链接
Connection conn=DriverManager.getConnection(url, userName, password);
return conn;
}
public static void close(PreparedStatement pstm)
{
try
{
if(pstm!=null)
{
pstm.close();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public static void close(Connection conn)
{
try
{
if(conn!=null && !conn.isClosed())
{
conn.close();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String[] args)
{
try
{
System.out.println(DBUtils.getConnection());
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
事务的方式来执行更新操作:
package transaction;
import java.sql.*;
import com.neusoft.system.db.DBUtils;
public class Person
{
public static void main(String[] args)
{
try
{
boolean tag=Person.tiger();
System.out.println(tag);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private static boolean tiger()throws Exception
{
//1.定义JDBC接口
Connection conn=null;
PreparedStatement pstm1=null; //扣减西门吹雪
PreparedStatement pstm2=null; //增加武松
try
{
//2.创建连接
conn=DBUtils.getConnection();
//3.完成对西门吹雪账户的处理
//3.1定义SQL语句
String sql1="update person set umoney=umoney-? where uid=?";
//3.2编译SQL语句
pstm1=conn.prepareStatement(sql1);
pstm1.setObject(1, 5);
pstm1.setObject(2, 2);
//4.处理武松的账户
//4.1定义SQL语句
String sql2="update person set umoney=umoney+? where uid=?";
//4.2编译SQL及赋值
pstm2=conn.prepareStatement(sql2);
pstm2.setObject(1, 5);
pstm2.setObject(2, 1);
//5.以事务方式执行SQL
//5.1定义事务返回值
boolean tag=false;
/**
* 5.2开启事务
* conn内部存在一个叫autoCommit的属性,该属性默认值为true,
* 表示遇到更新类语句,立即修改数据库
* setAutoCommit(false); 遇到更新类语句,先不要修改数据库,而是进行彩排(模拟执行),
* 等待后继指令,后继指令如果是更新数据库那么再去更新,如果是撤销,那么取消更新操作
*/
conn.setAutoCommit(false);
try
{
//5.3在事务内部执行所有的更新语句
pstm1.executeUpdate();
pstm2.executeUpdate();
//5.4.1:确认对数据的修改---提交事务
conn.commit();
//5.5修改事务返回值,表示执行成功
tag=true;
}
catch(Exception ex)
{
//5.4.2:取消对数据的修改---事务回滚
conn.rollback();
ex.printStackTrace();
}
finally
{
//5.6结束事务
conn.setAutoCommit(true);
}
return tag;
}
finally
{
DBUtils.close(pstm1);
DBUtils.close(pstm2);
DBUtils.close(conn);
}
}
}
【注】
事务不提交,不会执行sql语句。
在捕捉到异常的时候,要进行事务的回滚,这样才不会出差错。
JDBC结束之后,一定记得关闭连接资源,否则内存泄漏。