spring 复习整理四(仗剑走天涯) spring 框架的事务抽象 三个关键类 TransactionManager org.springframework.transaction.PlatformTransactionManager接口用于为不同平台提供统一抽象的事务管理器,重要
org.springframework.transaction.ReactiveTransactionManager接口用于响应式事务管理,这个不重要
1 2 3 4 5 6 7 8 9 public  interface  PlatformTransactionManager  extends  TransactionManager      TransactionStatus getTransaction (@Nullable  TransactionDefinition definition)  throws  TransactionException ;     void  commit (TransactionStatus status)  throws  TransactionException     void  rollback (TransactionStatus status)  throws  TransactionException } 
任何PlatformTransactionManager接口实现类的方法抛出的TransactionException是未检查的 它继承了java.lang.RuntimeException的类
TransactionDefinition TransactionDefinition 接口指定了当前事务的相关配置
Propagation:通常情况下,事务范围内的所有代码都在该事务中运行。 但是,如果事务方法在 已经存在事务的上下文中运行,则可以指定事务的传播行为
Isolation:该事务与其他事务的工作隔离的程度。 例如,这个事务可以看到其他事务未提交的写入吗 隔离级
Timeout:该事务在超时并被底层事务基础设施自动回滚之前运行多长时间
只读状态:当代码读取但不修改数据时,可以使用只读事务。 在某些情况下,如使用Hibernate时,只读事务可能是一种有用的优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public  interface  TransactionDefinition  	int  PROPAGATION_REQUIRED = 0 ; 	int  PROPAGATION_SUPPORTS = 1 ;    	int  PROPAGATION_MANDATORY = 2 ; 	int  PROPAGATION_REQUIRES_NEW = 3 ; 	int  PROPAGATION_NOT_SUPPORTED = 4 ; 	int  PROPAGATION_NEVER = 5 ; 	int  PROPAGATION_NESTED = 6 ; 	int  ISOLATION_DEFAULT = -1 ; 	int  ISOLATION_READ_UNCOMMITTED = 1 ;   	int  ISOLATION_READ_COMMITTED = 2 ;   	int  ISOLATION_REPEATABLE_READ = 4 ;   	int  ISOLATION_SERIALIZABLE = 8 ;   	int  TIMEOUT_DEFAULT = -1 ; 	default  int  getPropagationBehavior ()   		return  PROPAGATION_REQUIRED; 	} 	default  int  getIsolationLevel ()   		return  ISOLATION_DEFAULT; 	} 	default  int  getTimeout ()   		return  TIMEOUT_DEFAULT; 	} 	default  boolean  isReadOnly ()   		return  false ; 	} 	@Nullable  	default  String getName ()   		return  null ; 	} 	static  TransactionDefinition withDefaults ()   		return  StaticTransactionDefinition.INSTANCE; 	} 
TransactionStatus TransactionStatus接口为事务代码提供了一种简单的方法来控制事务执行和查询事务状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public  interface  TransactionStatus  extends  TransactionExecution , SavepointManager , Flushable      @Override           boolean  isNewTransaction ()      boolean  hasSavepoint ()      @Override           void  setRollbackOnly ()      @Override           boolean  isRollbackOnly ()      void  flush ()      @Override           boolean  isCompleted ()  } 
编程式事务管理 使用 TransactionManager 1 2 3 4 driverClass =com.mysql.cj.jdbc.Driver url =jdbc:mysql://localhost:3306/db_mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true user =root password =xiaobo 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <?xml version="1.0" encoding="UTF-8"?> <beans  xmlns ="http://www.springframework.org/schema/beans"         xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"         xmlns:p ="http://www.springframework.org/schema/p"         xmlns:context ="http://www.springframework.org/schema/context"         xmlns:aop ="http://www.springframework.org/schema/aop"         xsi:schemaLocation ="http://www.springframework.org/schema/beans          https://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/context         https://www.springframework.org/schema/context/spring-context.xsd         http://www.springframework.org/schema/aop         https://www.springframework.org/schema/aop/spring-aop.xsd" >    <context:property-placeholder  location ="jdbc.properties"  />      <context:component-scan  base-package ="com.dream.xiaobo.service"  />      <bean  id ="transactionManager"  class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >          <property  name ="dataSource"  ref ="druidDataSource" />      </bean >      <bean  id ="jdbcTemplate"  class ="org.springframework.jdbc.core.JdbcTemplate" >          <property  name ="dataSource"  ref ="druidDataSource" />      </bean >      <bean  id ="druidDataSource"  class ="com.alibaba.druid.pool.DruidDataSource" >          <property  name ="driverClassName"  value ="${driverClass}"  />          <property  name ="url"  value ="${url}"  />          <property  name ="username"  value ="${user}"  />          <property  name ="password"  value ="${password}"  />      </bean >  </beans > 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @Service public  class  AccountServiceImpl  implements  AccountService      @Autowired      private  PlatformTransactionManager transactionManager;     @Autowired      private  JdbcTemplate jdbcTemplate;     @Override      public  void  transfer (String from, String to, Integer money)           TransactionDefinition definition = new  DefaultTransactionDefinition();         TransactionStatus transaction = transactionManager.getTransaction(definition);         try  {             String fromSql = "UPDATE account SET money = money - ? WHERE name = ?" ;             int  i = 1 / 0 ;             String toSql = "UPDATE account SET money = money + ? WHERE name = ?" ;             jdbcTemplate.update(fromSql,new  Object[]{                     money,                     from             });             jdbcTemplate.update(toSql,new  Object[]{                     money,                     to             });         }catch  (RuntimeException exception){             exception.printStackTrace();                          transactionManager.rollback(transaction);         }         transactionManager.commit(transaction);     } } 
使用TransactionTemplate 1 2 3 4 5 6 <bean  id ="transactionManager"  class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >         <property  name ="dataSource"  ref ="druidDataSource" />      </bean >  <bean  id ="transactionTemplate"  class ="org.springframework.transaction.support.TransactionTemplate" >         <property  name ="transactionManager"  ref ="transactionManager" />      </bean >  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Service public  class  AccountServiceImpl2  implements  AccountService      @Autowired      private  JdbcTemplate jdbcTemplate;     @Autowired      private  TransactionTemplate transactionTemplate;     @Override      public  void  transfer (String from, String to, Integer money)           transactionTemplate.execute(new  TransactionCallbackWithoutResult() {             @Override              protected  void  doInTransactionWithoutResult (TransactionStatus status)                   String fromSql = "UPDATE account SET money = money - ? WHERE name = ?" ;                 int  i = 1 / 0 ;                 String toSql = "UPDATE account SET money = money + ? WHERE name = ?" ;                 jdbcTemplate.update(fromSql,new  Object[]{                         money,                         from                 });                 jdbcTemplate.update(toSql,new  Object[]{                         money,                         to                 });             }         });     } } 
new TransactionCallback<Object>() {} 带返回值
new TransactionCallbackWithoutResult(){} 不带返回值
声明式事务管理  Spring Framework的TransactionInterceptor为命令式和响应式编程模型提供了事务管理  拦截器通过检查方法返回类型来检测所需的事务管理风格 事务管理风格会影响需要哪个事务管理器 命令式事务需要PlatformTransactionManager 而响应式事务使用 ReactiveTransactionManager 实现
@Transactional 通常用于PlatformTransactionManager 管理的 线程绑定事务 将事务暴露给当前执行线程中的所有数据访问操作
1 2 3 4 5 6 7 8 9 10 11 12 <tx:advice  id ="interceptor"  transaction-manager ="transactionManager" >         <tx:attributes >              <tx:method  name ="get*"  read-only ="true" />                           <tx:method  name ="*" />          </tx:attributes >      </tx:advice >      <aop:config >          <aop:pointcut  id ="point"  expression ="execution(public * com.dream.xiaobo.service..*(..))" />          <aop:advisor  advice-ref ="interceptor"  pointcut-ref ="point"  />      </aop:config >  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public  class  TxAdvice  implements  MethodInterceptor      private  PlatformTransactionManager transactionManager;     public  void  setTransactionManager (PlatformTransactionManager transactionManager)           this .transactionManager = transactionManager;     }     @Override      public  Object invoke (MethodInvocation methodInvocation)  throws  Throwable          TransactionDefinition definition = new  DefaultTransactionDefinition();         TransactionStatus transaction = transactionManager.getTransaction(definition);         Object invoke = null ;         try  {             invoke = methodInvocation.getMethod().invoke(                     methodInvocation.getThis(),                     methodInvocation.getArguments()             );         }catch  (RuntimeException exception){             exception.printStackTrace();             transactionManager.rollback(transaction);             throw   new  RuntimeException("出现异常了" );         }         transactionManager.commit(transaction);         return  invoke;     } } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public  void  transfer2 (String from, String to, Integer money)          String fromSql = "UPDATE account SET money = money - ? WHERE name = ?" ;         int  i = 1 / 0 ;         String toSql = "UPDATE account SET money = money + ? WHERE name = ?" ;         jdbcTemplate.update(fromSql,new  Object[]{                 money,                 from         });         jdbcTemplate.update(toSql,new  Object[]{                 money,                 to         });     } 
事务回滚 在其默认配置中,Spring框架的事务基础结构代码只在运行时、未检查的异常情况下标记事务进行回滚。 也就是说,当抛出的异常是 RuntimeException 的实例或子类时 (默认情况下,Error 实例也会导致回滚) 事务方法抛出的已检查异常不会导致默认配置的回滚
指定回滚规则 1 2 3 4 5 6 <tx:advice  id ="txAdvice"  transaction-manager ="txManager" >     <tx:attributes >      <tx:method  name ="get*"  read-only ="true"  rollback-for ="NoProductInStockException" />      <tx:method  name ="*" />      </tx:attributes >  </tx:advice > 
指定无回滚规则 1 2 3 4 5 6 <tx:advice  id ="txAdvice" >     <tx:attributes >      <tx:method  name ="updateStock"  no-rollback-for ="InstrumentNotFoundException" />      <tx:method  name ="*" />      </tx:attributes >  </tx:advice > 
默认配置 
属性介绍 嵌套在tx:advice/ 和tx:attributes/ 标签中的tx:method/ 标签的各种属性如下
属性 
Required? 
默认值 
描述 
 
 
name 
Yes 
要与事务属性相关联的方法名 
通配符()字符可用于将相同的事务属性设置与许多方法相关联(例如,’ get ‘、’ handle* ‘、’ on*Event ‘等等) 
 
