课程学习--SSM--第5讲--声明式事务

思路

在这里插入图片描述

目标

webui/res/spring-persist-tx.xml

  1. 配置自动扫描的包
  2. 配置事务管理器
    - 装配数据源
  3. 配置事务切面
    - 让切入点表达式定位到ServiceImpl
    - 将切入点表达式和事务通知关联起来
  4. 配置事务通知
  • 配置事务属性
    - 查询方法
    - 增删改方法

接口component/api/AdminService.java

实现类component/impl/AdminServiceImpl.java

实现

webui/res/spring-persist-tx.xml

<?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:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

	<!-- 配置自动扫描的包:主要是为了把Service扫描到IOC容器中 -->
	<context:component-scan base-package="com.atguigu.crowd.service"/>
	
	<!-- 配置事务管理器 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 装配数据源 -->
		<property name="dataSource" ref="dataSource"/>
		
	</bean>
	
	<!-- 配置事务切面 -->
	<aop:config>
		<!-- 考虑到后面我们整合SpringSecurity,避免把UserDetailsService加入事务控制,让切入点表达式定位到ServiceImpl -->
		<aop:pointcut expression="execution(* *..*ServiceImpl.*(..))" id="txPointcut"/>
		
		<!-- 将切入点表达式和事务通知关联起来 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
	</aop:config>
	
	<!-- 配置事务通知 -->
	<tx:advice id="txAdvice" transaction-manager="txManager">
	
		<!-- 配置事务属性 -->
		<tx:attributes>
			
			<!-- 查询方法:配置只读属性,让数据库知道这是一个查询操作,能够进行一定优化 -->
			<tx:method name="get*" read-only="true"/>
			<tx:method name="find*" read-only="true"/>
			<tx:method name="query*" read-only="true"/>
			<tx:method name="count*" read-only="true"/>
			
			<!-- 增删改方法:配置事务传播行为、回滚异常 -->
			<!-- 
				propagation属性:
					REQUIRED:默认值,表示当前方法必须工作在事务中,如果当前线程上没有已经开启的事务,则自己开新事务。如果已经有了,那么就使用这个已有的事务。
						顾虑:用别人的事务有可能“被”回滚。
					REQUIRES_NEW:建议使用的值,表示不管当前线程上有没有事务,都要自己开事务,在自己的事务中运行。
						好处:不会受到其他事务回滚的影响。
			 -->
			<!-- 
				rollback-for属性:配置事务方法针对什么样的异常回滚
					默认:运行时异常回滚
					建议:编译时异常和运行时异常都回滚
			 -->
			<tx:method name="save*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
			<tx:method name="update*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
			<tx:method name="remove*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
			<tx:method name="batch*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
			
		</tx:attributes>
	
	</tx:advice>

</beans>

接口component/api/AdminService.java

package com.atguigu.crowd.service.api;

import com.atguigu.crowd.entity.Admin;

public interface AdminService {
	
	void saveAdmin(Admin admin);

}

实现类component/impl/AdminServiceImpl.java

package com.atguigu.crowd.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.atguigu.crowd.entity.Admin;
import com.atguigu.crowd.mapper.AdminMapper;
import com.atguigu.crowd.service.api.AdminService;

@Service
public class AdminServiceImpl implements AdminService {

	@Autowired
	private AdminMapper adminMapper; 
	
	public void saveAdmin(Admin admin) {
		// TODO Auto-generated method stub
		adminMapper.insert(admin);
		
		// 测试事务回滚
//		throw new RuntimeException();
	}

}

注意

配置事务管理器中通配符

在这里插入图片描述在这里插入图片描述

测试

/atcrowdfunding02-admin-webui/src/test/java/com/atguigu/crowd/test/CrowdTest.java

package com.atguigu.crowd.test;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.atguigu.crowd.entity.Admin;
import com.atguigu.crowd.mapper.AdminMapper;
import com.atguigu.crowd.service.api.AdminService;

//在类上标记必要的注解,Spring整合Junit
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-persist-mybatis.xml","classpath:spring-persist-tx.xml"})

public class CrowdTest {
	
	@Autowired
	private DataSource dataSource;
	
	@Autowired
	private AdminMapper adminMapper;
	
	@Autowired
	private AdminService adminService;
	
	@Test
	public void testTx() {
		Admin admin = new Admin(null, "jerry", "123456", "杰瑞", "jerry@qq.com", null);
		adminService.saveAdmin(admin);
		
	}
	
}

控制台输出:

