事务并发(乐观锁)

事务的四个特性

要了解事务并发我们先要了解事务的四个特性:
原子性(Atomic),事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行
一致性(Consistent),事务在完成时,必须使所有的数据都保持一致状态。
隔离性(Insulation),由事务并发所作的修改必须与任何其它并发事务所作的修改隔离。
持久性(Duration),事务完成之后,它对于系统的影响是永久性的。

事务并发

为获得更好的运行性能,各类数据库都允许多个事务同时运行,这便是事务并发

事务并发所带来的的问题

① 第一类丢失更新
在这里插入图片描述
② 第二类丢失更新
在这里插入图片描述
③ 脏读
在这里插入图片描述
④ 幻读
在这里插入图片描述
⑤ 不可重复读
在这里插入图片描述

事务隔离机制

由于事务并发会带来以上五种问题,每一款数据库都有自己的事务处理机制
未提交读 Read UnCommited
提交读 Read Commited
可重复读 Read Repeatable
可串行读 Read Serializable
在这里插入图片描述
市面上的数据库都不会选择可串行读和未提交读,而是选择可重复读和提交读,数据库本身默认事务隔离级别可以解决事务并发中的脏读、幻读、不可重复读,剩下的第一类和第二类丢失更新需要由JPA解决:
悲观锁:修改一行数据的时候,将整张表锁定(用户体验非常差)
乐观锁:修改一行数据的时候,就只锁定当前行数据

乐观锁

乐观锁的实现方式有两种:
1.时间戳:datetime作为数据类型
2.版本号:integer作为数据类型
实现原理都一样:在一张表中添加一个列,数据类型采用datetime或者是integer,区别在于integer比datetime所占用的数据库空间更小

代码模拟

我们通过模拟商品秒杀来实现乐观锁
domain实体类:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Version;

@Entity
public class Product {

    @Id
    @GeneratedValue
    private Long id;

    //商品名称
    private String name;

    //商品剩余数量
    private Integer number;

    //@Version 注解就表示JPA要使用乐观锁
    @Version
    private Integer version;

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }
}

测试类:

import cn.itsource.domain.Product;
import org.junit.Test;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class OptimisticLock_Test {
    @Test
    public void test() throws Exception{
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa_day04");
        EntityManager entityManager01 = factory.createEntityManager();
        EntityManager entityManager02 = factory.createEntityManager();
        entityManager01.getTransaction().begin();
        entityManager02.getTransaction().begin();
        Product product01 = entityManager01.find(Product.class, 1L);
        Product product02 = entityManager02.find(Product.class, 1L);
        //开始秒杀
        product01.setNumber(product01.getNumber() - 1);
        entityManager01.getTransaction().commit();
        /**
         * 第二个事务开始秒杀
         * 这一行数据已经被另一个事务修改了或者删除了
         * 使用JPA的乐观锁,秒杀失败就一定会报出StaleObjectStateException异常
         */
        product02.setNumber(product02.getNumber() - 1);
        entityManager02.getTransaction().commit();
        entityManager01.close();
        entityManager02.close();
        factory.close();
    }

}

数据库的变化:
秒杀前:
在这里插入图片描述
秒杀后:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值