propagation 
No 
REQUIRED 
事务传播行为 
 
isolation 
No 
DEFAULT    事务隔离级别 
仅适用于’ REQUIRED ‘或’ REQUIRES_NEW ‘的传播设置 
 
timeout 
No 
-1    事务超时(秒) 
仅适用于传播’ REQUIRED ‘或’ REQUIRES_NEW ‘ 
 
read-only 
No 
false    读写事务与只读事务 
只适用于’ REQUIRED ‘或’ REQUIRES_NEW ‘ 
 
rollback-for 
No 
触发回滚的“Exception”实例的逗号分隔列表例如,“com.foo.MyBusinessException, ServletException” 
 
no-rollback-for 
No 
不触发回滚的“Exception”实例的逗号分隔列表例如,“com.foo.MyBusinessException, ServletException” 
 
@Transactional @Transactional 注解是元数据,它指定接口、类或方法必须具有事务性语义
1 @EnableTransactionManagement 
1 <tx:annotation-driven  transaction-manager ="txManager" /> 
如果要连接的TransactionManager 的bean名称为 TransactionManager  则可以省略 tx:annotation-driven 标记中的 transaction-manager 属性
事务传播 事务的传播通常发生在【一个service层中的方法】调用【其他service层中的方法】,虽然我们并不推荐这么做,但是的确会存在一个【大的业务】包含多个【小业务】,大业务和小业务都可独立运行的场景
传播行为 
含义 
 
 
PROPAGATION_REQUIRED 
表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务 
 
