JDBC的学习(五)——事务、模拟转账(事务回滚)

一、事务的概念

事务指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败。

事务的特性:

①原子性:是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

②一致性:指事务执行前后数据的完整性必须保持一致

③隔离性:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离

④持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,即使数据库发生故障也不应该对其有任何影响。

二、事务的隔离级别

多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。

如果数据库没有事务隔离机制,事务不考虑隔离性,可能会引发如下问题:

①脏读:指的是一个事务读取了另外一个事务未提交的数据

比如A和B进行银行转账,当B刚转了账,还没确认(即还未提交)的时候,这时A查看了账户,发现账户上的金额多了,这就是脏读。

②不可重复读:指的是在一个事务内读取表中的某一行数据,多次读取的结果不同。

比如银行查询A的余额,刚查的时候为200元,这时候,A存入100元,并且提交了,这时银行又查询一次,结果发现A账户为300元,两次查询结果不一样,就会产生疑惑。

不可重复读和脏读的区别是:脏读是读取前一次事务未提交的脏数据,不可重复读是重新读取了前一事务已经提交的数据。

③幻读(虚读):指的是在一个事务内读取到了别的事务插入的数据,导致前后结果不一样。

比如A存入100元还未提交,银行统计总共有多少存款发现是500,这时A提交了,银行又查询一次,发现总共存款变成了600。

三、JDBC中使用事务

①Connection.setAutoCommit(false):开启事务(start transaction),关闭自动提交

②Connection.rollback():回滚事务(rollback),如果出现异常,也可以自动回滚

③Connection.commit():提交事务(commit)

四、代码展示

演示银行转账

update account set money=money-100 where name='A'

 update account set money=money+100 where name='B'

先建立一张表account:

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `money` double DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 模拟转账成功
 * @author littledyf
 *
 */
public class TransferSuccess {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps = null;
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql:///spring_transaction", "root", "1234");
			conn.setAutoCommit(false);
			//A账户减少100
			String sql1 = "update account set money=money-100 where name='A'";
			ps = conn.prepareStatement(sql1);
			ps.executeUpdate();
			//B账户增加100
			String sql2 = "update account set money=money+100 where name='B'";
			ps = conn.prepareStatement(sql2);
			ps.executeUpdate();
			
			conn.commit();
			System.out.println("转账成功!");
			
		} catch (Exception e) {
			try {
				conn.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			e.printStackTrace();
		}finally {
			try {
				if(ps != null){
					ps.close();
				}
				if(conn != null){
					conn.close();
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

在模拟转账的代码中,如果程序出现异常,会发生回滚,也可以设置事务的回滚点,使用以下方式:

        Savepoint sp = conn.setSavepoint();
  Conn.rollback(sp);
  Conn.commit();//回滚后必须通知数据库提交事务


 

猜你喜欢

转载自blog.csdn.net/qq_41061437/article/details/82667882