Java大数据之路--事务

事务


事务概述

在一个事件中,有许多单元组成,这些单元要么全部成功,或者全部失败,这些单元全部组成起来称之为一个事务。

  • 案例

比如简单的转账业务,sql实现

开启事务
start transaction;
update account set money = money-100 where name ='小明';
update account set money = money+100 where name ='小红';
commit; 或者 rollback;

由于这个事件需要同时发生或者同时不发生,所以需要把这两句sql写在一个事务中。不开启事务,mysql默认一条语句为一个事务。

  • JDBC事务案例

在JDBC中也是一条语句为一个事务,如果需要多条sql语句在同一个事务中,就需要开启事务。

conn.setAutoCommit(boolean)

开启事务。默认值位true。代表开启自动提交,一句sql就是一个事务。修改为false,代表关闭自动提交,意味着开启使用,多个sql可以在同一个事务中执行。

conn.commit()提交事务
conn.rollback()回滚事务
conn.rollback(Savepoint sp)回滚到记录点

 

  • JDBC代码实现
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//事务测试
public class TransDemo1 {

	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
        SavePoint sp = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day16", "root", "root");
			//开启事务
			conn.setAutoCommit(false);//默认值为true,代表会自动提交。
			//自动提交意味着一句sql就是一个事务,执行sql就会立刻提交这个事务,修改数据库中的数据。
			//设置为false,代表不会自动提交,表示开启事务,需要手动提交或回滚。
			ps = conn.prepareStatement("update user set money = money -100 where name=?");
			ps.setString(1, "a");
			ps.executeUpdate();
            //设置事务回滚点
            //sp = conn.setSavePoint();
			int i =1/0;
			ps = conn.prepareStatement("update user set money = money +100 where name = ?");
			ps.setString(1, "b");
			ps.executeUpdate();
			conn.commit();//在sql书写完成之后,选择使用commit方法提交事务。
		} catch (Exception e) {
			if(conn !=null){
				try {
					conn.rollback();
				} catch (SQLException e1) {
					e1.printStackTrace();
				} }
			e.printStackTrace();
		}finally{
			if(conn !=null){
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}finally{
					conn = null;
				} }
			if(rs !=null){
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}finally{
					rs = null;
				} }
			if(ps !=null){
				try {
					ps.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}finally{
					ps =null;
				} } } } }

事务特性

  • 事务四大特性(ACID)

原子性(Atomicity):一个事务中多个单元,是不能分割的,要么同时成功,要么同时失败。

一致性(Consistency):事务修改数据前后,数据库的数据的完整性,仍然保持一致。

隔离性(Isolation):数据库中一个事务,可能被其他事务影响,为了避免这种情况发生,数据库提供了几种隔离级别供用户选择。

持久性(Durability):数据库中的事务一旦提交,就会永久改变,无法改变,即使数据库损坏,也无法恢复原有的数据。

  • 数据库中的四大特性

数据库中除了隔离性,另外三种性质都得到了具体实现,开发中直接使用即可,唯独隔离性,没有做出具体实现。原因是:

每一个数据库用户,对于数据库的隔离级别看法不同,数据库不能写死其隔离级别,如果写死的话会很不友好,所以隔离性需要用户自行设置。

考虑数据库的隔离级别,就是分析数据库中事务之间的线程安全问题,所以可以从数据涉及读和写来分析。

两个事务同时读取数据:

这种情况不会存在线程安全问题。因为两个事务对应的线程都未对数据进行修改,任何人读取的数据内容都相同。

两个事务同时写入数据:

这种情况一定会存在线程安全问题。因为两个事务对应的线程都会对数据进行修改,第二次修改可能会覆盖第一次的操作,所以应该将两个事务严格分开。可以通过修改数据库的隔离级别,来保证两个事务分别执行,避免出现线程安全问题。

一个事务写,一个事务读:

在面对一个事务写,一个事务读这种情况时,可以选择修改数据库的隔离级别达到自己想要的效果。如果要求数据库安全性与正确性,则可以选择最高的隔离级别。如果要求数据的写入速度,则可以选择数据库的最低隔离级别。多数情况需要两者兼顾,可以选择中间两个隔离级别。面对数据库中存储的脏读,不可重复读,虚读/幻读这些情况,也可以根据自己的需求,修改数据库的隔离级别。防止这些问题的隔离级别,推荐使用repeatable read。原因是这个级别,不会出现脏读,和不可重复读。而虚读出现的情况极少。可以认为当前隔离级别是安全且能够保证执行效率的。

  • 几种事务之间互相影响的情景分析

