spring的编程式事务和声明式事务管理(xml方式和注解方式)

本文深入探讨Spring框架中的事务管理机制,包括事务的四大特性(ACID)、常见的并发问题及解决方案,并详细介绍了编程式事务管理、XML配置式声明事务管理和注解式声明事务管理的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.事务

     1.1.事务的四大特性ACID

        (1)原子性(Atomicity)事务所包含的操作,要么全部成功,要么全部失败回滚,具有不可分割性。

        (2)一致性(Consistency)事务执行前和执行之后都必须处于一致性状态。

        (3)隔离性(Isolation)多个并发事务之间要相互隔离。

        (4)持久性(Durability)事务一旦提交,数据库中的数据就被持久化。

     1.2.事务的并发问题

         (1)脏读:当一个事务在修改数据还未提交时,另一个事务来访问该事务。

         (2)不可重复读:一个事务在多次查询的间隔,被另一个事务修改并提交了数据,查询到不同的结果。

         (3)幻读(虚读):一个事务在对所有数据进行修改时,另外一个事务插入了一条数据,导致修改完之后,发现仍有一条记录没有被修改。以为自己产生了幻觉。

     1.3.事务的隔离级别

           (1)Read uncommitted(读未提交)

           (2)Read committed(读已提交):避免脏读

           (3)Repeatable read(可重复度):避免脏读 不可重复读

           (4)Serializable(串行化):避免幻读

2.spring的事务管理

    2.1.准备数据表


    2.2.准备转账的业务代码

package work.yuegege.domain;

public class Account {
	private int id;
	private String name;
	private double account;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getAccount() {
		return account;
	}
	public void setAccount(double account) {
		this.account = account;
	}
	@Override
	public String toString() {
		return "Account [id=" + id + ", name=" + name + ", account=" + account
				+ "]";
	}
}
   
package work.yuegege.dao;

public interface TransactionAccountDao {
	public void addAccount(String name,double account);
	
	public void subAccount(String name,double account);

}

package work.yuegege.daoImpl;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

import work.yuegege.dao.TransactionAccountDao;

public class TransactionAccountDaoImpl extends JdbcDaoSupport implements TransactionAccountDao{

	@Override
	public void addAccount(String name, double account) {
		super.getJdbcTemplate().update("update account set money=money+? where user=?",account,name);
		
	}

	@Override
	public void subAccount(String name, double account) {
		super.getJdbcTemplate().update("update account set money=money-? where user=?",account,name);
		
	}
	

}
package work.yuegege.service;

public interface AccountService {
	public void transaction(String from ,String to,double money);

}

  2.3.编程式事务管理

package work.yuegege.service;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import work.yuegege.dao.TransactionAccountDao;

public class AccountServiceImpl implements AccountService {

	private TransactionAccountDao transactionAccountDao;
	
	private TransactionTemplate transactionTemplate;
	
	public void transaction(final String from , final String to , final double money) {
		
		//这里运用编程式事务管理 TransactionTemplate封装了事务的打开,回滚,和事务的关闭方法。
		//但这种方法不适合多业务的操作,因为每个业务都需要将代码放在execute()方法中。
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				transactionAccountDao.subAccount(from, money);
				int i=1/0;
				transactionAccountDao.addAccount(to, money);
			}
		});
	}
	public void setTransactionAccountDao(TransactionAccountDao transactionAccountDao) {
		this.transactionAccountDao = transactionAccountDao;
	}
	
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
}

    applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.springframework.org/schema/beans" 
xmlns:p="http://www.springframework.org/schema/p" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
	<!-- 1.配置连接池 -->
	<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="jdbcUrl" value="jdbc:mysql:///students"></property>
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	
	<!--2.将JDBCTemplate放入spring容器 -->
	<!-- <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
		<property name="dataSource" ref="dataSource"></property>
	</bean> -->
	
	<!-- 编程式事务管理 -->
		<!--1.配置核心事务管理器  -->
		<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="dataSource"></property>
		</bean>
		
		<!--2.配置事务模板对象  -->
		<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
			<property name="transactionManager" ref="transactionManager"></property>
		</bean>
	
	<!--3.将AccountDaoImpl放入spring容器 -->
	<bean name="transactionAccountDao" class="work.yuegege.daoImpl.TransactionAccountDaoImpl">
		<!-- <property name="jbbcTemplate" ref="jdbcTemplate"></property> -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!--4.将AccountServiceImpl放入spring容器  -->
	<bean name="accountService" class="work.yuegege.service.AccountServiceImpl">
		<property name="transactionAccountDao" ref="transactionAccountDao"></property>
		<property name="transactionTemplate" ref="transactionTemplate"></property>
	</bean>
	
	
	
	
	
	 