控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txAdvice'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'adminMapper'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@20f5281c]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'sqlSessionFactoryBean'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate - Storing ApplicationContext in cache under key [[MergedContextConfiguration@4d3167f4 testClass = CrowdTest, locations = '{classpath:spring-persist-mybatis.xml, classpath:spring-persist-tx.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@1115ec15 size = 1, maxSize = 32, parentContextCount = 0, hitCount = 0, missCount = 1]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'com.atguigu.crowd.test.CrowdTest': AutowiredFieldElement for private javax.sql.DataSource com.atguigu.crowd.test.CrowdTest.dataSource
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'dataSource'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'com.atguigu.crowd.test.CrowdTest' to bean named 'dataSource'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'com.atguigu.crowd.test.CrowdTest': AutowiredFieldElement for private com.atguigu.crowd.mapper.AdminMapper com.atguigu.crowd.test.CrowdTest.adminMapper
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'adminMapper'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'com.atguigu.crowd.test.CrowdTest' to bean named 'adminMapper'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'com.atguigu.crowd.test.CrowdTest': AutowiredFieldElement for private com.atguigu.crowd.service.api.AdminService com.atguigu.crowd.test.CrowdTest.adminService
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'adminServiceImpl'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'com.atguigu.crowd.test.CrowdTest' to bean named 'adminServiceImpl'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test method: context [DefaultTestContext@76a3e297 testClass = CrowdTest, testInstance = com.atguigu.crowd.test.CrowdTest@e720b71, testMethod = testTx@CrowdTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@4d3167f4 testClass = CrowdTest, locations = '{classpath:spring-persist-mybatis.xml, classpath:spring-persist-tx.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class annotated with @DirtiesContext [false] with mode [null], method annotated with @DirtiesContext [false] with mode [null].
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name [com.atguigu.crowd.service.impl.AdminServiceImpl.saveAdmin]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,-java.lang.Exception
控制台- 2020-08-19 14:19:23 [main] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [com.mysql.jdbc.JDBC4Connection@524f3b3a] for JDBC transaction
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@524f3b3a] to manual commit
控制台- 2020-08-19 14:19:23 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
控制台- 2020-08-19 14:19:23 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@19e4fcac]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@524f3b3a] will be managed by Spring
控制台- 2020-08-19 14:19:23 [main] DEBUG com.atguigu.crowd.mapper.AdminMapper.insert - ==>  Preparing: insert into t_admin (id, login_acct, user_pswd, user_name, email, create_time ) values (?, ?, ?, ?, ?, ? ) 
控制台- 2020-08-19 14:19:23 [main] DEBUG com.atguigu.crowd.mapper.AdminMapper.insert - ==> Parameters: null, jerry(String), 123456(String), 杰瑞(String), jerry@qq.com(String), null
控制台- 2020-08-19 14:19:23 [main] DEBUG com.atguigu.crowd.mapper.AdminMapper.insert - <==    Updates: 1
控制台- 2020-08-19 14:19:23 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@19e4fcac]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@19e4fcac]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@19e4fcac]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@19e4fcac]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Initiating transaction commit
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Committing JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@524f3b3a]
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@524f3b3a] after transaction
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@76a3e297 testClass = CrowdTest, testInstance = com.atguigu.crowd.test.CrowdTest@e720b71, testMethod = testTx@CrowdTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@4d3167f4 testClass = CrowdTest, locations = '{classpath:spring-persist-mybatis.xml, classpath:spring-persist-tx.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class annotated with @DirtiesContext [false] with mode [null], method annotated with @DirtiesContext [false] with mode [null].
控制台- 2020-08-19 14:19:23 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@76a3e297 testClass = CrowdTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@4d3167f4 testClass = CrowdTest, locations = '{classpath:spring-persist-mybatis.xml, classpath:spring-persist-tx.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class annotated with @DirtiesContext [false] with mode [null].
控制台- 2020-08-19 14:19:23 [Thread-1] INFO  org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@64485a47: startup date [Wed Aug 19 14:19:22 CST 2020]; root of context hierarchy
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'sqlSessionFactoryBean'
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@29626d54: defining beans [org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,dataSource,sqlSessionFactoryBean,mapperScannerConfigurer,adminServiceImpl,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,txManager,org.springframework.aop.config.internalAutoProxyCreator,txPointcut,org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0,txAdvice,adminMapper]; root of factory hierarchy
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'sqlSessionFactoryBean': [adminMapper]
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'adminMapper': [adminServiceImpl, com.atguigu.crowd.test.CrowdTest]
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'adminServiceImpl': [com.atguigu.crowd.test.CrowdTest]
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'dataSource': [txManager]
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'txManager': [txAdvice]
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean '(inner bean)#1a72a540': [txAdvice]
控制台- 2020-08-19 14:19:23 [Thread-1] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter - Invoking destroy method 'close' on bean with name 'dataSource'
控制台- 2020-08-19 14:19:23 [Thread-1] INFO  com.alibaba.druid.pool.DruidDataSource - {dataSource-1} closed

小结

加油

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

charliejohn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值