一、事务
1、事务的四大特性
(1)原子性:事务开始后所有的操作要么一起成功,要么一起失败,整个事务是一个不可分割的整体。
(2)一致性:是物开始前到结束后,数据库的完整性约束没有被破坏。
(3)隔离性:同一时间只允许一个事务请求同一事务,不同事务互不干扰。
(4)持久性:事务完成,事务对数据库的所有更新将被保存到数据库,不能回滚。
tps:数据库的完整性约束-->数据完整性:存储在数据库中的所有数据值均正确的状态。它是应防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而提出的。 数据完整性分为四类: 实体完整性(实体完整性是对关系中的记录唯一性,也就是主键的约束。准确地说,实体完整性是指关系中的主属性值不能为Null且不能有相同值。定义表中的所有行能唯一的标识,一般用主键,唯一索引 约束是表级的强制规定,有以下五中:not null,unique,primary key,foreign key,check 。 |
2、事务的隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) (mysql默认) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
(1)脏读:事务A读取到事务B未提交的数据(事务B回滚可怎么办)。
(2)不可重复读:事务A在同一事务中多次读取同一数据,取到不同的值。(有其他事务在A事务期间更新了这一数据、或删除,导致)
(3)幻读:事务A两次读取数据,返回的数据条数不一致(发生增加)
二、行锁
1、乐观锁
乐观锁并不是数据库本身实现的,他需要我们自己去实现。
每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
2、悲观锁
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。
悲观锁涉及到另外两个锁概念,它们就是共享锁与排它锁。共享锁和排它锁是悲观锁的不同的实现,它俩都属于悲观锁的范畴。
1)共享锁:对于多个事务对同一资源共享一把锁
在执行语句后面加上lock in share mode就代表对某些资源加上共享锁了
2)排它锁:对于多个事务对同一资源只能有一把锁
在执行语句后面加上for update就代表对某些资源加上排它锁了
3、悲观锁与扫描行:
对通过索引、主键查询到的数据加锁,会将这个索引所在的记录加上锁,如果通过条件查询,会对多条记录加上锁。
如果不加索引,MySQL 会对扫描到的数据加锁。(不确定)
SpringMVC @Transactional 注解
@Transactional 在方法头上注解,该方法被其他方法内部调用,则不会生效。
另需要手动开启事务用:
@Autowired
private PlatformTransactionManager transactionManager; DefaultTransactionDefinition def=new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。
TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态
transactionManager.commit(status);//提交
transactionManager.rollback(status);//回滚