日常总结 postgresql批量删除 mybatis动态sql spring事物

今天在写业务代码时,需要写一个删除数据库记录的方法。然而要操作的表被其他的表依赖。也就是本表的主键是其他表的外键。但是数据库并没有设计外键,所以只能手动删除关联表的信息  。用的框架是spring,dubbo,mybatis,数据库是postgresql。因为设计到多条sql语句。当然要用事务来解决数据的一致性和完整性的问题。下面先来重新学习一下spring事务。

  数据库事务有严格的定义,必须同时满足:原子性,一致性,隔离性,持久性。

原子性:表示组成一个事务的多条sql语句是一个不可分割的数据单元。所有语句执行成功才能提交,只要有一条语句执行失败,所有操作必须全部撤销。让数据库返回初始状态。

一致性:事务操作成功后,数据次所处的状态和这个数据库业务规则是一致的,数据不会被破坏。假如在银行系统中,两个人相互转账,他们的总存款数应该不变,不能因为事务的执行发生变化。

隔离性:在并发操作时,各个事务拥有各自的操作空间,他们的操作不会对对方产生干扰。数据库规定了不同的隔离级别,不同级别对应在并发操作数据库时的不同干扰程度。隔离级别越高,数据一致性越好,但是并发性越弱。

持久性:一旦事务执行成功。就会被持久化到数据库。

 

其中“一致性”是最终目标。其他三个特性都是为了达到这一目标所确定的。

 

数据并发问题:

脏读:B事务执行时发生了错误回滚。但是A恰巧读到了B回滚之前的数据,并执行成功。这样A的数据应该是错误的,不被承认的。

 

不可重复读:A读取了两次数据,但在这两次读取之间B更改了该数据。这样A两次读取到的数据就会不一样。

 

幻象读:A读取了两次符合条件的数据,但在这两次读取之间B新增加了数据。这样A两次读取到的数据就会不一致

 

不可重复读和幻象读的区别就是,不可重复读是读取更改的满足条件数据,幻象读是读取到新增加的满足条件的新数据。解决前者要为数据添加行级锁,后者要添加表级锁。

 

第一类丢失更新:A在回滚时覆盖了B提交的事务。假如B事务让银行新进账100,A回滚后B的操作也被覆盖掉。银行赔了100。

 

第二类丢失更新:A在提交事务时,把B提交的事务覆盖了。假如事务A读取银行存款1000并添加100,这时B也做同样操作,但是A提交后把B提交结果覆盖掉了,银行又赔了100。

 

数据库通过锁来解决并发访问的问题,insert,update,delete,select for update 都会隐式采用必要的行级锁。

 

事务隔离级别。数据库为了方便用户操作设定了4个隔离级别。用户只需要设定相应的隔离级别,事务操作就会为数据资源添加合适的锁。

ANSI/ISO SQL 92定义了4个隔离级别。

Read uncommitted :不允许第一类丢失更新

Read commited:不允许脏读和第一类丢失更新

Repetable read :只允许幻象读

Serializable :全都不允许

mysql数据库默认repetable read 隔离级别。它只允许幻象读。

 

 

Spring为了方便管理嵌套事务,定义了7中传播行为

PROPAGATION_REQUIRED:如果当前没有事务就新建一个事务,有就加入到这个事务中执行。

PROPAGATOIN_SUPPORTS:当前有事务就在当前事务中执行,没有就以非事务执行。

PROPAGATION_MANDATORY:当前有事务就在当前事务中执行,没有就抛出异常。

PROPAGATION_REQUIRES_NEW:新建立一个事务执行,如果当前有事务执行,就把当前事务挂起。

PROPAGATION_NOT_SUPPORT:以非事务方式执行,如果当前有事务就把其挂起。

PROPAGATION_NEVER:不支持事务,如果当前存在事务,就抛出异常。

PROPAGATION_NESTED:如果当前有事务,就嵌套在事务中执行。没有就新建一个事务执行。

 

以上是spring 3.x企业应用开发实战里的内容

我用的注解得方式执行事务操作,别忘了在配置文件里定义事务管理器。

 

事务复习完了,继续说删除方法的执行过程,由于从表的多条记录对应主表的一条记录。而我又不想,多次与数据库交互删除。就想到的批量操作,但我并不会,上网了解了一下。

找到了一条sql这样写  delete from xx using(values (1),(2),(3)) as tmp(id) where xx.id = tmp.id

但我不太懂postgresql里using的用法。在网上也没查到资料,这个疑问只能日后再解决的。

由于需要把很多主键值放到values旁边的多个括号里,所以又要用到mybatis的动态sql了。

动态sql我不太熟悉。下回再写关于动态sql的。这里就先用到的foreach标签。里面有几个属性 collection是要遍历的集合类型,可不是要传入的集合名哦。 item是每次遍历到的值。Index对于list来说是遍历元素的序号,对于set来说是key值。Separator是拼出来每个元素间的分隔符。Open是foraeach拼出的串的最开始符号可以是左括号,close是结束符号。他俩配合使用。下面是批量删除加上动态sql语句:

delete from twatch_enterprise  a
using (values
<foreach item="item" index="index" collection="list" separator=",">
  (#{item})
</foreach>
) as mid(id) where a.leased = mid.id

把sql语句都放进一个dubbo service方法里,再在方法上面添加Transcational注解,属性是propagaton = PROPAGATION.REQUIRED ,isolation=repetable read,rollbackfor = {SQLExcation.class}。

就ok了。

猜你喜欢

转载自blog.csdn.net/qq_35368651/article/details/81290572