PROPAGATION_SUPPORTS 
表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行 
 
PROPAGATION_MANDATORY 
表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 
 
PROPAGATION_REQUIRED_NEW 
表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager 
 
PROPAGATION_NOT_SUPPORTED 
表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager 
 
PROPAGATION_NEVER 
表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 
 
PROPAGATION_NESTED 
表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。 
 
隔离级别 
含义 
 
 
ISOLATION_DEFAULT 
使用后端数据库默认的隔离级别 
 
ISOLATION_READ_UNCOMMITTED 
最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 
 
ISOLATION_READ_COMMITTED 
允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 
 
ISOLATION_REPEATABLE_READ 
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 
 
ISOLATION_SERIALIZABLE 
最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的 
 
spring简单整合mybatis 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 <dependencies >         <dependency >              <groupId > junit</groupId >              <artifactId > junit</artifactId >              <version > 4.13.2</version >              <scope > test</scope >          </dependency >                   <dependency >              <groupId > org.springframework</groupId >              <artifactId > spring-context</artifactId >              <version > 5.2.18.RELEASE</version >          </dependency >                   <dependency >              <groupId > ch.qos.logback</groupId >              <artifactId > logback-classic</artifactId >              <version > 1.2.10</version >          </dependency >                   <dependency >              <groupId > javax.annotation</groupId >              <artifactId > javax.annotation-api</artifactId >              <version > 1.3.2</version >          </dependency >          <dependency >              <groupId > com.alibaba</groupId >              <artifactId > druid</artifactId >              <version > 1.2.8</version >          </dependency >                   <dependency >              <groupId > org.aspectj</groupId >              <artifactId > aspectjweaver</artifactId >              <version > 1.9.6</version >          </dependency >          <dependency >              <groupId > mysql</groupId >              <artifactId > mysql-connector-java</artifactId >              <version > 8.0.11</version >          </dependency >                   <dependency >              <groupId > org.springframework</groupId >              <artifactId > spring-jdbc</artifactId >              <version > 5.3.19</version >          </dependency >          <dependency >              <groupId > org.mybatis</groupId >              <artifactId > mybatis</artifactId >              <version > 3.5.5</version >          </dependency >          <dependency >              <groupId > org.mybatis</groupId >              <artifactId > mybatis-spring</artifactId >              <version > 2.0.2</version >          </dependency >          <dependency >              <groupId > org.projectlombok</groupId >              <artifactId > lombok</artifactId >              <version > 1.18.16</version >          </dependency >      </dependencies >  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <?xml version="1.0" encoding="UTF-8"?> <beans  xmlns ="http://www.springframework.org/schema/beans"         xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"         xmlns:p ="http://www.springframework.org/schema/p"         xmlns:context ="http://www.springframework.org/schema/context"         xmlns:aop ="http://www.springframework.org/schema/aop"         xmlns:tx ="http://www.springframework.org/schema/tx"         xmlns:mybatis ="http://mybatis.org/schema/mybatis-spring"         xsi:schemaLocation ="http://www.springframework.org/schema/beans          https://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/context         https://www.springframework.org/schema/context/spring-context.xsd         http://www.springframework.org/schema/aop         https://www.springframework.org/schema/aop/spring-aop.xsd         http://www.springframework.org/schema/tx         https://www.springframework.org/schema/tx/spring-tx.xsd         http://mybatis.org/schema/mybatis-spring         https://mybatis.org/schema/mybatis-spring.xsd         " >    <context:property-placeholder  location ="jdbc.properties"  />      <context:component-scan  base-package ="com.dream.xiaobo"  />      <mybatis:scan  base-package ="com.dream.xiaobo.dao"  />      <bean  id ="sqlSessionFactory"  class ="org.mybatis.spring.SqlSessionFactoryBean" >          <property  name ="dataSource"  ref ="druidDataSource" />          <property  name ="configLocation"  value ="classpath:mybatis-config.xml" />          <property  name ="mapperLocations"  value ="classpath*:mapper/**/*.xml"  />      </bean >      <bean  id ="transactionManager"  class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >          <property  name ="dataSource"  ref ="druidDataSource" />      </bean >      <bean  id ="druidDataSource"  class ="com.alibaba.druid.pool.DruidDataSource" >          <property  name ="driverClassName"  value ="${driverClass}"  />          <property  name ="url"  value ="${url}"  />          <property  name ="username"  value ="${user}"  />          <property  name ="password"  value ="${password}"  />      </bean >  </beans > 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration          PUBLIC  "-//mybatis.org//DTD Config 3.0//EN"          "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration >     <settings >                            <setting  name ="lazyLoadingEnabled"  value ="true" />                   <setting  name ="aggressiveLazyLoading"  value ="false" />                   <setting  name ="logImpl"  value ="SLF4J" />          <setting  name ="logPrefix"  value ="mybatis.sql." />                   <setting  name ="mapUnderscoreToCamelCase"  value ="true"  />      </settings >           <typeAliases >                            <package  name ="com.dream.xiaobo.entity" />      </typeAliases >  </configuration > 
1 2 3 4 driverClass =com.mysql.cj.jdbc.Driver url =jdbc:mysql://localhost:3306/db_mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 user =root password =xiaobo 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper          PUBLIC  "-//mybatis.org//DTD Mapper 3.0//EN"          "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper  namespace ="com.dream.xiaobo.dao.UserMapper" >     <resultMap  id ="userMap"  type ="com.dream.xiaobo.entity.User" >          <id  column ="id"  property ="id"  />          <result  column ="username"  property ="username"  />          <result  column ="password"  property ="password"  />      </resultMap >      <sql  id ="sql" >          id,username,password     </sql >      <select  id ="selectUser"  resultType ="com.dream.xiaobo.entity.User" >          SELECT <include  refid ="sql"  />          FROM `user`     </select >  </mapper > 
你知道的越多 你不知道的越多 嘿 我是小博 带你一起看我目之所及的世界……