目录
Spring框架事务管理
Spring声明式事务
声明式事务是Spring框架提供的一种通过配置而非编程代码来管理事务的方式。
相关的类和API
-
PlatformTransactionManager接口:平台事务管理器- 该接口根据不同的持久层框架,选择不同的具体实现类:
- 接口方法:
void commit(TransactionStatus status)void rollback(TransactionStatus status)- 使用Spring框架的JDBC模板或者MyBatis框架,选择
DataSourceTransactionManager实现类 - 使用Hibernate框架,选择
HibernateTransactionManager实现类
-
TransactionDefinition接口,事务定义信息接口- 定义了事务隔离级别
- 定义了事务传播行为
Spring框架声明式事务管理
声明式事务管理
有三种形式:
- 配置文件形式
- 半注解形式(配置文件 + 注解)
- 全注解形式(注解)
配置文件形式
Bean管理的元素属性
<tx:advice>:事务通知配置id:事务通知标识符,用于其它地方引用transaction-manager:指定事务管理器Bean的id叫什么<tx:attributes>:定义方法级别的事务属性<tx:method>:为匹配的方法指定详细的事务行为规则name:匹配XX的方法isolation:隔离级别read-only:
<aop:config>:AOP通知配置<aop:advisor>:系统通知advice-ref:引用上面的事务pointcut:定义切入点表达式
<aop:advisor>与<aop:aspect> 的区别:
| 特性 | <aop:advisor> | <aop:aspect> |
|---|---|---|
| 用途 | 系统级通知 | 自定义业务通知 |
| 通知类型 | 通常使用Around通知 | 支持5种通知 |
| 配置方式 | 引用外部定义的Advice | 在aspect内部定义通知方法 |
| 灵活性 | 相对固定 | 更灵活,可自定义逻辑 |
实操案例
- 创建maven Java项目
- 引入依赖
<!-- Maven中配置Java版本 --> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <!--有单元测试的环境,Spring5版本,Junit4.12版本--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- 连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!-- mysql驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <!-- Spring整合Junit测试的jar包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> <scope>test</scope> </dependency> <!-- AOP联盟 --> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <!-- Spring Aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!-- aspectj --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies> - 创建实体类:Account类
- 添加id、name、money这三个成员变量(字段)
- 获取它们的getter/setter方法
- 创建持久层的接口类和实现类:AccountDao类和AccountDaoImpl类
package com.qcby.dao; public interface AccountDao { /** * 转账 * @param name 转账人 * @param money 金额 */ public void outMoney(String name, Double money); /** * 收账 * @param name 收账人 * @param money 金额 */ public void inMoney(String name, Double money); }package com.qcby.dao.impl; import com.qcby.dao.AccountDao; import org.springframework.jdbc.core.JdbcTemplate; public class AccountDaoImpl implements AccountDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public void outMoney(String name, Double money) { //编写sql语句 String sql = "update account set money = money - ? where name = ?"; jdbcTemplate.update(sql, money, name); } @Override public void inMoney(String name, Double money) { String sql = "update account set money = money + ? where name = ?"; jdbcTemplate.update(sql, money, name); } } - 创建业务层的接口来和实现类:AccountService类和AccountServiceImpl类
package com.qcby.service; public interface AccountService { /** * * @param out 转账 * @param in 收账 * @param money 金额 */ public void pay(String out, String in, Double money); }package com.qcby.service.impl; import com.qcby.dao.AccountDao; import com.qcby.service.AccountService; public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } /** * * @param out 转账 * @param in 收账 * @param money 金额 */ @Override public void pay(String out, String in, Double money) { accountDao.outMoney(out,money); accountDao.inMoney(in,money); } } - 编写属性文件:jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///spring_db jdbc.username=username // 你的用户名 jdbc.password=userpassword // 你的密码 - 编写配置文件:applicationContext.xml
- 加载属性文件,并配置参数
- 配置平台事务管理器
- 配置事务通知(有Spring提供的切面类)
- 配置AOP增强
- 配置jdbc模板
- 配置Service
- 配置dao
<?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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--配置文件形式--> <!--使用标签方式--> <!--加载属性文件--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!--配置平台事务管理器--> <bean id="tran" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置事务的通知(由Spring提供的切面类)--> <tx:advice id="txAdvice" transaction-manager="tran"> <tx:attributes> <!--对pay进行增强,设置隔离级别,传播行为,超时时间--> <tx:method name="pay" isolation="DEFAULT"/> <tx:method name="find*" read-only="true"></tx:method> </tx:attributes> </tx:advice> <!--配置AOP增强--> <aop:config> <!--Spring框架提供系统通知,使用advisor标签--> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.qcby.service.impl.AccountServiceImpl.pay(..))"></aop:advisor> </aop:config> <!--配置jdbc模板--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置Service--> <bean id="accountService" class="com.qcby.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!--配置Dao--> <bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> </beans> - 创建测试类:AccountTest类
package com.qcby.text; import com.qcby.service.AccountService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * IOC:配置文件形式 * JDBC模板,配置文件形式 + 属性文件 * 声明式事务:配置文件形式(Spring框架提供AOP) */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AccountTest { @Autowired public AccountService accountService; @Test public void run(){ accountService.pay("美羊羊","沸羊羊",100.0); } }
半注解形式(配置文件 + 注解)
常用的注解
@Transactional()注解:将一个方法或类标记为需要事务性执行- 也就是说,在方法上添加了这个注解,Spring会在这个方法上开始执行前自动开启一个数据库事务,方法完毕后提交事务,出现异常回滚事务。
isolation属性:设置事务隔离级别@EnableAspectJAutoProxy注解:开启事务注解@PropertySource("classpath:jdbc.properties")注释:读取属性文件
实操案例
- 前三步与上面配置文件形式一样
- 持久层种的实现类,加上注解
@Repository("accountDao2") public class AccountDaoImpl2 implements AccountDao { @Autowired private JdbcTemplate jdbcTemplate; // ……其它代码与上面一致 } - 业务层种的实现类,加上注解
@Service("accountService2") // 设置事务级别 @Transactional(isolation = Isolation.DEFAULT) public class AccountServiceImpl2 implements AccountService{ @Autowired @Qualifier("accountDao2") private AccountDao accountDao; // ……其它代码与上面一致 } - 属性文件内容不变
- 配置文件内容有修改:applicationContext2.xml
- 去掉配置Service、配置Dao、配置AOP增强的Bean管理代码,修改为开启注解扫描
- 去掉配置事务的通知(由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" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--配置文件 + 注解--> <!--开启注解扫描--> <context:component-scan base-package="com.qcby"> <!-- 排除标注了@Configuration的类 --> <context:exclude-filter type="annotation" expression="org.springframework.context.annotation.Configuration"/> </context:component-scan> <!--标签方式--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--加载属性文件--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!--配置平台事务管理--> <bean id="tean" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置JDBC模板--> <bean id="jdebTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--开启事务注解支持--> <tx:annotation-driven transaction-manager="tean"></tx:annotation-driven> </beans> - 创建测试类:AccountTest2类
package com.qcby.text; import com.qcby.service.AccountService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * IOC:配置文件形式 + 注解 * JDBC模板,配置文件形式 + 属性文件 * 声明式事务:配置文件形式 + 注解 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext2.xml") public class AccountTest2 { @Autowired @Qualifier("accountService2") public AccountService accountService; @Test public void run(){ accountService.pay("美羊羊","沸羊羊",100.0); } }
全注解形式
实操案例
- 前3步与上面半注解形式一致
- 不在需要属性文件和配置文件,只需要创建配置类:SpringConfig类
- 配置数据库连接池
- 创建模板对象
- 创建平台事务管理对象
package com.qcby.tools; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.transaction.PlatformTransactionManager; import javax.annotation.Resource; import javax.sql.DataSource; @Configuration @ComponentScan("com.qcby") // 开启事务注解 @EnableAspectJAutoProxy public class SpringConfig { /** * 连接数据库 * @return * @throws Exception */ @Bean("dataSource") public DataSource dataSource() throws Exception{ // 创建连接池对象,Spring框架内置了连接池对象 DriverManagerDataSource ds = new DriverManagerDataSource(); // 设置4个参数 ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql:///spring_db"); ds.setUsername("root"); ds.setPassword("root"); return ds; } /** * 创建模板对象 * @param dataSource * @return */ @Resource(name = "dataSource") // 不仅可以作用在属性上,也可以作用方法上 @Bean("jdbcTemplate") // 把JdbcTemplate保存到IOC容器中 public JdbcTemplate createJdbcTemplate(DataSource dataSource){ JdbcTemplate template = new JdbcTemplate(dataSource); return template; } /** * 创建平台事务管理器对象 * @param dataSource * @return */ @Resource(name = "dataSource") @Bean("manager") public PlatformTransactionManager createTransactionManager(DataSource dataSource){ DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource); return manager; } } - 创建测试类:AccountTest3类
package com.qcby.text; import com.qcby.service.AccountService; import com.qcby.tools.SpringConfig; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * IOC全注解:注解类 * JDBC模板全注解,注解类 * 声明式事务:注解类 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {SpringConfig.class}) public class AccountTest3 { @Autowired @Qualifier("accountService3") public AccountService accountService; @Test public void run(){ accountService.pay("美羊羊","沸羊羊",100.0); } }
Spring声明式事务详解

被折叠的 条评论
为什么被折叠?



