开发中事务的传播特性引发的问题

 前提:

 1、项目中遇到了多线程并发的问题,因为考虑到数据库可以做到随意更换,所以并没有在数据库中加锁,而是在java代码中做了同步。

 2、基于1,数据库没有采用序列或者主键自增的方法,而是新增了一张叫TABLE_KEY的表,存储其他表中表名和主键值,当insert的时候,从TABLE_KEY中取相应表名的主键值然后update相应表名的主键值


 在什么地方加锁?

 原先的方案:

 在service层中某insert方法内封装的操作TABLE_KEY表的方法(假设叫foo)上加排他锁,service本身不加锁。


 产生的问题:

 测试的时候,数据库报错:违反了主键唯一性


 原因:

 项目采用的事务传播特性为:PROPAGATION_REQUIRED,即:

 如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入到这个事务中。

 就像两个事务的嵌套,内部事务依赖了外部事务,导致项目中foo中update没有commit,ThreadA处理完之后解锁,ThreadB重新加锁但query的还是没有update的数据,所以会产生违反主键唯一性的错误。


 目前解决办法:在service方法上加锁。


 Spring提供的事务传播特性:

  • PROPAGATION_REQUIRED:
    如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入到这个事务中。这是最常见的选择。
  • PROPAGATION_SUPPORTS:
    支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY:
    使用当前的事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW:
    新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED:
    以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER:
    以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED:
    如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。