脏读:一个事务读取到另一个未提交事务的数据,导致数据前后读取不一致。

a:1000 买家
b:1000 商家
--------------------------------------------------------------------
a:start transaction;
update user set money = money -100 where name='a';
update user set money =money +100 where name ='b';
-----------------------------------------------------------------------------
b:start transaction;
select * from user where name ='b';-----1100
-----------------------------------------------
a:rollback;
-------------------------------------------------------
b:select * from user where name ='b';-----1000

不可重复读:一个事务读取到另一个已经提交事务的数据,在事务提交前后,读取的数据内容不一致,这种现象就称之为不可重复读。

------------------------------------------------------------------------
a:1000 1000 1000
------------------------------------------------------------------------
b:start transaction;
select hq from account where name='a';----1000;
select dq from account where name='a';----1000;
select gp from account where name='a';----1000;
-----------------------------------------------------------------
a:start transaction;
update account set hq = hq-100 where name='a';
commit;
------------------------------------------------------------------
b:
select hq+dq+gq from account where name='a';---2900
--------------------------------------------------------------------
hq 1000
dq 1000 
gp 1000
sum 2900

虚读/幻读:在整表操作中,一个事务读取到另外一个已经提交事务的数据,导致事务提交前后数据不一致的现象,这种现象称之为虚读/幻读。

-----------------------------------------------------------------------------
a:1000
b:2000
------------------------------------------------------------------------------
d:
start transaction;
select sum(money) from user; ----3000
select count(money) from user; ----2
---------------------------------------------------------------------
c: 3000
start transaction;
insert into user values('c',3000);
commit;
----------------------------------------------------------------------
d:
select avg(money) from user;---- 1500

数据库隔离级别

在数据库的事务特性当中,唯独没有实现隔离性的内容,转而是为用户提供四个隔离界别的选项,用户可以根据自己的需求,选择合适隔离级别。

  • 四个隔离级别

read uncommitted;

脏读,不可重复读,虚读/幻读,都会出现。数据库安全性最低,但是效率最高。
read committed;可以防止脏读。不可以防止不可重复读及虚读/幻读。数据库安全性较低,效率较高。
repeatable read;

可以防止脏读,和不可重复读。不可以方式虚读/幻读.数据库的安全性较高,效率较低。mysql默认的隔离级别。

serializable;

可以防止脏读,不可重复度和虚读/幻读.它是mysql最高的隔离级别。是一个串行化的处理方式,虽然安全性较高,但是执行效率过低。

  • 隔离级别的选择

安全serializable > repeatable read >read committed>read uncommitted

性能read uncommitted>read committed> repeatable read>serializable由于read uncommitted隔离级别过低,安全性保证较差,所以实际开发中使用较少。serializable隔离级别过高,安全性虽然较高,但是效率极低,对于开发影响较大,所以实际开发中很少使用。

read committedrepeatable read两个隔离级别较为使用,对于数据安全性和语句执行效率都有较好的保证,开始时多数会采用两者其中一个。

修改数据库的事务级别
set global/session transaction isolation level read uncommitted;
set transaction isolation level read uncommitted;临时修改,只对下一次的事务生效

-------------------------------------------------------------------------------------------

查询当前数据库的隔离级别
select @@tx_isoaltion;

数据库中的锁

  • 共享锁和排他锁

​​​​​​​a. 在非serializable隔离级别之下,查询不加锁。增删改添加排它锁。

b. serializable隔离级别之下,查询添加共享锁。增删改添加排它锁。

特点:

i. 共享锁和共享锁可以共存。

ii. 共享锁和排它锁不能共存。

iii. 排它锁和排它锁不能共存。

  • 表级锁和行级锁

​​​​​​​表级锁:添加锁之后,当前表格,不允许另外的事务操作。

行级锁:添加锁之后,当前表格中的某一行或几行,不允许另外的事务操作。

  • 死锁​​​​​​​

两个线程相互等待对方释放资源,这种现象称之为死锁。

解决死锁的方案:

i. 销毁其中任意一个线程。

ii. 修改代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值