什么是事务
所谓的事务,一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。事务要么都执行要么都不执行。
通俗来说,事务就是把数据库的各种操作封装到一个事务里,这些数据库的操作要么全都执行要么全都不执行。我们通常利用事务的特性来保证操作的安全性,它可以在事务执行出现错误时,进行回滚操作,以恢复成最初的样子。
事务的四大特性——ACID
事务的四大特性分别是:原子性(atomicity)、一致性(consistency)、隔离性(isolation)以及持久性(durability)。
- 原子性(atomicity):事务是一个原子操作,由一系列对数据库进行操作的动作组成,事物的原子性可以确保事务要么全部完成要么完全不起作用。
- 一致性(consistency):一致性是指,事务必须使数据库从一个一致性状态变成另外一个一致性状态,也就是说,事务执行前后都必须处于一致。
- 隔离性(isolation):因为会有许多事务同时处理的数据,所以各个事务执行之间都要隔离开来,以免对数据造成损坏。
- 持久性(durability):一旦事务完成后,其结果一般会写到持久化存储器中,也就是说,一旦事务完成,无论发生什么系统错误,他的结果都不会受到影响。
事务并发会带来的问题
事务并发会带来脏读、不可重复读以及幻读的问题。
- 脏读:也称为读未提交,就是一个事物读取到了另一个事务未提交的数据。
举例解释:事务A先查询某人年龄,随后事务B修改某人年龄,然后事务A又读取某人年龄,然后事务A提交事务,事务B回滚,那事务A第二次查出的数据就是错的,所以是脏读。
- 不可重复读:在一个事务中,多次读取同一个数据,但返回了不同的结果。该现象是因为在该事物读取数据间隔中,有别的事务对该数据进行修改并提交,导致发生不可重复读的事故。
举例解释:事务A先查询某人年龄,随后事务B修改某人年龄,然后之间提交了,然后事务A又读取某人年龄,读取两个不一样的数据。被称为不可重复读。
- 幻读:幻读是指事务不独立执行时,另一个事务插入或删除了一些数据导致影响到当前事务结果而发生的一种类似幻觉的现象。
举例解释:事务A先查询C表总数,随后事务B删除一条条记录,然后直接提交了,然后事务A又查询C表总数,两次总数不一样。称为幻读。
如何解决事务并发带来的问题
我们可以通过设置数据库的隔离级别来解决事务并发带来的问题,不同的隔离级别可以解决不同的问题。
- read uncommited(读取未提交内容):这是最低的隔离级别,在该隔离级别下,所有事务都可以看到其他未提交事务的执行结果,读取未提交的数据。在该隔离级别下,脏读、幻读不可重复读都可能会发生。
- read commited(读取提交内容):这是大多数数据库默认的隔离级别(MySQL除外)。该隔离级别满足了隔离的简单定义,即一个事务只能看见已提交事务所做的改变。该隔离级别可以解决脏读,但是无法解决不可重复读和幻读。
- repeatable read(可重读):这是MySQL默认的隔离级别,该隔离级别下,同一个事务的多个实例在并发读取数据时,会看到同样的数据。因此该隔离级别可以解决脏读以及不可重复读,但是仍然解决不掉幻读。
- serializable(可串行化):这是最高的隔离级别,该级别通过强制事务排序,使事物之间不可能冲突,从而解决掉幻读问题。实际上,它就是在每个读的数据上加上共享锁。但是缺点也显而易见,在这个级别下,可能会导致大量的超时现象以及锁竞争。该隔离级别可以解决脏读、不可重复读以及幻读。
总结来说就是,隔离级别越高,事务并发带来的问题越少,相对的性能也就越弱。
//MySQL查看隔离级别的命令(在cmd中查看)
select @@global.tx_isolation
SELECT @@tx_isolation
show variables like 'tx_isolation'
//MySQL设置隔离级别的命令
//隔离级别分别为: READ UNCOMMITTED(读未提交) READ COMMITTED(读已提交) REPETABLE READ(可重读) SERIALIZABLE(可串行化)
//设置全局隔离级别
set global transaction isolation level 隔离级别
//设置会话隔离级别
set session transaction isolation level 隔离级别
//通过更改配置文件来设置隔离级别,打开"mysql.ini"文件,添加"transaction-isolation=隔离级别"语句即可。
transaction-isolation=隔离级别
注意:msql8.0以后使用select @@GLOBAL.transaction_isolation;查看全局隔离级别。select @@transaction_isolation; 当前会话的隔离级别
Spring如何实现事务
1、首先引入依赖jar包
<!--spring事务依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
2、 修改配置文件,注入事务切面类,开启事务注解驱动
<!--注入事务切面类 必须为transactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
</bean>
<!--开启事务注解驱动-->
<tx:annotation-driven/>
3、在方法上直接用这个注解transactional