Spring之事务管理

1.Spring事务管理的两种方式

Java EE应用的事务策略分为全局事务和局部事务。大多数情况下,我们都使用局部事务,所以这篇文章就不说全局事务了。

而Spring 框架为局部事务提供了两种管理方式,分别如下

(1)编程式事务管理:通过编程实现,但我们太懒了,所以一般不用。

(2)声明式事务管理:通过声明实现。

而声明式事务管理又可以通过以下两种方式实现

  • 基于配置文件实现
  • 基于注解的实现

2.Spring事务管理的API

Spring框架提供的事务管理抽象层主要由org.springframework.transaction包下的三个接口组成:

  • TransactionDefinition接口:用于描述事务的隔离级别、传播规则、超时时间、是否为只读事务等特性,可以编程设置这些特性,也可以通过XML文件或者注解配置。

  • TransactionStatus接口:用于描述事务的状态,事务管理器通过该接口可以获取事务的运行期状态信息,也可以通过该接口间接的回滚事务,它相比于在抛出异常时回滚事务的方式更具有可控性。

  • PlatformTransactionManager接口:该接口代表事务管理器,是Spring事务管理的核心接口。

针对不同的持久化技术,Spring提供了PlatformTransactionManager接口的不同实现类:

  • JpaTransactionManager:使用JPA持久化的事务管理器。

  • HibernateTransactionManager:使用Hibernate持久化的事务管理器。

  • DataSourceTransactionManager:使用Spring JDBC、iBatis等DataSource数据源持久化时的事务管理器。

  • JdoTransactionManager:使用JDO持久化的事务管理器。

  • JtaTransactionManager:使用全局事务的事务管理器。

3.步骤

无论是使用XML配置事务还是使用注解配置事务,都有以下几步
(1)配置数据源
(2)配置事务管理器
(3)配置事务增强
(4)配置事务增强的切面

####准备工作
导jar包,这里我们使用了c3p0连接池,所以导入了c3p0的jar包
9.png

引入约束

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx" 
        xmlns:jdbc="http://www.springframework.org/schema/jdbc"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.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
        http://www.springframework.org/schema/jdbc 
        http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"> 
</beans>

新建数据库account
11.png

新建dao和service

public class AccountDao {
	// JdbcTemplate实例
	private JdbcTemplate jdbcTemplate;
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	/**
	 * 账户减少钱
	 */
	public void lessAccount() {
		String sql = "update account set money = money - ? where name = ?";
		jdbcTemplate.update(sql, 1000, "CodeTiger");
	}
	
	/**
	 * 账户增加钱
	 */
	public void moreAccount() {
		String sql = "update account set money = money + ? where name = ?";
		jdbcTemplate.update(sql, 1000, "xu");
	}
}
public class AccountService {
	private AccountDao accountDao;

	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}
	
	public void accountMoney() {
		// 一个账户减少钱
		accountDao.lessAccount();
		
		// 提现事务的功能
		int a = 10 / 0;
		System.out.println(a);
		
		// 一个账户增加钱
		accountDao.moreAccount();
	}
}

####基于XML配置文件的事务管理
(1)配置数据源

    <!-- 配置c3p0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/spring"></property>
		<property name="user" value="root"></property>
		<property name="password" value="1311664842"></property>
	</bean>

配置了c3p0连接池一些最基本的参数,仅用于连接。

(2)配置事务管理器

    <!-- 配置jdbc的事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

不同的持久化技术,使用的事务管理器不一样,这里我们使用JDBC的事务管理器。

(3)配置事务增强

使用<tx:advice>标签,可以为一个或一批(通过通配符的方式进行方法名称的匹配)方法配置事务增强。

<tx:advice>标签有两个属性

  • id:唯一标识。

  • transaction-manager:已经配置的事务管理器bean的id,如果事务管理器bean的id值为transactionManager,则可以省略此属性。

