原 mysql读写锁及事务_Spring data Jpa,Mybatis,读写锁,@Lock 使用(示例代码)

Spring data jpa 支持注解式的读写锁(悲观锁),实际上这个东西硬编码也简单,但是基于Jpa 命名方式定义的Sql,只能用注解添加支持读写锁了,

不了解读写锁的可以点这里

并且推荐

PESSIMISTIC_READ,

PESSIMISTIC_WRITE,

而不是

READ,

WRITE,

但是官方文档貌似没有更新这个案例,踩了一些坑.

lazy.gif

新建一个实体Book.java

/*** User: laizhenwei

* Date: 2018-04-18 Time: 9:04

* Description:*/@Entity

@Table(name= "test_book")

@Alias("Book")

@Getter

@Setter

@NoArgsConstructor

@AllArgsConstructorpublic class Book extendsAbstractJbatisIdEntity{private static final long serialVersionUID = -1L;privateString name;privateString author;

}

BookRepository.java

/*** User: laizhenwei

* Date: 2018-04-18 Time: 9:11

* Description:*/

public interface BookRepository extends JpaRepository{

@Lock(LockModeType.PESSIMISTIC_READ)

Book findTop1ByName(String name);

}

BookServiceImpl TimeUnit.SECONDS.sleep(20); 是为了让事务延迟提交,好测试save操作需要阻塞到读写释放才能提交

public static final CountDownLatch readCount = new CountDownLatch(1);public static final CountDownLatch saveCount = new CountDownLatch(1);

@Transactional(propagation=Propagation.REQUIRES_NEW)

@OverridepublicBook save(Book book){

Book book1= null;try{

readCount.await();

book1=getRepository().save(book);

saveCount.countDown();

}catch(InterruptedException e) {

e.printStackTrace();

}returnbook1;

}

@Transactional(propagation=Propagation.REQUIRES_NEW)

@OverridepublicBook findTop1ByName(String name){

Book book=getRepository().findTop1ByName(name);try{

readCount.countDown();

TimeUnit.SECONDS.sleep(20);

}catch(InterruptedException e) {

e.printStackTrace();

}returnbook;

}

JunitTest 先添加一条数据,待会要锁这个数据

@Testpublic voidsave(){

Book book= newBook();

book.setName("百年孤独");

book.setAuthor("加西亚·马尔克斯");

bookRepository.save(book);

}

开启两条线程,一条先加上读锁,然后睡眠一会,另一条线程去修改这个对象的时候,需要阻塞到读事务提交以后才会成功

第二个查询动作不会阻塞,因为读锁只对写操作限制(这里用直接用bookRepository,是为了避免CountDownLatch 再一次阻塞而已)

@Test

@Transactional

public void findByName() throwsInterruptedException {new Thread(()->bookService.findTop1ByName("百年孤独")).start();

BookServiceImpl.readCount.await();

Book book=bookRepository.findTop1ByName("百年孤独");

book.setAuthor("加西亚·马尔克斯5");new Thread(()->bookService.save(book)).start();

BookServiceImpl.saveCount.await();}

有个有趣的现象,如果直接运行第二次,会发现不用阻塞,就能save成功,因为数据并没有做任何修改.

再注释掉@Lock跑一次,修改 book.setAuthor("加西亚·马尔克斯5");再保存也不需要等待.

Mybatis下的实现,就是手动编码而已

/*** User: laizhenwei

* Date: 2018-04-18 Time: 9:12*/@Mapperpublic interface BookMapper extends BaseMapper{

@Select("select * from test_book where name=#{name} limit 1 lock in share mode")

Book findTop1ByName(String name);

}

Service  TimeUnit.SECONDS.sleep(20); 是为了让事务延迟提交,好测试save操作需要阻塞到读写释放才能提交

@Transactional(propagation =Propagation.REQUIRES_NEW)

@OverridepublicBook mapperFindTop1ByName(String name){

Book book=getMapper().findTop1ByName(name);try{

readCount.countDown();

TimeUnit.SECONDS.sleep(20);

}catch(InterruptedException e) {

e.printStackTrace();

}returnbook;

}

JunitTest (这里用直接用bookRepository,是为了避免CountDownLatch 再一次阻塞而已)

@Test

@Transactional

public void findByName() throwsInterruptedException {new Thread(()->bookService.mapperFindTop1ByName("百年孤独")).start();

BookServiceImpl.readCount.await();

Book book=bookRepository.findTop1ByName("百年孤独");

book.setAuthor("加西亚·马尔克斯3");new Thread(()->bookService.save(book)).start();

BookServiceImpl.saveCount.await();}

测试效果与Jpa一样.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值