Spring整合持久层
- Spring技术为什么要与持久层技术进行整合?
1、JavaEE开发过程中我们需要持久才能进行数据库的访问操作。
2、JDBC Hibernate MyBatis进行持久层过程中存在大量的代码冗余。
3、Spring基于模板设计模式对这些持久层技术呢作出了封装。
ps注释:
Spring基于模板设计模式对持久层框架封装之后呢,开发效率提升很多
- Spring能与哪些持久层技术进行整合呢?
目前所有的主流层持久层技术都能进行整合
JDBC:基于JDBCSpring提出了一个JDBCTemplate这样的一个类对JDBC进行了封装,这是它与JDBC的整合
Hibernate(JPA):基于HibernateSpring提出了HibernateTemplate这样的一个工具类对Hibernate进行了封装
MaBatis:基于Mybatis,Spring提供了SqlSessionFactoryBean MapperScannerConfigure这样的工具类简化Mybatis开发
Spring整合MyBatis
Spring整合Mybatis的本质在于Spring对于Mybatis的使用有不满意的地方,所以对Mybatis作出合理的封装,使持久层开发变得更加的简洁。
- Mybatis的开发过程(七步)
1、实体
2、实体别名
3、建立表
4、创建Dao接口
5、实现Mapper文件
6、注册Mapper文件
7、MybatisApi的调用
Mybatis开发存在的问题
配置繁琐,代码冗余
1、配置了使用别名,这样的配置文件就很繁琐,这样的配置大量出现。
2、所有的Mapper文件都需要注册到核心配置文件上。
3、Mybatis开发过程总Api调用过程中创建SqlSession对象的也很冗余
4、获取Mapper对象的时候也非常的冗余
Spring整合Mybatis整合思路分析
** Spring整合Mybatis的目的在于简化Mybatis开发,主要是从两个方面着手:
1、Spring对于创建SqlSessionFactory对象的创建过程做了一个封装,Spring提供了一个SqlSessionFactoryBean专门用于创建SqlSessionFactory对象,我们在Spring当中只需要在配置文件中进行响应的配置,将这个SqlSessionFactoryBean配置到Spring的核心配置文件当中,交由Spring工厂创建他的对象,经过这样的配置,这个对象就被创建出来,在创建这个类的时候,mybatis读取了一个Mybatis-config.xml的配置问价你,作为这个配置文件来讲,这个配置文件起的作用可以划分为三个环节,第一个是连接池的配置,第二个是类别名的配置,第三个是Sql文件的注册,Mybatis现在需要的这三块内容,在Spring当中通过注入的方式来提供给Mybatis,怎么来完成呢?这里个我们使用的依赖注入的方式,在bean标签当中通过Property标签,name属性是dataSource的属性、typeAliasesPackage、mapperLocations这三个属性,这样原有Mabatis核心配置文件中的三块 内容就通过注入的形式来注入到SqlSessionFactoryBean当中,然后可以为工厂对象创建提供材料,所以,Mybatis核心配置文件也就没有用了。那么这三个注入的三个属性是具体怎么实现的呢?连接池也是一个对象,dataSource是连接池对象,这里应该注入的是Spring整合的连接池对象的ref,引用这个而连接池对象之前需要把连接池对象创建出来,通过bean标签把连接池对象创建出来,连接池是一个用户自建的对象,我们使用Bean前创建好之后,把他进行注入即可。指定实体所对应的包就可以了,里边的实体类就Spring会我们自动创建别名,这个别名就是类名,这个属性在英勇过程中更加的强大,只需要指定包就可以了,对于这个Mapper注册,Spring整合Mybatis的时候MapperLocation当中采用了通配的设置,基于通配的方式例如:Mapper.xml就可以全部注册进去。
2、Spring对于创建代理对象的封装比较简单,提供了一个类MapperScannerConfigure这个类,他需要两个要素,一个是SqlSessionFactory对象,一个是Dao层的Class对象,在Bean当中,把SqlSessionFactoryBean注入进去就可以拿到工厂对象,另一个就是Dao接口的class对象,我们指定basePackage的属性,执行这个包名,就可以生成对于Dao的实现类的对象,最终通过这个MapperScannerConfigure这个类就可以创建Dao的实现类的对象,我们这个工具类当中创建的Dao实现类的对象,他们的id值是接口首单词首字母小写。*
Spring与Mybatis整合的开发步骤
配置原理
**1、配置文件:applicationContext.xml文件的配置
第一步:配置创建SqlSessionFactroy
在这一步当中,我们为了获取这个对象,就需要配置Spring为我们准备的SqlSessionFactoryBean这个类,配置好这个类之后呢就可以获取到SqlSessionFactory这个对象了,我们在Spring核心配置文件当中配置这个类的对象的时候,需要首先创建dataSource数据源的Bean的标签,创建他的对象,然后将这个对象使用Property标签引入到,SqlSessionFactoryBean的对象的创建中,然后需要配置类别名,这个也是对应一个Property标签中的一个typeAliasesPackage属性,在这个属性当中指定实体类所在的包,通过这个配置,以后我们的实体Bean只要是放到这个包中,那么在以后的Mybatis映射中,他的别名就叫做他的类名。然后第三个需要注入的属性是配置文件或者映射文件的路径通用配置等,将来我们的Mapper文件将会放到一个特定的目录里,我们一方面制定了这个目录对应的路径信息,另一方面,我们使用一种通配的方式来适配所有的Mapper文件(com.dashu.mapper/*Mapper.xml),这样就可以将所有的Mapper文件被Spring感知到,并将他们配置到SqlSessionFactory对象当中。这几块的配置极大地简化了开发。
第二步:配置创建DAO接口的实现类
为了实现这个第二部,Spring当中准备了一个MapperScannerConfigure这样的类,作为这个类,他主要的作用是通过session.getMapper()方法获取xxxDao实现类的对象,他这个实现类的XXXDao 实现类的id值是xXXDao,在这个对象当中他需要获取Session对象,通过Session对象获取这个类的dao实现类的对象。所以,在MapperScannerConfigure的Bean标签当中应该将SqlSessionFactoryBean的对象的id值赋值给MapperScannerConfigure的sqlSessionFactoryBeanName属性,按照这个配置就可以找到SqlSessionFactoryBean这个对象,另外一个属性basePacakge指定的是放置Dao的具体的包,Spring通过扫描这个包创建包下所有的Dao的实现类。
总结:
以上的这两种配置的好处在于,只需要配置一次,以后所有的都不需要进行重新配置。
**
开发过程
1、实体Bean
2、表
3、创建Dao接口
4、实现Mapper文件
总结:这才是未来实战中写的代码。
- 搭建开发环境
所谓的搭建开发环境指的就是引入Jar包
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.dashu</groupId> <artifactId>spring-mybatis</artifactId> <version>V1.0.1</version> <dependencies> <!--引入druid数据源,这是一个连接池。--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.18</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.48</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!--Spring对Jdbc封装--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.14.RELEASE</version> </dependency> <!--这个是Spring和mybatis整合的JAR包--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> </dependencies> </project>
- Spring配置文件的配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--连接池--> <!--我们使用连接池的本质就是为了创建和数据库的链接。--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/tree?useSSL=false"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> <!--创建SqlSessionFactroyBean对象--> <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="com.dashu.entity"/> <property name="mapperLocations"> <list> <!--这是Spring里边内置的关键字代表Classes目录,也就是java目录--> <!--/旁边是路径名,/右边是命名规范。--> <value>classpath:com.dashu.mapper/*Mapper.xml</value> </list> </property> </bean> <!--创建Dao对象--> <bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/> <property name="basePackage" value="com.dashu.dao"/> </bean> </beans>
- 编码
package com.dashu.Dao; import com.dashu.entity.User; /** * @Auther: DaShu * @Date: 2021/7/26 20:29 * @Description: */ public interface UserDao { public void save(User user); }
package com.dashu.test; import com.dashu.Dao.UserDao; import com.dashu.entity.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @Auther: DaShu * @Date: 2021/7/26 20:47 * @Description: */ public class TestMybatisSpring { @Test public void test1(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); UserDao userDao =(UserDao) ctx.getBean("userDao"); User user = new User(); user.setAge(16); user.setName("liming"); userDao.save(user); } }
Spring整合Mybatis细节
2021-07-26 20:58:12 DEBUG ClassPathXmlApplicationContext:590 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@66d33a 2021-07-26 20:58:13 DEBUG XmlBeanDefinitionReader:396 - Loaded 3 bean definitions from class path resource [applicationContext.xml] 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'scanner' 2021-07-26 20:58:13 DEBUG LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2021-07-26 20:58:13 DEBUG ClassPathMapperScanner:437 - Identified candidate component class: file [D:\giteesource\jdbc\spring-mybatis\target\classes\com\dashu\dao\UserDao.class] 2021-07-26 20:58:13 DEBUG ClassPathMapperScanner:49 - Creating MapperFactoryBean with name 'userDao' and 'com.dashu.Dao.UserDao' mapperInterface 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSource' 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'sqlSessionFactoryBean' 2021-07-26 20:58:13 DEBUG SqlSessionFactoryBean:49 - Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration 2021-07-26 20:58:13 DEBUG SqlSessionFactoryBean:49 - Parsed mapper file: 'file [D:\giteesource\jdbc\spring-mybatis\target\classes\com.dashu.mapper\UserDaoMapper.xml]' 2021-07-26 20:58:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userDao' 2021-07-26 20:58:13 DEBUG SqlSessionUtils:49 - Creating a new SqlSession 2021-07-26 20:58:13 DEBUG SqlSessionUtils:49 - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@152aa092] was not registered for synchronization because synchronization is not active 2021-07-26 20:58:13 DEBUG DataSourceUtils:115 - Fetching JDBC Connection from DataSource 2021-07-26 20:58:14 INFO DruidDataSource:1003 - {dataSource-1} inited 2021-07-26 20:58:14 DEBUG SpringManagedTransaction:49 - JDBC Connection [com.mysql.jdbc.JDBC4Connection@25fb8912] will not be managed by Spring 2021-07-26 20:58:14 DEBUG save:159 - ==> Preparing: Insert into tree (name,age) values (?,?) 2021-07-26 20:58:14 DEBUG save:159 - ==> Parameters: liming(String), 16(Integer) 2021-07-26 20:58:14 DEBUG save:159 - <== Updates: 1 2021-07-26 20:58:14 DEBUG SqlSessionUtils:49 - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@152aa092]
1、单纯使用Mybatis进行开发的时候,我们一定会手动记性提交事务,在代码sql执行完毕之后,会有一个session.commit()来提交事务,但是现在使用Spring整合Mybatis之后,并没有在代码中体现事务提交, 这个Dao对象由Spring来为我们进行创建的时候,我们并没有手动提交事务,为什么数据可以插入到数据库当中呢?Connection对象是链接对象,连接对象控制着事务,谁控制着连接对象就变相控制着事务,在整个Spring整合Mybatis之后是谁控制着链接对象呢?在刚才的运行日志中,链接对象并不是交由Spring进行管理,那不是Spring就是Mybatis,本质上控制Connection对象,是连接池对象,当我们使用单纯Mybatis进行开发的时候,Mybatis提供的连接池对象创建链接,Spring和Mybatis整合之后,我们使用的是Druid连接池,他负责Connection对象的创建,这样使用和当时Mybatis提供连接池创建链接对象,有着细微的差别,Mybatis使用自身连接池创建对象之后,调用了一个Connection.setAutoCommit(false),这样就把链接对象中的事务控制改为了手动,这样在操作完成之后,必须手工提交,这就是在Mybatis原生开发的时候必须手动提交,而使用Druid连接池的时候,Connection.setAutoCommit(true)这是默认值,意味着保持着自动控制事务,就是完成一条SQL操作就会自动提交事务,所以,我们使用了Druid链接池之后,是自动提交事务,不需要手动提交。日后换成了其他的连接池之后,都一样,他们的都是true,都是自动提交事务,一条SQL语句都会自动的提交。
答案:Spring和Mybatis整合时引入外部连接池,,保持着自动提交事务的机制(Connection.setaAutoCommit(true)不需要手动提交事务)
注意:
未来实战中,我们设计到多条SQL提交,我们需要把多条SQL设置成一个整体,手工控制成一个事务(Sql一起成功,一起失败),将来呢在Spring当中,Spring会通过他的事务控制,解决这个问题
Spring事务处理
什么是事务?
保证业务操作完整性的数据库操作,就是数据库中的操作要么一起成功要么 一起失败,而且不能产生响应的影响,事务这个概念是数据库的范畴,我们通过Java代码只是完成对这种机制的调用。
事务的ACID
1、原子性:一起成功一起失败
2、一致性:与实际发生相一致
3、隔离性:事务之间不可以相互访问
4、持久性:持久到数据库
如何来控制事务
这里我们先不考虑Spring
JDBC控制事务
Connection.setAutoCommit(false)开启事务
ConnectIon.commit()提交事务
Connection,rollback()回滚事务
其核心就是控制Connection链接对象来控制事务
Mybatis控制事务
Mybatis自动开启事务
sqlSession.commit()提交事务
sqlSession.rollback()回滚事务
总结:开启-提交-回滚
Mybatis底层的SqlSession底层也是封装的Connection,底层也是调用的是Connection.commit,不论是当前的jdbc还是Mybatis当中的sqlSession还是将来的jta,底层都是调用的Connection.commit,封装的都是COnnection对象,所有的技术,我们看到
的表象是不一样的,但是底层都是一样的,以上的都是不讨论Spring的事务控制的前提下。
Spring控制事务开发
开发步骤
事务是业务开发过程中的额外功能,因为是额外功能所以我们可以采用Aop的方式来进行开发,Spring当中的事务是通过Aop的方式来进行控制事务开发的
1、原始对象
(1)这里的原始对象就是XXXUserServiceImpl中的方法,核心功能(业务功能+Dao的调用)
(2)我们要把Dao作为Service的成员边量,通过Spring的方式进行依赖注入的方式进行赋值,并为他提供get,set方法。
2、额外功能
(1)第一种实现MethodInterceptor,在里面的invoke方法中调用原始对象原始方法,并进行额外功能编写,如果原始方法抛出异常,我们就进行事务的回滚。
(2)@Aspect @Around这种方式呢实现原理是一样的,我们可以把开启提交回滚的代码写在额外功能当中,所以Spring也会写,所以呢,Spring框架就直接把这个代码给写了,给分装好了,我们直接用即可,那我们在org.springframework.jdbc.datasourceDataSourceTransactionManager这里边把这个给封装好了,这里边就是事务控制的额外功能,只需要用好这个类就行,要想这个类起作用,就需要在额外功能中对这个连接对象的支持和配合,所以说DataSourceTranSactionManager依赖连接对象,我们需要给她注入连接,但是我们现在引入了连接池,现在呢连接来自于连接池,所以把连接池注入给她即可,这样这个类就可以基于连接池对象完成对事物的控制。在这里我们需要注意两个要点,第一个代码不用我们写了,Spring已经帮我们写好了,第二个要点,我们是用Spring进行实物控制的时候需要为这个类注入连接池对象,有了连接池对象就等效于有了链接,就可以控制事务了。
3、切入点
@Transactionl就可以控制事务了
应用这个注解就可以给业务方法加入事务控制了。
1、类上:类中所有方法都会加入事务
2、方法上:这个方法会加入事务
4、组装切面
切面一定是有两个部分组成的,
1、切入点
2、额外功能
在Spring进行实物控制的时候,他的组装切面的时候是通过标签来控制的,在标签当中会体现这两个元素。
<tx:annotation-driven transaction-manager=“”/>这个属性适用于获取额外功能,切入点他自己会直接 扫描注解来组装注解信息,引入这个标签我们就组装好了事务的切面。
Spring控制事务的编码
搭建开发环境
引入响应的jar包,Spring引入事务控制的时候,他有开发了一个jar包需要我们引入进来,Spring-tx,引入这个jar包就把Spring与事务整合的Jar包引入了进来。
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.1.14.RELEASE</version> </dependency>
原始对象和切入点
package com.dashu.service; import com.dashu.Dao.UserDao; import com.dashu.entity.User; import org.springframework.transaction.annotation.Transactional; /** * @Auther: DaShu * @Date: 2021/7/26 22:36 * @Description: */ /*定义切入点*/ @Transactional public class UserServiceImpl implements UserService{ private UserDao userDao; public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void register(User user) { userDao.save(user); } }
额外功能和切面组装
<!--DataSourceTransactionManager--> <bean id="dataSourceTransactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--组装事物切面,选择Tx结尾的。--> <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
测试Spring事务处理
@Test public void test2(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); UserService userService = (UserService) ctx.getBean("userService"); User user = new User(); user.setName("张晓哎"); user.setAge(21); userService.register(user); }
测试结果打印
2021-07-26 22:54:34 DEBUG ClassPathXmlApplicationContext:590 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@66d33a 2021-07-26 22:54:34 DEBUG XmlBeanDefinitionReader:396 - Loaded 10 bean definitions from class path resource [applicationContext.xml] 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'scanner' 2021-07-26 22:54:34 DEBUG LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2021-07-26 22:54:34 DEBUG ClassPathMapperScanner:437 - Identified candidate component class: file [D:\giteesource\jdbc\spring-mybatis\target\classes\com\dashu\dao\UserDao.class] 2021-07-26 22:54:34 DEBUG ClassPathMapperScanner:49 - Creating MapperFactoryBean with name 'userDao' and 'com.dashu.Dao.UserDao' mapperInterface 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSource' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' 2021-07-26 22:54:34 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'sqlSessionFactoryBean' 2021-07-26 22:54:34 DEBUG SqlSessionFactoryBean:49 - Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration 2021-07-26 22:54:35 DEBUG SqlSessionFactoryBean:49 - Parsed mapper file: 'file [D:\giteesource\jdbc\spring-mybatis\target\classes\com.dashu.mapper\UserDaoMapper.xml]' 2021-07-26 22:54:35 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userService' 2021-07-26 22:54:35 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userDao' 2021-07-26 22:54:35 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSourceTransactionManager' 2021-07-26 22:54:35 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0' 2021-07-26 22:54:35 DEBUG DataSourceTransactionManager:372 - Creating new transaction with name [com.dashu.service.UserServiceImpl.register]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 2021-07-26 22:54:35 INFO DruidDataSource:1003 - {dataSource-1} inited 2021-07-26 22:54:35 DEBUG DataSourceTransactionManager:265 - Acquired Connection [com.mysql.jdbc.JDBC4Connection@273444fe] for JDBC transaction 2021-07-26 22:54:35 DEBUG DataSourceTransactionManager:282 - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@273444fe] to manual commit 2021-07-26 22:54:35 DEBUG SqlSessionUtils:49 - Creating a new SqlSession 2021-07-26 22:54:35 DEBUG SqlSessionUtils:49 - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 22:54:35 DEBUG SpringManagedTransaction:49 - JDBC Connection [com.mysql.jdbc.JDBC4Connection@273444fe] will be managed by Spring 2021-07-26 22:54:35 DEBUG save:159 - ==> Preparing: Insert into tree (name,age) values (?,?) 2021-07-26 22:54:35 DEBUG save:159 - ==> Parameters: 张晓哎(String), 21(Integer) 2021-07-26 22:54:35 DEBUG save:159 - <== Updates: 1 2021-07-26 22:54:35 DEBUG SqlSessionUtils:49 - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 22:54:35 DEBUG SqlSessionUtils:49 - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 22:54:35 DEBUG SqlSessionUtils:49 - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 22:54:35 DEBUG SqlSessionUtils:49 - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 22:54:35 DEBUG DataSourceTransactionManager:743 - Initiating transaction commit 2021-07-26 22:54:35 DEBUG DataSourceTransactionManager:327 - Committing JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@273444fe] 2021-07-26 22:54:36 DEBUG DataSourceTransactionManager:385 - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@273444fe] after transaction
事务编码细节
1、上述测试实例并不能证明事务加进来了,因为原有逻辑可以完成插入操作的,事务加上没有一定是加上了,以下是验证细节
package com.dashu.service; import com.dashu.Dao.UserDao; import com.dashu.entity.User; import org.springframework.transaction.annotation.Transactional; /** * @Auther: DaShu * @Date: 2021/7/26 22:36 * @Description: */ /*定义切入点*/ @Transactional public class UserServiceImpl implements UserService{ private UserDao userDao; public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void register(User user) { userDao.save(user); throw new RuntimeException("测试异常"); } }
D:\DevelopPackage\jdk8\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\lib\idea_rt.jar=58943:D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\bin" -Dfile.encoding=UTF-8 -classpath "D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\lib\idea_rt.jar;D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\plugins\junit\lib\junit5-rt.jar;D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\plugins\junit\lib\junit-rt.jar;D:\DevelopPackage\jdk8\jre\lib\charsets.jar;D:\DevelopPackage\jdk8\jre\lib\deploy.jar;D:\DevelopPackage\jdk8\jre\lib\ext\access-bridge-64.jar;D:\DevelopPackage\jdk8\jre\lib\ext\cldrdata.jar;D:\DevelopPackage\jdk8\jre\lib\ext\dnsns.jar;D:\DevelopPackage\jdk8\jre\lib\ext\jaccess.jar;D:\DevelopPackage\jdk8\jre\lib\ext\jfxrt.jar;D:\DevelopPackage\jdk8\jre\lib\ext\localedata.jar;D:\DevelopPackage\jdk8\jre\lib\ext\nashorn.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunec.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunjce_provider.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunmscapi.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunpkcs11.jar;D:\DevelopPackage\jdk8\jre\lib\ext\zipfs.jar;D:\DevelopPackage\jdk8\jre\lib\javaws.jar;D:\DevelopPackage\jdk8\jre\lib\jce.jar;D:\DevelopPackage\jdk8\jre\lib\jfr.jar;D:\DevelopPackage\jdk8\jre\lib\jfxswt.jar;D:\DevelopPackage\jdk8\jre\lib\jsse.jar;D:\DevelopPackage\jdk8\jre\lib\management-agent.jar;D:\DevelopPackage\jdk8\jre\lib\plugin.jar;D:\DevelopPackage\jdk8\jre\lib\resources.jar;D:\DevelopPackage\jdk8\jre\lib\rt.jar;D:\giteesource\jdbc\spring-mybatis\target\classes;D:\DevelopPackage\repository\junit\junit\4.12\junit-4.12.jar;D:\DevelopPackage\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\DevelopPackage\repository\com\alibaba\druid\1.1.18\druid-1.1.18.jar;D:\DevelopPackage\repository\mysql\mysql-connector-java\5.1.48\mysql-connector-java-5.1.48.jar;D:\DevelopPackage\repository\org\mybatis\mybatis\3.4.6\mybatis-3.4.6.jar;D:\DevelopPackage\repository\org\springframework\spring-jdbc\5.1.14.RELEASE\spring-jdbc-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-beans\5.1.14.RELEASE\spring-beans-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-core\5.1.14.RELEASE\spring-core-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-jcl\5.1.14.RELEASE\spring-jcl-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-tx\5.1.14.RELEASE\spring-tx-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-context\5.1.4.RELEASE\spring-context-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-aop\5.1.4.RELEASE\spring-aop-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-expression\5.1.4.RELEASE\spring-expression-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\mybatis\mybatis-spring\2.0.2\mybatis-spring-2.0.2.jar;D:\DevelopPackage\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;D:\DevelopPackage\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\DevelopPackage\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.dashu.test.TestMybatisSpring,test2 2021-07-26 23:00:29 DEBUG ClassPathXmlApplicationContext:590 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@66d33a 2021-07-26 23:00:29 DEBUG XmlBeanDefinitionReader:396 - Loaded 10 bean definitions from class path resource [applicationContext.xml] 2021-07-26 23:00:29 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'scanner' 2021-07-26 23:00:29 DEBUG LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2021-07-26 23:00:29 DEBUG ClassPathMapperScanner:437 - Identified candidate component class: file [D:\giteesource\jdbc\spring-mybatis\target\classes\com\dashu\dao\UserDao.class] 2021-07-26 23:00:29 DEBUG ClassPathMapperScanner:49 - Creating MapperFactoryBean with name 'userDao' and 'com.dashu.Dao.UserDao' mapperInterface 2021-07-26 23:00:29 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 2021-07-26 23:00:29 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 2021-07-26 23:00:29 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory' 2021-07-26 23:00:29 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSource' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'sqlSessionFactoryBean' 2021-07-26 23:00:30 DEBUG SqlSessionFactoryBean:49 - Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration 2021-07-26 23:00:30 DEBUG SqlSessionFactoryBean:49 - Parsed mapper file: 'file [D:\giteesource\jdbc\spring-mybatis\target\classes\com.dashu.mapper\UserDaoMapper.xml]' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userService' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userDao' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSourceTransactionManager' 2021-07-26 23:00:30 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0' 2021-07-26 23:00:30 DEBUG DataSourceTransactionManager:372 - Creating new transaction with name [com.dashu.service.UserServiceImpl.register]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 2021-07-26 23:00:30 INFO DruidDataSource:1003 - {dataSource-1} inited 2021-07-26 23:00:31 DEBUG DataSourceTransactionManager:265 - Acquired Connection [com.mysql.jdbc.JDBC4Connection@273444fe] for JDBC transaction 2021-07-26 23:00:31 DEBUG DataSourceTransactionManager:282 - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@273444fe] to manual commit 2021-07-26 23:00:31 DEBUG SqlSessionUtils:49 - Creating a new SqlSession 2021-07-26 23:00:31 DEBUG SqlSessionUtils:49 - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 23:00:31 DEBUG SpringManagedTransaction:49 - JDBC Connection [com.mysql.jdbc.JDBC4Connection@273444fe] will be managed by Spring 2021-07-26 23:00:31 DEBUG save:159 - ==> Preparing: Insert into tree (name,age) values (?,?) 2021-07-26 23:00:31 DEBUG save:159 - ==> Parameters: xi(String), 21(Integer) 2021-07-26 23:00:31 DEBUG save:159 - <== Updates: 1 2021-07-26 23:00:31 DEBUG SqlSessionUtils:49 - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 23:00:31 DEBUG SqlSessionUtils:49 - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 23:00:31 DEBUG SqlSessionUtils:49 - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1972e513] 2021-07-26 23:00:31 DEBUG DataSourceTransactionManager:836 - Initiating transaction rollback 2021-07-26 23:00:31 DEBUG DataSourceTransactionManager:342 - Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@273444fe] 2021-07-26 23:00:31 DEBUG DataSourceTransactionManager:385 - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@273444fe] after transaction java.lang.RuntimeException: 测试异常 at com.dashu.service.UserServiceImpl.register(UserServiceImpl.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy18.register(Unknown Source) at com.dashu.test.TestMybatisSpring.test2(TestMybatisSpring.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53) Process finished with exit code -1
第二个细节,是 --proxy-target-class="false"这是默认属性,默认是false,可以设置成true,设置成true就是使用cglib动态代理。
<tx:annotation-driven transaction-manager=“dataSourceTransactionManager” proxy-target-class=“false”/>完成动态代理底层的切换。
Spring的事务属性
什么是事务属性
什么是属性:描述物体特征的一系列值,描述特征的值有差异,所以就有好看不好看的概念,事务的属性和事务的特征就是描述事务特征的一系列值
1、隔离属性
2、传播属性
3、只读属性
4、超时属性
5、异常属性
如何添加事务属性
我们在开发过程中添加上这些事务的属性就可以控制事务的特征
@Transactionnal(isoLation=,propagation=,readOnly=,timeout=,rollbackFor,NoRollbackFor=)用于描述传播属性)这个注解就可以用来配置属性。
事务属性详解
1、隔离属性
**概念:描述了事务解决并发问题的特征
1、什么是并发?
多个事务(用户)同一时间访问操作了相同的数据。
例如:一张表中有四条数据,有一个事务1访问了第一行数据,第二个事务同事也访问了第一行数据,这样就产生了并发问题。同一时间、同一数据。同一时间也是有一个微小前后的差异
2、并发会产生什么问题?
(1)脏读
(2)不可重复读
(3)幻读
3、并发问题如何解决?
实际上及时隔离属性和对应的值解决的工作。我们在隔离属性中设置不同的值解决并发处理过程中的问题,在事务属性的概念中,并发会产生问题,并发的问题可以通过隔离属性来进行解决。
**
- 脏读
概念:一个事务读取了另一个事物当中没有提交的数据。另一个事物一回滚数据就错了。产生这个问题的核心就是读取了事务没有提交的数据,前者一回滚,后者就凉凉。
解决方案:@Transactional(isolation=Isolation.READ_COMMIT)读已提交的数据,这样就可以避免脏读的产生。
@Transactional(isolation = Isolation.READ_COMMITTED)
- 不可重复读
概念:一个事务中多次获取相同的数据,但是获取每次的结果不一致
例如:A开始事务查询某一行数据,获取到第一次的值,B开始一次事务update一次,然后快速提交事务,A操作完其他行数据过来又查了一遍,成了800;这就是不可重复读。在A的操作过程中出现了数据不一致的情况。不可重复读获取到的不是事务未提交的脏数据,这些数据已经提交了,不可能被回滚了,一个事务中对一组数据只进行了查询,本来今天查一次1000,明天查一次800这样很正常,只不过在今天的一次事务中就读取到了不一致, 结果就有点尴尬,这样后续处理的时候就不知道以哪个值为基准了,这样就是不可重复读的危害,不可重复读不是脏读,他读取的事已经提交的数据,她是在一个事务中发生的这样的情况。解决方案:@Transactional(isolation = Isolation.REPEATABLE_READ),我们加上这样代码之后数据库会为我们操作的这几行数据加上一把行锁。他的底层本质就是一把行锁。这样只有等第一个事务提交之后,第二个事务才能获取到这个行锁进行操作这个数据。
本质:一把行锁
@Transactional(isolation = Isolation.REPEATABLE_READ)
- 幻影读
概念:一个事物中多次对整表进行查询统计,但是结果不一样,会产生本事务中数据不一致的问题。
关键字:整表操作:例如Count(balance),结果不一样。
解决方案:@Transactional(isolation = Isolation.SERIALIZABLE)
本质:表锁
@Transactional(isolation = Isolation.SERIALIZABLE)
事务隔离属性的总结
并发安全:@Transactional(isolation = Isolation.SERIALIZABLE)最安全,锁住所有的表,别人用表中数据的时候只能等着,并发安全最高,另外是@Transactional(isolation = Isolation.REPEATABLE_READ)他是为数据添加了行锁,别人操作这一行的时候,别人别搞,最差的是@Transactional(isolation = Isolation.READ_COMMITTED),这个只要求读取别人提交之后的数据,而没有添加任何额外限制,并发安全最低。
运行效率:整好反过来。
数据库对于隔离属性的支持
并不是所有的数据库对以上四个属性都支持
Oracle不支持这个值,是如何解决不可重复读的呢?他没有采用隔离属性的方式来解决,而是采用多版本比对的方式来解决不可重复读的问题。
默认的隔离属性:如果程序员不指定隔离属性的话Spring会指定默认的隔离属性,Isolation-default这是Spring默认帮我们设置的,表达的含义是调用不同数据库所设置的默认隔离属性,对应Mysql和Oracle就是如下的值:。
MySql是:Isolation.REPEATABLE_READ
Oracle是:Isolation.READ_COMMITTED
隔离属性在实战中的建议
隔离属性实战过程中,我们推荐使用Spring的默认值ISOLATION_DEFAULT,为什么推荐使用这个?不用写,未来的实战过程中,并发访问的情况本身就很低,必须有一个前提:海量用户,并发可能性很低,为了可能遇到问题直接加表锁,这样是很不合理的。如果真的遇到这种并发问题了,我们有限推荐的方案也不是隔离属性来解决,而是采用乐观锁的方式,乐观锁是应用锁,不会过多影响我们的效率,隔离属性是物理锁,物理锁对效率影响比较大。Hibernate(JPA) 通过Version的方式进行控制乐观锁,Mybatis中默认没有支持乐观锁,对于乐观锁的控制比较繁琐,需要定义Mybatis当中的拦截器进行自定义开发,在整个隔离属性的开发过程中,我们还是要优先保证效率,我们使用他默认的就行了。一旦遇到了并发问题,我们可以通过乐观锁的方式进行解决。
2、传播属性
概念:描述了事务解决嵌套问题的特征
事务的嵌套:事务之间的包含的关系,一个大事务之间包含一个或若干个小事务,这就是事务的嵌套的问题
事务的嵌套
什么场景会出现事务嵌套呢?
service调用Service会出现事务嵌套的
一旦出现了事务嵌套之后,会出现什么问题呢?
正常情况下是没有问题的,一旦C当中出现了异常,进行了回滚,那么C在A当中,C回滚,A也会回滚,此时A回滚了,C回滚了,但是B已经提交了,事务之间相互影响,违反原子性了。
传播属性的值及其用法
通过设置合理的事务属性之后,彼此之间就不存在事务的嵌套了。这样的话就实现了事务的原子性。他这个事务的传播属性搞定的就是同一时间只有一个事务属性在,没有嵌套的发生,只有最外层事务的存在。实际的开发过程中也就是通过注解属性的形式进行。REQUIRED这个属性经常用在增删改操作中,Supports这个属性值,经常用到查询的操作当中。
默认的传播属性
也就是说程序员不手动进行设置传播属性的话,Spring会默认为我们设置传播属性,默认值对应的值是PROPAGATION_REQUIRED,这个是传播属性的默认值,这个适用于增删改,查询的话,我们推荐Supports
建议:增删改方法:我们使用默认值就可以了(PROPAGATION_REQUIRED)
查询操作:我们显示的指定传播属性值为SUPPORTSREQUIRES_NEW:挂起外部事务,创建新的事务,的含义就是外部事物先暂停,内部事务开启执行提交,内部事务完成之后,在进行外部事务适用于在日志操做中,不管外部成功与否,否要把正常日志异常日志插入到数据库中
挂起外部事务,就是外部事务先暂停,先被挂起,内部业务并没有融合到外部事务中,仅仅执行而已,执行完毕之后在激活外部事务。
NOT_SUPPORTED 外部存在事务时挂起外部事务,执行内部逻辑,内部逻辑执行完毕之后,激活外部事物
其他两个:略
3、只读属性
**作用:针对于值进行查询操作的方法,我们可以加入这个只读属性,可以提高运行效率。确定了这个方法是只有查询,那么加上这个属性之后,就不会加上任何的锁了,查询效率就会变很高。
我们在类上加入@Transaction这个注解之后,全部方法都开启了事务,查询方法也开启了事务,对于Mysql来讲默认的隔离性是:Isolation.REPEATABLE_READ这个本质是行锁,那么在这个方法再次引入@Transaction这个注解之后,我们可以指定只读属性来覆盖类上的默认设定,这样的话查询的时候不用加锁,提高效率。
只读属性默认值:false
**
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true) public void login(String name,String password){ }
4、超时属性
概念:指定了了事务等待的最长时间
为什么事务需要等待呢?
某个用户访问某张表的第一行数据,加了一把行锁,第二个用户也发起对这一行数据的访问,那么第二个用户就需要进行等待,第二个用户最多可以等待多长时间呢?就是通过这个超时属性来设置的
等待的时间是以秒为单位,超时之后就会抛出超时异常。
如何进行应用呢?
超时属性默认值 -1 最终由对应的数据库来指定,每个数据库的产品都默认设置了这些值。
package com.dashu.service; import com.dashu.Dao.UserDao; import com.dashu.entity.User; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** * @Auther: DaShu * @Date: 2021/7/26 22:36 * @Description: */ /*定义切入点*/ @Transactional(timeout = 2) public class UserServiceImpl implements UserService{ private UserDao userDao; public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void register(User user) throws InterruptedException { Thread.currentThread().sleep(3000); userDao.save(user); throw new RuntimeException("测试异常"); } @Transactional(propagation = Propagation.SUPPORTS,readOnly = true) public void login(String name,String password){ } }
2021-07-27 21:48:45 DEBUG ClassPathXmlApplicationContext:590 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@66d33a 2021-07-27 21:48:45 DEBUG XmlBeanDefinitionReader:396 - Loaded 10 bean definitions from class path resource [applicationContext.xml] 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'scanner' 2021-07-27 21:48:46 DEBUG LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2021-07-27 21:48:46 DEBUG ClassPathMapperScanner:437 - Identified candidate component class: file [D:\giteesource\jdbc\spring-mybatis\target\classes\com\dashu\dao\UserDao.class] 2021-07-27 21:48:46 DEBUG ClassPathMapperScanner:49 - Creating MapperFactoryBean with name 'userDao' and 'com.dashu.Dao.UserDao' mapperInterface 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSource' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' 2021-07-27 21:48:46 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'sqlSessionFactoryBean' 2021-07-27 21:48:46 DEBUG SqlSessionFactoryBean:49 - Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration 2021-07-27 21:48:47 DEBUG SqlSessionFactoryBean:49 - Parsed mapper file: 'file [D:\giteesource\jdbc\spring-mybatis\target\classes\com.dashu.mapper\UserDaoMapper.xml]' 2021-07-27 21:48:47 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userService' 2021-07-27 21:48:47 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userDao' 2021-07-27 21:48:47 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSourceTransactionManager' 2021-07-27 21:48:47 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0' 2021-07-27 21:48:47 DEBUG DataSourceTransactionManager:372 - Creating new transaction with name [com.dashu.service.UserServiceImpl.register]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_2 2021-07-27 21:48:47 INFO DruidDataSource:1003 - {dataSource-1} inited 2021-07-27 21:48:48 DEBUG DataSourceTransactionManager:265 - Acquired Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] for JDBC transaction 2021-07-27 21:48:48 DEBUG DataSourceTransactionManager:282 - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] to manual commit 2021-07-27 21:48:51 DEBUG SqlSessionUtils:49 - Creating a new SqlSession 2021-07-27 21:48:51 DEBUG SqlSessionUtils:49 - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35841320] 2021-07-27 21:48:51 DEBUG SpringManagedTransaction:49 - JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] will be managed by Spring 2021-07-27 21:48:51 DEBUG SqlSessionUtils:49 - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35841320] 2021-07-27 21:48:51 DEBUG SqlSessionUtils:49 - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35841320] 2021-07-27 21:48:51 DEBUG SqlSessionUtils:49 - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35841320] 2021-07-27 21:48:51 DEBUG DataSourceTransactionManager:836 - Initiating transaction rollback 2021-07-27 21:48:51 DEBUG DataSourceTransactionManager:342 - Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] 2021-07-27 21:48:51 DEBUG DataSourceTransactionManager:385 - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] after transaction org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Tue Jul 27 21:48:50 CST 2021 at org.springframework.transaction.support.ResourceHolderSupport.checkTransactionTimeout(ResourceHolderSupport.java:155) at org.springframework.transaction.support.ResourceHolderSupport.getTimeToLiveInMillis(ResourceHolderSupport.java:144) at org.springframework.transaction.support.ResourceHolderSupport.getTimeToLiveInSeconds(ResourceHolderSupport.java:128) at org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout(SpringManagedTransaction.java:125) at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:85) at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49) at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198) at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:185) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426) at com.sun.proxy.$Proxy14.insert(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:271) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:58) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) at com.sun.proxy.$Proxy15.save(Unknown Source) at com.dashu.service.UserServiceImpl.register(UserServiceImpl.java:30) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy18.register(Unknown Source) at com.dashu.test.TestMybatisSpring.test2(TestMybatisSpring.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
5、异常属性
默认情况下抛出运行时异常的话,会回滚
public void register(User user) throws InterruptedException { // Thread.currentThread().sleep(3000); userDao.save(user); throw new RuntimeException("测试异常"); }
D:\DevelopPackage\jdk8\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\lib\idea_rt.jar=62070:D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\bin" -Dfile.encoding=UTF-8 -classpath "D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\lib\idea_rt.jar;D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\plugins\junit\lib\junit5-rt.jar;D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\plugins\junit\lib\junit-rt.jar;D:\DevelopPackage\jdk8\jre\lib\charsets.jar;D:\DevelopPackage\jdk8\jre\lib\deploy.jar;D:\DevelopPackage\jdk8\jre\lib\ext\access-bridge-64.jar;D:\DevelopPackage\jdk8\jre\lib\ext\cldrdata.jar;D:\DevelopPackage\jdk8\jre\lib\ext\dnsns.jar;D:\DevelopPackage\jdk8\jre\lib\ext\jaccess.jar;D:\DevelopPackage\jdk8\jre\lib\ext\jfxrt.jar;D:\DevelopPackage\jdk8\jre\lib\ext\localedata.jar;D:\DevelopPackage\jdk8\jre\lib\ext\nashorn.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunec.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunjce_provider.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunmscapi.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunpkcs11.jar;D:\DevelopPackage\jdk8\jre\lib\ext\zipfs.jar;D:\DevelopPackage\jdk8\jre\lib\javaws.jar;D:\DevelopPackage\jdk8\jre\lib\jce.jar;D:\DevelopPackage\jdk8\jre\lib\jfr.jar;D:\DevelopPackage\jdk8\jre\lib\jfxswt.jar;D:\DevelopPackage\jdk8\jre\lib\jsse.jar;D:\DevelopPackage\jdk8\jre\lib\management-agent.jar;D:\DevelopPackage\jdk8\jre\lib\plugin.jar;D:\DevelopPackage\jdk8\jre\lib\resources.jar;D:\DevelopPackage\jdk8\jre\lib\rt.jar;D:\giteesource\jdbc\spring-mybatis\target\classes;D:\DevelopPackage\repository\junit\junit\4.12\junit-4.12.jar;D:\DevelopPackage\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\DevelopPackage\repository\com\alibaba\druid\1.1.18\druid-1.1.18.jar;D:\DevelopPackage\repository\mysql\mysql-connector-java\5.1.48\mysql-connector-java-5.1.48.jar;D:\DevelopPackage\repository\org\mybatis\mybatis\3.4.6\mybatis-3.4.6.jar;D:\DevelopPackage\repository\org\springframework\spring-jdbc\5.1.14.RELEASE\spring-jdbc-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-beans\5.1.14.RELEASE\spring-beans-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-core\5.1.14.RELEASE\spring-core-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-jcl\5.1.14.RELEASE\spring-jcl-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-tx\5.1.14.RELEASE\spring-tx-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-context\5.1.4.RELEASE\spring-context-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-aop\5.1.4.RELEASE\spring-aop-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-expression\5.1.4.RELEASE\spring-expression-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\mybatis\mybatis-spring\2.0.2\mybatis-spring-2.0.2.jar;D:\DevelopPackage\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;D:\DevelopPackage\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\DevelopPackage\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.dashu.test.TestMybatisSpring,test2 2021-07-27 21:59:13 DEBUG ClassPathXmlApplicationContext:590 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@66d33a 2021-07-27 21:59:13 DEBUG XmlBeanDefinitionReader:396 - Loaded 10 bean definitions from class path resource [applicationContext.xml] 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'scanner' 2021-07-27 21:59:13 DEBUG LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2021-07-27 21:59:13 DEBUG ClassPathMapperScanner:437 - Identified candidate component class: file [D:\giteesource\jdbc\spring-mybatis\target\classes\com\dashu\dao\UserDao.class] 2021-07-27 21:59:13 DEBUG ClassPathMapperScanner:49 - Creating MapperFactoryBean with name 'userDao' and 'com.dashu.Dao.UserDao' mapperInterface 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory' 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator' 2021-07-27 21:59:13 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSource' 2021-07-27 21:59:14 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 2021-07-27 21:59:14 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' 2021-07-27 21:59:14 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'sqlSessionFactoryBean' 2021-07-27 21:59:14 DEBUG SqlSessionFactoryBean:49 - Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration 2021-07-27 21:59:14 DEBUG SqlSessionFactoryBean:49 - Parsed mapper file: 'file [D:\giteesource\jdbc\spring-mybatis\target\classes\com.dashu.mapper\UserDaoMapper.xml]' 2021-07-27 21:59:14 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userService' 2021-07-27 21:59:14 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userDao' 2021-07-27 21:59:14 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSourceTransactionManager' 2021-07-27 21:59:14 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0' 2021-07-27 21:59:14 DEBUG DataSourceTransactionManager:372 - Creating new transaction with name [com.dashu.service.UserServiceImpl.register]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 2021-07-27 21:59:14 INFO DruidDataSource:1003 - {dataSource-1} inited 2021-07-27 21:59:15 DEBUG DataSourceTransactionManager:265 - Acquired Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] for JDBC transaction 2021-07-27 21:59:15 DEBUG DataSourceTransactionManager:282 - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] to manual commit 2021-07-27 21:59:15 DEBUG SqlSessionUtils:49 - Creating a new SqlSession 2021-07-27 21:59:15 DEBUG SqlSessionUtils:49 - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35841320] 2021-07-27 21:59:15 DEBUG SpringManagedTransaction:49 - JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] will be managed by Spring 2021-07-27 21:59:15 DEBUG save:159 - ==> Preparing: Insert into tree (name,age) values (?,?) 2021-07-27 21:59:15 DEBUG save:159 - ==> Parameters: xi(String), 21(Integer) 2021-07-27 21:59:15 DEBUG save:159 - <== Updates: 1 2021-07-27 21:59:15 DEBUG SqlSessionUtils:49 - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35841320] 2021-07-27 21:59:15 DEBUG SqlSessionUtils:49 - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35841320] 2021-07-27 21:59:15 DEBUG SqlSessionUtils:49 - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@35841320] 2021-07-27 21:59:15 DEBUG DataSourceTransactionManager:836 - Initiating transaction rollback 2021-07-27 21:59:15 DEBUG DataSourceTransactionManager:342 - Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] 2021-07-27 21:59:15 DEBUG DataSourceTransactionManager:385 - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1a75e76a] after transaction java.lang.RuntimeException: 测试异常 at com.dashu.service.UserServiceImpl.register(UserServiceImpl.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy18.register(Unknown Source) at com.dashu.test.TestMybatisSpring.test2(TestMybatisSpring.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53) Process finished with exit code -1
但是如果抛出的检查异常Exception会怎么样呢?日志并没有回滚而是进行提交了,并且数据已经提交了
D:\DevelopPackage\jdk8\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\lib\idea_rt.jar=49671:D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\bin" -Dfile.encoding=UTF-8 -classpath "D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\lib\idea_rt.jar;D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\plugins\junit\lib\junit5-rt.jar;D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\plugins\junit\lib\junit-rt.jar;D:\DevelopPackage\jdk8\jre\lib\charsets.jar;D:\DevelopPackage\jdk8\jre\lib\deploy.jar;D:\DevelopPackage\jdk8\jre\lib\ext\access-bridge-64.jar;D:\DevelopPackage\jdk8\jre\lib\ext\cldrdata.jar;D:\DevelopPackage\jdk8\jre\lib\ext\dnsns.jar;D:\DevelopPackage\jdk8\jre\lib\ext\jaccess.jar;D:\DevelopPackage\jdk8\jre\lib\ext\jfxrt.jar;D:\DevelopPackage\jdk8\jre\lib\ext\localedata.jar;D:\DevelopPackage\jdk8\jre\lib\ext\nashorn.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunec.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunjce_provider.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunmscapi.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunpkcs11.jar;D:\DevelopPackage\jdk8\jre\lib\ext\zipfs.jar;D:\DevelopPackage\jdk8\jre\lib\javaws.jar;D:\DevelopPackage\jdk8\jre\lib\jce.jar;D:\DevelopPackage\jdk8\jre\lib\jfr.jar;D:\DevelopPackage\jdk8\jre\lib\jfxswt.jar;D:\DevelopPackage\jdk8\jre\lib\jsse.jar;D:\DevelopPackage\jdk8\jre\lib\management-agent.jar;D:\DevelopPackage\jdk8\jre\lib\plugin.jar;D:\DevelopPackage\jdk8\jre\lib\resources.jar;D:\DevelopPackage\jdk8\jre\lib\rt.jar;D:\giteesource\jdbc\spring-mybatis\target\classes;D:\DevelopPackage\repository\junit\junit\4.12\junit-4.12.jar;D:\DevelopPackage\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\DevelopPackage\repository\com\alibaba\druid\1.1.18\druid-1.1.18.jar;D:\DevelopPackage\repository\mysql\mysql-connector-java\5.1.48\mysql-connector-java-5.1.48.jar;D:\DevelopPackage\repository\org\mybatis\mybatis\3.4.6\mybatis-3.4.6.jar;D:\DevelopPackage\repository\org\springframework\spring-jdbc\5.1.14.RELEASE\spring-jdbc-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-beans\5.1.14.RELEASE\spring-beans-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-core\5.1.14.RELEASE\spring-core-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-jcl\5.1.14.RELEASE\spring-jcl-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-tx\5.1.14.RELEASE\spring-tx-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-context\5.1.4.RELEASE\spring-context-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-aop\5.1.4.RELEASE\spring-aop-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-expression\5.1.4.RELEASE\spring-expression-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\mybatis\mybatis-spring\2.0.2\mybatis-spring-2.0.2.jar;D:\DevelopPackage\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;D:\DevelopPackage\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\DevelopPackage\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.dashu.test.TestMybatisSpring,test2 2021-07-27 22:00:42 DEBUG ClassPathXmlApplicationContext:590 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4cdbe50f 2021-07-27 22:00:43 DEBUG XmlBeanDefinitionReader:396 - Loaded 10 bean definitions from class path resource [applicationContext.xml] 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'scanner' 2021-07-27 22:00:43 DEBUG LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2021-07-27 22:00:43 DEBUG ClassPathMapperScanner:437 - Identified candidate component class: file [D:\giteesource\jdbc\spring-mybatis\target\classes\com\dashu\dao\UserDao.class] 2021-07-27 22:00:43 DEBUG ClassPathMapperScanner:49 - Creating MapperFactoryBean with name 'userDao' and 'com.dashu.Dao.UserDao' mapperInterface 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSource' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'sqlSessionFactoryBean' 2021-07-27 22:00:43 DEBUG SqlSessionFactoryBean:49 - Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration 2021-07-27 22:00:43 DEBUG SqlSessionFactoryBean:49 - Parsed mapper file: 'file [D:\giteesource\jdbc\spring-mybatis\target\classes\com.dashu.mapper\UserDaoMapper.xml]' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userService' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userDao' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSourceTransactionManager' 2021-07-27 22:00:43 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0' 2021-07-27 22:00:44 DEBUG DataSourceTransactionManager:372 - Creating new transaction with name [com.dashu.service.UserServiceImpl.register]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 2021-07-27 22:00:44 INFO DruidDataSource:1003 - {dataSource-1} inited 2021-07-27 22:00:44 DEBUG DataSourceTransactionManager:265 - Acquired Connection [com.mysql.jdbc.JDBC4Connection@33bc72d1] for JDBC transaction 2021-07-27 22:00:44 DEBUG DataSourceTransactionManager:282 - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@33bc72d1] to manual commit 2021-07-27 22:00:44 DEBUG SqlSessionUtils:49 - Creating a new SqlSession 2021-07-27 22:00:44 DEBUG SqlSessionUtils:49 - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7ae0a9ec] 2021-07-27 22:00:44 DEBUG SpringManagedTransaction:49 - JDBC Connection [com.mysql.jdbc.JDBC4Connection@33bc72d1] will be managed by Spring 2021-07-27 22:00:44 DEBUG save:159 - ==> Preparing: Insert into tree (name,age) values (?,?) 2021-07-27 22:00:44 DEBUG save:159 - ==> Parameters: xi(String), 21(Integer) 2021-07-27 22:00:44 DEBUG save:159 - <== Updates: 1 2021-07-27 22:00:44 DEBUG SqlSessionUtils:49 - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7ae0a9ec] 2021-07-27 22:00:44 DEBUG SqlSessionUtils:49 - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7ae0a9ec] 2021-07-27 22:00:44 DEBUG SqlSessionUtils:49 - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7ae0a9ec] 2021-07-27 22:00:44 DEBUG SqlSessionUtils:49 - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7ae0a9ec] 2021-07-27 22:00:44 DEBUG DataSourceTransactionManager:743 - Initiating transaction commit 2021-07-27 22:00:44 DEBUG DataSourceTransactionManager:327 - Committing JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@33bc72d1] 2021-07-27 22:00:44 DEBUG DataSourceTransactionManager:385 - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@33bc72d1] after transaction java.lang.Exception: 测试异常 at com.dashu.service.UserServiceImpl.register(UserServiceImpl.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy18.register(Unknown Source) at com.dashu.test.TestMybatisSpring.test2(TestMybatisSpring.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53) Process finished with exit code -1
@Test public void test2() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); UserService userService = (UserService) ctx.getBean("userService"); User user = new User(); user.setName("xixi"); user.setAge(21); userService.register(user); }
**总结
Spring事务处理过程中
默认 与运行时异常及其子类,采用的是回滚的策略,如果是检查异常Exception及其子类的话默认采用的事提交策略。
我们是可以改变这个策略的,需要通过异常属性来进行修改,对应的事rollbackFor = {} noRollbackFor这两个属性,一个是回滚,一个是不会滚,他们的值都是数组。实战中都采用默认
@Transactional(rollbackFor = {java.lang.Exception.class}) public void register(User user) throws Exception { // Thread.currentThread().sleep(3000); userDao.save(user); throw new Exception("测试异常"); }
@Test public void test2() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); UserService userService = (UserService) ctx.getBean("userService"); User user = new User(); user.setName("xixixi"); user.setAge(21); userService.register(user); }
D:\DevelopPackage\jdk8\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\lib\idea_rt.jar=51583:D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\bin" -Dfile.encoding=UTF-8 -classpath "D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\lib\idea_rt.jar;D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\plugins\junit\lib\junit5-rt.jar;D:\DevelopPackage\idea\IntelliJ IDEA 2020.2.2\plugins\junit\lib\junit-rt.jar;D:\DevelopPackage\jdk8\jre\lib\charsets.jar;D:\DevelopPackage\jdk8\jre\lib\deploy.jar;D:\DevelopPackage\jdk8\jre\lib\ext\access-bridge-64.jar;D:\DevelopPackage\jdk8\jre\lib\ext\cldrdata.jar;D:\DevelopPackage\jdk8\jre\lib\ext\dnsns.jar;D:\DevelopPackage\jdk8\jre\lib\ext\jaccess.jar;D:\DevelopPackage\jdk8\jre\lib\ext\jfxrt.jar;D:\DevelopPackage\jdk8\jre\lib\ext\localedata.jar;D:\DevelopPackage\jdk8\jre\lib\ext\nashorn.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunec.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunjce_provider.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunmscapi.jar;D:\DevelopPackage\jdk8\jre\lib\ext\sunpkcs11.jar;D:\DevelopPackage\jdk8\jre\lib\ext\zipfs.jar;D:\DevelopPackage\jdk8\jre\lib\javaws.jar;D:\DevelopPackage\jdk8\jre\lib\jce.jar;D:\DevelopPackage\jdk8\jre\lib\jfr.jar;D:\DevelopPackage\jdk8\jre\lib\jfxswt.jar;D:\DevelopPackage\jdk8\jre\lib\jsse.jar;D:\DevelopPackage\jdk8\jre\lib\management-agent.jar;D:\DevelopPackage\jdk8\jre\lib\plugin.jar;D:\DevelopPackage\jdk8\jre\lib\resources.jar;D:\DevelopPackage\jdk8\jre\lib\rt.jar;D:\giteesource\jdbc\spring-mybatis\target\classes;D:\DevelopPackage\repository\junit\junit\4.12\junit-4.12.jar;D:\DevelopPackage\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\DevelopPackage\repository\com\alibaba\druid\1.1.18\druid-1.1.18.jar;D:\DevelopPackage\repository\mysql\mysql-connector-java\5.1.48\mysql-connector-java-5.1.48.jar;D:\DevelopPackage\repository\org\mybatis\mybatis\3.4.6\mybatis-3.4.6.jar;D:\DevelopPackage\repository\org\springframework\spring-jdbc\5.1.14.RELEASE\spring-jdbc-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-beans\5.1.14.RELEASE\spring-beans-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-core\5.1.14.RELEASE\spring-core-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-jcl\5.1.14.RELEASE\spring-jcl-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-tx\5.1.14.RELEASE\spring-tx-5.1.14.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-context\5.1.4.RELEASE\spring-context-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-aop\5.1.4.RELEASE\spring-aop-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\springframework\spring-expression\5.1.4.RELEASE\spring-expression-5.1.4.RELEASE.jar;D:\DevelopPackage\repository\org\mybatis\mybatis-spring\2.0.2\mybatis-spring-2.0.2.jar;D:\DevelopPackage\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;D:\DevelopPackage\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\DevelopPackage\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.dashu.test.TestMybatisSpring,test2 2021-07-27 22:10:44 DEBUG ClassPathXmlApplicationContext:590 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@66d33a 2021-07-27 22:10:45 DEBUG XmlBeanDefinitionReader:396 - Loaded 10 bean definitions from class path resource [applicationContext.xml] 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'scanner' 2021-07-27 22:10:45 DEBUG LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2021-07-27 22:10:45 DEBUG ClassPathMapperScanner:437 - Identified candidate component class: file [D:\giteesource\jdbc\spring-mybatis\target\classes\com\dashu\dao\UserDao.class] 2021-07-27 22:10:45 DEBUG ClassPathMapperScanner:49 - Creating MapperFactoryBean with name 'userDao' and 'com.dashu.Dao.UserDao' mapperInterface 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSource' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'sqlSessionFactoryBean' 2021-07-27 22:10:45 DEBUG SqlSessionFactoryBean:49 - Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration 2021-07-27 22:10:45 DEBUG SqlSessionFactoryBean:49 - Parsed mapper file: 'file [D:\giteesource\jdbc\spring-mybatis\target\classes\com.dashu.mapper\UserDaoMapper.xml]' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userService' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'userDao' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'dataSourceTransactionManager' 2021-07-27 22:10:45 DEBUG DefaultListableBeanFactory:213 - Creating shared instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0' 2021-07-27 22:10:46 DEBUG DataSourceTransactionManager:372 - Creating new transaction with name [com.dashu.service.UserServiceImpl.register]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Exception 2021-07-27 22:10:46 INFO DruidDataSource:1003 - {dataSource-1} inited 2021-07-27 22:10:46 DEBUG DataSourceTransactionManager:265 - Acquired Connection [com.mysql.jdbc.JDBC4Connection@353352b6] for JDBC transaction 2021-07-27 22:10:46 DEBUG DataSourceTransactionManager:282 - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@353352b6] to manual commit 2021-07-27 22:10:46 DEBUG SqlSessionUtils:49 - Creating a new SqlSession 2021-07-27 22:10:46 DEBUG SqlSessionUtils:49 - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@548a24a] 2021-07-27 22:10:46 DEBUG SpringManagedTransaction:49 - JDBC Connection [com.mysql.jdbc.JDBC4Connection@353352b6] will be managed by Spring 2021-07-27 22:10:46 DEBUG save:159 - ==> Preparing: Insert into tree (name,age) values (?,?) 2021-07-27 22:10:46 DEBUG save:159 - ==> Parameters: xixixi(String), 21(Integer) 2021-07-27 22:10:46 DEBUG save:159 - <== Updates: 1 2021-07-27 22:10:46 DEBUG SqlSessionUtils:49 - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@548a24a] 2021-07-27 22:10:46 DEBUG SqlSessionUtils:49 - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@548a24a] 2021-07-27 22:10:46 DEBUG SqlSessionUtils:49 - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@548a24a] 2021-07-27 22:10:46 DEBUG DataSourceTransactionManager:836 - Initiating transaction rollback 2021-07-27 22:10:46 DEBUG DataSourceTransactionManager:342 - Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@353352b6] 2021-07-27 22:10:46 DEBUG DataSourceTransactionManager:385 - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@353352b6] after transaction java.lang.Exception: 测试异常 at com.dashu.service.UserServiceImpl.register(UserServiceImpl.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy18.register(Unknown Source) at com.dashu.test.TestMybatisSpring.test2(TestMybatisSpring.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53) Process finished with exit code -1
@Transactional(rollbackFor = {java.lang.Exception.class},noRollbackFor = {java.lang.RuntimeException.class})
事务属性常见配置总结
1、隔离属性 默认值
2、传播属性 Rqueired(默认值) 增删改 Supports查询操作
3、只读属性 readOnly false 增删改 true查询
4、超时属性 默认值-1
5、异常属性 默认值
结论:
增删改操作:@Transactional
查询操作: @Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
基于标签的事务配置方式(事务开发的第二种形式)
基于注解的开发形式
<bean id="userService" class = "com.dashu.service.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> <!--DataSourceTransactionManager--> <bean id="dataSourceTransactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> @Transactional(rollbackFor = {java.lang.Exception.class},noRollbackFor = {java.lang.RuntimeException.class}) public void register(User user) throws Exception { // Thread.currentThread().sleep(3000); userDao.save(user); throw new Exception("测试异常"); } <tx:annotation-driven transaction-manager="dataSourceTransactionManager" proxy-target-class="false"/>
基于标签的开发形式
<bean id="userService" class = "com.dashu.service.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> <!--DataSourceTransactionManager--> <bean id="dataSourceTransactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> 事务属性+定义切入点 <tx:advice id="txAdvice" transacation-manager="dataSourceTransactionManager"> <tx:attributes> <tr:method name="register" isolation="" ,propagation=""></tx:method> <tr:method name="login" isolation="" ,propagation=""></tx:method> </tx:attributes> </tx:advice> 柱状切面 <aop:config> <aop:pointcut id = "pc" expression = "*****************"></aop:pointcut> <aop:advisor advice-ref="" pointcut-ref=""></aop:advisor> </aop:config>
基于标签的开发实战中的应用方式
<bean id="userService" class = "com.dashu.service.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> <!--DataSourceTransactionManager--> <bean id="dataSourceTransactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> 定义切入点 <tx:advice id="txAdvice" transacation-manager="dataSourceTransactionManager"> <tx:attributes> //日后这个开头的方法都这么干,使用了*通配符 <tr:method name="modify*" isolation="" ,propagation=""></tx:method> 除了以上,剩下 ... 除了以上,剩下 ... //除了以上命名之外的所有方法 <tr:method name="*" isolation="" ,propagation=""></tx:method> </tx:attributes> </tx:advice> 简化之后的切面 <aop:config> <aop:pointcut id = "pc" expression = "优化为包切入点"></aop:pointcut> <aop:advisor advice-ref="" pointcut-ref=""></aop:advisor> </aop:config>