<tx:advice>标签具有<tx:attributes>子标签,通过<tx:attributes>标签的子标签<tx:method>可以配置需要被事务增强的方法,以及事务的传播、隔离、超时、只读事务、对指定异常回滚和对指定异常不会滚的属性。<tx:method>标签的属性如下:

  • name:配置需要被事务增强的方法名,可以使用通配符*。

  • propagation:配置事务的传播类型。可选择REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED之一,默认为REQUIRED。

  • isolation:配置事务的隔离级别。可选择DEFAULT、READ_UNCOMMITED、READ_COMMITED、REPEATABLE_READ、SERIALIZABLE之一,默认为DEFAULT。

  • timeout:配置事务超时时间(以秒为单位),默认为-1,表示事务超时的时间由底层的事务系统决定。

  • read-only:配置是否为只读事务,默认为false。

  • rollback-for:配置需要自动回滚事务的异常类型,默认所有RuntimeException都会回滚。

  • no-rollback-for:配置不触发自动回滚事务的异常类型,默认所有CheckedException都不会回滚。

下面的代码配置事务增强

    <!-- 配置事务增强 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<!-- 做事务操作 -->
		<tx:attributes>
			<!-- 设置进行事务操作的方法匹配原则 -->
			<tx:method name="account*"/>
		</tx:attributes>
	</tx:advice>

(4)配置事务增强的切面

这一步将事务增强与切入点关联在一起。配置ide方法与普通的切面配置相同。

    <!-- 配置切面 -->
	<aop:config>
		<!-- 配置切入点,注意这里的切入点是service,不是dao -->
		<aop:pointcut expression="execution(* com.codeliu.service.AccountService.*(..))" id="pointcut1"/>
		<!-- 把增强用到切入点上 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
	</aop:config>

事务管理也使用了AOP的原理,即把事务增强看成切面,service看成切点(当然也可以把dao看成切点,这时事务增强的方法匹配规则就得相应的进行修改)

当然,配置文件中还少了一些东西,比如service和dao的实例化,以及获取操作数据库的实例对象。把它们也加上。

    <!-- 开启注解扫描 -->
	<context:component-scan base-package="com.codeliu"></context:component-scan>
	
	<!-- 开启aop操作 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!-- 配置Jdbc Template -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<bean id="accountDao" class="com.codeliu.dao.AccountDao">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	<bean id="accountService" class="com.codeliu.service.AccountService">
		<property name="accountDao" ref="accountDao"></property>
	</bean>

最后写一个测试方法进行测试

    @Test
	public void accountTest() {
		@SuppressWarnings("resource")
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		AccountService service = (AccountService)context.getBean("accountService");
		service.accountMoney();
	}

运行测试,出现除0异常,刷新数据库,账户余额没有发生变化,说明事务管理生效了。

####基于注解的事务管理

(1)启用注解式事务配置

使用注解配置事务,首先需要在XML配置文档中开启事务的注解

    <!-- 开启事务的注解 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>

该标签有三个属性

  • transaction-manager:已经配置好的事务管理器Bean的id,如果未指定,则会查找id为transactionManager的事务管理器Bean。
  • proxy-target-class:是否通过cglib创建子类代理对象。
  • order:如果业务类除事务切面外,还需要织入其他的切面,通过该属性可以控制事务切面在目标连接点的织入顺序。

(2)使用@Transactional注解

业务类或业务类的方法如果需要被增强,则需要使用@Transactional注解进行配置。

@Transactional注解的参数和前面讲的<tx:method>标签的属性非常类似。通常情况都使用默认值,不需要改动。

@Transactional注解可用于接口、接口的方法、类、类的public方法上,由于注解的不可继承性,通常建议在类上使用该注解。

如下,给service类加注解

// 开启事务,对该类的所有方法都生效
@Transactional
public class AccountService {
	private AccountDao accountDao;

	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}
	
	@Transactional(readOnly = true)
	public void accountMoney() {
		// 一个账户减少钱
		accountDao.lessAccount();
		
		// 提现事务的功能
		int a = 10 / 0;
		System.out.println(a);
		
		// 一个账户增加钱
		accountDao.moreAccount();
	}
}

上面的代码中,给AccountService 类加了@Transactional注解,给accountMoney方法也加了@Transactional注解并设置为只读。因此最终的配置结果就是AccountService 类的所有方法都会被增强,并且accountMoney方法使用的是只读事务。(覆盖了类上的注解)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值