SpringMybatis事物管理

来源:互联网 发布:Python 异常 编辑:程序博客网 时间:2024/06/05 02:28

SpringMybatis事物管理

刚刚学了Mybatis3, 开放了SQL权限确实很好用.

但造成使用者对持久层也花费了不少精力 ,有舍便有得

感觉所有的框架应该最后整合到使程序员只专注于业务层的实现,2017年7月18日21:42:55

明天来写事物控制 2017年7月19日10:58:11

先去看阿里出的java开发人员手册了 ,其中的异常,线程,和日志不是太了解

2017年7月20日12:08:53

又要去看java新特性了

概述
事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。
Spring Framework
对事务管理提供了一致的抽象,其特点如下:

  • 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence APIJDO(Java Data Objects)
  • 支持声明式事务管理,特别是基于注解的声明式事务管理,简单易用
  • 提供比其他事务APIJTA更简单的编程式事务管理API
  • spring数据访问抽象的完美集成

 

事务管理方式

spring支持编程式事务管理和声明式事务管理两种方式。

编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

声明式事务管理也有两种常用的方式,一种是基于txaop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

 

默认情况下 数据库 自动AutoCommit

 

对于正常的事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。不过,这个我们不用担心,spring会将底层连接的自动提交特性设置为false
org/springframework/jdbc/datasource/DataSourceTransactionManager.java

基于注解的声明式事务管理配置
spring-servlet.xml

 

spring事务特性

spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口

 

 

publicinterface PlatformTransactionManager {

  

  TransactionStatus getTransaction(TransactionDefinition definition)

    throws TransactionException;

  

  void commit(TransactionStatus status) throws TransactionException;

  

  void rollback(TransactionStatus status) throws TransactionException;

}

其中TransactionDefinition接口定义以下特性:

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • transactiondefinition.isolation_default:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是transactiondefinition.isolation_read_committed
  • transactiondefinition.isolation_read_uncommitted:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如postgresql实际上并没有此级别。
  • transactiondefinition.isolation_read_committed:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
  • transactiondefinition.isolation_repeatable_read:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
  • transactiondefinition.isolation_serializable:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
    • @Transactional注解
    • @Transactional属性
    •   

  

属性

类型

描述

value 

String 

可选的限定描述符,指定使用的事务管理器

propagation 

enum: Propagation 

可选的事务传播行为设置

isolation 

enum: Isolation 

可选的事务隔离级别设置

readOnly 

boolean 

读写或只读事务,默认读写

timeout 

int (in seconds granularity) 

事务超时时间设置

rollbackFor 

Class对象数组,必须继承自Throwable

导致事务回滚的异常类数组

rollbackForClassName 

类名数组,必须继承自Throwable

导致事务回滚的异常类名字数组

noRollbackFor 

Class对象数组,必须继承自Throwable

不会导致事务回滚的异常类数组

noRollbackForClassName 

类名数组,必须继承自Throwable

不会导致事务回滚的异常类名字数组

 

 

用法

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protectedprivate 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

 

 

出现了注入失败的问题

 

spring mvc加入aop拦截实现事务处理,导致ioc注入失败

重点是AOP导致了IOC失败

原因是spring拦截了过多的方法,在我的应用里,希望的是只需要拦截service中的方法,但实际也拦截了controller的方法.

导致了IllegalArgumentException异常明显是参数类型的问题.

解决方式:只拦截指定类的方法

<aop:config proxy-target-class="true">

    <aop:pointcut id="pcut" expression="execution(* org.anyline.service.*.*(..))" />

    <aop:advisor advice-ref="txAdvice" pointcut-ref="pcut" />

</aop:config>

注意:proxy-target-class="true"

proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK 基于接口的代理将起作用。

即使你未声明 proxy-target-class="true" ,但运行类没有继承接口,spring也会自动使用CGLIB代理。

高版本spring自动根据运行类选择 JDK 或 CGLIB 代理

异常输出

 

 

 

 

 

https://github.com/zhang570221322/AllTest.git 代码位置

 

原创粉丝点击