</beans>

  编写测试类

	@Test
	public void test8(){
		ApplicationContext applicationContext=new ClassPathXmlApplicationContext("work/yuegege/test/applicationContext.xml");
		AccountService accountService=(AccountService) applicationContext.getBean("accountService");
		accountService.transaction("lucy", "mengyue", 500);
		System.out.println("转账成功");
	}

 结果:



因为转账过程发生了异常,所以回滚。转账没有成功

2.4.xml方式配置spring的声明式事务管理

package work.yuegege.service;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import work.yuegege.dao.TransactionAccountDao;

public class AccountServiceImpl implements AccountService {

	private TransactionAccountDao transactionAccountDao;
	
	public void transaction(final String from , final String to , final double money) {
		
		transactionAccountDao.subAccount(from, money);
		int i=1/0;
		transactionAccountDao.addAccount(to, money);
			
	}
	public void setTransactionAccountDao(TransactionAccountDao transactionAccountDao) {
		this.transactionAccountDao = transactionAccountDao;
	}
	
}

 applicationContext.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans" 
	xmlns:p="http://www.springframework.org/schema/p" 
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
	<!-- 1.配置连接池 -->
	<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="jdbcUrl" value="jdbc:mysql:///students"></property>
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	
	<!--2.配置核心事务管理器  -->
	<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!--3.配置事务通知  -->
	<!-- isolation 表示事务的隔离级别    propagation事务的传播行为:默认值为:REQUIRED 
	 	read-only 表示是否只读   默认值:false -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="transaction" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
		</tx:attributes>
	</tx:advice>
	
	<!--4.将通知织入目标对象  -->
	<aop:config>
		<!--配置切点 -->
		<aop:pointcut expression="execution(* work.yuegege.service.*ServiceImpl.*(..))" id="txPointCut"/>
		<!--配置切面 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
	</aop:config>
	
	<!-- 将TransactionAccountDaoImpl放入spring容器-->
	<bean name="transactionAccountDao" class="work.yuegege.daoImpl.TransactionAccountDaoImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!--将accountService放入spring容器  -->
	<bean name="accountService" class="work.yuegege.service.AccountServiceImpl">
		<property name="transactionAccountDao" ref="transactionAccountDao"></property>
	</bean>
		 
</beans>

编写测试类:

//xml方式进行声明式事务管理测试
	@Test
	public void test9(){
		ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
		AccountService accountService=(AccountService) applicationContext.getBean("accountService");
		accountService.transaction("lucy", "mengyue", 500);
		System.out.println("转账成功");
	}

结果与上面一样。


2.5.注解方式配置spring的声明式事务管理

   2.5.1.注入TransactionAccountDaoImpl和JdbcTemplate

        在上面的业务代码中加上红色的注解

import javax.annotation.Resource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Component;

import work.yuegege.dao.TransactionAccountDao;

@Component("transactionAccountDao")
public class TransactionAccountDaoImpl implements TransactionAccountDao{
    
	
	private JdbcTemplate jdbcTemplate;
	
	@Resource(name = "jdbcTemplate")
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

  2.5.2.注入AccountServiceImpl和事务

@Component("accountService")
public class AccountServiceImpl implements AccountService {
	@Resource(name="transactionAccountDao")
	private TransactionAccountDao transactionAccountDao;
	
	@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
	public void transaction(final String from , final String to , final double money) {

   2.5.3.applicationContext.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans" 
	xmlns:p="http://www.springframework.org/schema/p" 
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
	<!-- 1.配置连接池 -->
	<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="jdbcUrl" value="jdbc:mysql:///students"></property>
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	
	<context:component-scan base-package="work.yuegege.*"></context:component-scan>
	
	<!-- 开启注解管理事务 -->
	<tx:annotation-driven/>
	
	<!--2.将JDBCTemplate放入spring容器 -->
	<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!--配置核心事务管理器  -->
	<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="dataSource"></property>
	</bean>
 
</beans>

    2.5.4.测试类

@Test
	public void test10(){
		ApplicationContext applicationContext=new ClassPathXmlApplicationContext("work/yuegege/service/applicationContext.xml");
		AccountService accountService=(AccountService) applicationContext.getBean("accountService");
		accountService.transaction("lucy", "mengyue", 500);
		System.out.println("转账成功");
	}

    2.5.5结果

结果与上面一样。






        





        


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值