spring 声明式事务管理
事务是我们在用 jdbc 操作数据库时,不可避免的问题。由于事务的执行。由于事务具有ACID 四大特性,执行起来还要受到事务的隔离级别,传播行为,锁机制等影响, 所以通过原生 jdbc 来控制事务面临着不少问题,同时通过原生 jdbc 控制事务也会带来大量代码冗余,如 conection.commit() 事务提交,conection.rollback() 事务回滚。spring 基于面向切面的编程思想,通过动态代理,方法增强,我们可以很轻松的通过配置和注解完成事务的管理。
spring声明式事务
Spring 声明式事务指的是,spring 为我们提供一套进行事务管理的API类。我们不需要进行过多的编码,只需要进行简单的xml或注解配置,就可以让spring 结题我们的事务管理的编码工作。我们做的事情就是配置,如何配置。
基于xml完成事务管理
基于 xml 配置声明式事务,主要还是集中在 spring 的配置文件。通过 IOC 和 AOP 共同完成声明式事务管理。
首先我们正常的在spring中配置好我们的持久层和服务层
> 我们在进行事务管理一般都集中在 服务层,所以我们要先在 IOC 中配置好我们三成架构中原有的Bean 组件
<!-- 配置 service --> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 配置 dao --> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <!-- 注入 dataSource --> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"> </property> <property name="url" value="jdbc:mysql:///spring_day04"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property> </bean>
在spring 中配置我们的事务管理器
< bean id="transactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 引用上面的事务管理 配置事务通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--在 tx:advice 标签内部 配置事务的属性 --> <!-- name:指定方法名称,是业务核心方法,通过正则表达去对匹配到的服务层方法进行事务管理 read-only:是否是只读事务。默认 false,不只读。 isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。 propagation:指定事务的传播行为。 timeout:指定超时时间。默认值为:-1。永不超时。 rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。 没有默认值,任何异常都回滚。 no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回 滚。没有默认值,任何异常都回滚。 --> <tx:attributes> <tx:method name="*" read-only="false" propagation="REQUIRED"/> <tx:method name="find*" read-only="true" propagation="SUPPORTS"/> </tx:attributes> </tx:advice>
> 注意,我们通过配置了事务管理器及其属性,我们不再需要去过多的关注事务什么时候提交,事务在什么时候回滚。因为这些我们已经交由 spring 声明式事务去管理,这已经不是我们关注的中心,我们应该把重点转移到,需要通过 name的正则去匹配哪些方法进行事务管理,这个方法的事务需要我们去设计哪些属性,是否自读,事务隔离,事务传播,遇到什么时候进行事务回滚,事务超时时间。
配置AOP 实现spring 声明式事务管理
<!--开启aop 配置 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut expression="execution(* com.stack.service.impl.*.*(..))" id="pt1"/> <!-- 引用事务通知类,完成事务管理,配置要对那些方法进行织入,组成切面 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/> </aop:config>
> 注意这里进行 aop 配置我们引用的是 aop:advisor 标签。这和我们配置切面的 aop:aspect 标签不一致,原因就在于我们自定义切面需要配置通知的位置,但是spring 事务管理,已经在内部帮我们配置好了,我们只需要引入事务通知即可。
基于注解完成事务管理
xml 开启注解支持(这里以 mybatis 为例)
<!-- 数据库相关的 IOC bean 在这里可以配置多数据源-->
<!-- 1. 数据源 : DriverManagerDataSource mybatis 在获取数据库连接需要 dataSource ,-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://182.92.221.190:3306/bookdb" />
<property name="username" value="ldy" />
<property name="password" value="135135ldy" />
</bean>
<!--
2. mybatis的SqlSession的工厂: SqlSessionFactoryBean dataSource:引用数据源
MyBatis定义数据源,同意加载配置
通过 注入不同的数据源,实现多数据源的 sqlSessionFactory
-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--
3. mybatis自动扫描加载Sql映射文件/接口 : MapperScannerConfigurer sqlSessionFactory
basePackage:指定sql映射文件/接口所在的包(自动扫描) sqlsession Builder
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.hyg.im.mapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!--
4. 事务管理 : DataSourceTransactionManager dataSource:引用上面定义的数据源
配置事务管理器
-->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 5. 使用声明式事务
transaction-manager:引用上面定义的事务管理器
开启事务的注解配置
-->
<tx:annotation-driven transaction-manager="txManager" />
关键注解
@Transactional : 这个注解是spring 提供的事务管理的注解,这个注解可以出现在服务层类或者方法上。出现在类上,表明这个服务类都被spring 声明式事务管理。出现在方法上,表明对这个方法进行细粒度的事务配置。
/**
* 在类上配置事务,在方法级别上详细配置事务,并可以指定事务的一些属性(只读,隔离性,传播行为:事务里面套着另一个事务,回滚机制)
*/
@Transactional(readOnly = true,isolation = Isolation.REPEATABLE_READ,rollbackFor = Throwable.class)
纯注解配置
纯注解配置分为自己写配置类或者采用 spring Boot 方式
Spring Boot 方式
/**
spring Boot 开启事务配置,只需要简单的配置一个注解 @EnableTransactionManagement 就能开启事务自动配置,具体事务管理就采用上面的@Transactional 主机就可以。
*/
@SpringBootApplication
@EnableTransactionManagement // 开启事务注解支持,相当于 <tx:annotation-driven transaction-manager="txManager" />
@MapperScan("com.stack.knowyouclient.dao") //配置 mybatis持久层扫描的包目录
public class KnowyouClientApplication {
public static void main(String[] args) {
SpringApplication.run(KnowyouClientApplication.class, args);
}
}
spring 方式
/**
* 配置事务管理器
* @date 2019/11/7 15:41
*/
public class TransactionManager {
@Bean(name = "transactionManager")
public PlatformTransactionManager createTransactionManager(DataSource source){
return new DataSourceTransactionManager(source);
}
}
package config;
import org.springframework.context.annotation.*;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* spring的配置类 相当于bean.xml
* @date 2019/11/7 15:08
*/
@Configuration
@ComponentScan("com") //扫描包
@Import({JdbcConfig.class,TransactionManager.class})
@PropertySource("jdbcConfig.properties") //配置数据源
@EnableTransactionManagement //开启事务注解支持 <tx:annotation-driven transaction-manager="txManager" />
public class SpringConfig {
}
补充说明,在 ssm 项目时,需要在应用的web.xml加载的 spring 的配置文件中,需要配置注解要扫描的包。
<!-- 加载Spring容器配置 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 设置 Spring 容器加载所有的配置文件的路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-*.xml</param-value>
</context-param>
<!-- 配置SpringMVC核心控制器 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始配置化文件,前面contextConfigLocation看情况二选一 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-mvc.xml</param-value>
</init-param>
<!-- 启动加载一次 -->
<load-on-startup>1</load-on-startup>
</servlet>
在spring MVC 配置文件中配置
<!-- IOC AOP注解持久层,服务层,控制层 扫描包目录(也可已在spring 配置文件中配置) -->
<context:component-scan base-package="com.stack.im" />
<!-- 开启 MVC 注解支持 @RequestMapping, @ ResponseBody -->
<mvc:annotation-driven />