深入理解Spring事务

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42292373/article/details/102532201

项目环境的搭建

在这里插入图片描述

beans.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: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.xsd
     	 http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
     	 http://www.springframework.org/schema/tx/spring-tx.xsd">
	<!-- 开启注解 -->
	<context:component-scan base-package="com.itmayiedu"></context:component-scan>
	<!-- 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://localhost:3306/ibis"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	<!-- 配置jdbc数据源 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
<!--	&lt;!&ndash; 配置事物 dataSource &ndash;&gt;-->
<!--	<bean id="dataSourceTransactionManager"-->
<!--		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">-->
<!--		<property name="dataSource" ref="dataSource"></property>-->
<!--	</bean>-->
<!--	&lt;!&ndash; 开启事物注解 &ndash;&gt;-->
<!--   <tx:annotation-driven  transaction-manager="dataSourceTransactionManager"/>-->
</beans>

logdao


package com.itmayiedu.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class LogDao {
	@Autowired
	private JdbcTemplate jdbcTemplate;

	public void addLog() {
		String sql = "insert into log values(1,?);";
		jdbcTemplate.update(sql, System.currentTimeMillis());
	}

}

userdao

在这里插入代码片

l;ogservice


package com.itmayiedu.service;

import com.itmayiedu.dao.LogDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class LogService {
	@Autowired
	private LogDao logDao;

   @Transactional(propagation=Propagation.NEVER)
	public void addLog() {
		logDao.addLog();
		System.out.println("我日志添加成啦");
	}

}

userSevice


package com.itmayiedu.service;

import com.itmayiedu.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

	@Autowired
	private UserDao userDao;

	@Autowired
	private LogService logService;

	public void add() {
		logService.addLog();
		userDao.addUser("lisi-" + System.currentTimeMillis(), 18);
//		int i = 1 / 0;
	}
}

app

package com.itmayiedu;

import com.itmayiedu.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.add();
        System.out.println(userService);
    }
}

引出事务的产生的原因

在这里插入图片描述
此时当我UserSerice调用日志服务的时候,加入此时我userService服务报错,此时数据log的数据能否添加上?

答案都可以的。因为 他们已经做了操作,此时无法回滚啦,这就是
如果是这样呢?
在这里插入图片描述
此时只会添加log而不会添加用户。 这就是分布式事务的问题的演示

事务的解决方案

编程事务

在xml添加事务管理器

 <!-- 配置事物 -->
   <bean  id="DataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
   </bean>

添加事务管理的配置类


package com.itmayiedu.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

@Component
public class TransactionManager {

	@Autowired
	private DataSourceTransactionManager dataSourceTransactionManager;

	public TransactionStatus begin() {
		return dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
	}

	public void commit(TransactionStatus transactionStatus) {
		dataSourceTransactionManager.commit(transactionStatus); 

	}

	public void rollback(TransactionStatus transactionStatus) {
		dataSourceTransactionManager.rollback(transactionStatus);
	}

}

修改service


package com.itmayiedu.service;

import com.itmayiedu.dao.UserDao;
import com.itmayiedu.transaction.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;

@Service
public class UserService {

	@Autowired
	private UserDao userDao;

	@Autowired
	private LogService logService;

	@Autowired
	private TransactionManager transactionManager;

	public void add() {
		TransactionStatus begin = null;
		try {
			begin = transactionManager.begin();
			logService.addLog();
			int i = 1 / 0;
			userDao.addUser("lisi-" + System.currentTimeMillis(), 18);
			transactionManager.commit(begin);
		} catch (RuntimeException r) {
			transactionManager.rollback(begin);
			new RuntimeException(r.getMessage());

		}
	}
}

此时运行会发现一方报错,双方都不会修改数据

增强事务

	<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true" />
			<tx:method name="find*" read-only="true" />
			<tx:method name="*" read-only="false" />
		</tx:attributes>
	</tx:advice>
	<!-- Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.itmayiedu.service.*.*(..))"
					  id="pt" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
	</aop:config>
public void add() {
		TransactionStatus begin = null;
			try {
				logService.addLog();
				int i = 1 / 0;
				userDao.addUser("lisi-" + System.currentTimeMillis(), 18);
			} catch (Exception e){
				e.printStackTrace();
			}
		}
	}

此时在进行添加的时候,我们发现log还是添加了数据这是为什么呢?

事物是程序运行如果没有错误,会自动提交事物,如果程序运行发生异常,则会自动回滚。
如果使用了try捕获异常时.一定要在catch里面手动回滚。
事物手动回滚代码
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

注解事务

<?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: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.xsd
     	 http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
     	 http://www.springframework.org/schema/tx/spring-tx.xsd">
	<!-- 开启注解 -->
	<context:component-scan base-package="com.itmayiedu"></context:component-scan>
	<!-- 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://localhost:3306/ibis"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	<!-- 配置jdbc数据源 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 配置事物 dataSource -->
	<!-- 配置事物 -->
	<bean id="dataSourceTransactionManager"
		  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
<!--	<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">-->
<!--		<tx:attributes>-->
<!--			<tx:method name="get*" read-only="true" />-->
<!--			<tx:method name="find*" read-only="true" />-->
<!--			<tx:method name="*" read-only="false" />-->
<!--		</tx:attributes>-->
<!--	</tx:advice>-->
<!--	&lt;!&ndash; Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 &ndash;&gt;-->
<!--	<aop:config>-->
<!--		<aop:pointcut expression="execution(* com.itmayiedu.service.*.*(..))"-->
<!--					  id="pt" />-->
<!--		<aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />-->
<!--	</aop:config>-->

	<!-- 开启注解事物 -->
	<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

</beans>
	@Transactional
	public void add() {
		TransactionStatus begin = null;
				logService.addLog();
				int i = 1/0;
				userDao.addUser("lisi-" + System.currentTimeMillis(), 18);
		}
	}

Spring的事务传播行为

在这里插入图片描述
需求的出现:根据我们刚刚的列子我们可以知道,如果log服务出错的话,相关的user的add服务也会回滚,但是在正常的服务的当中,日志影响正常服务的是是非的严重的,那么如何避免这个问题,引出今天的话题;

Spring中事务的定义:
Propagation(key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。)有以下选项可供使用:
•	PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
•	PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
•	PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 
•	PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 
•	PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 
•	PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

详情参考这位大佬写的博客,本来写好啦,但是感觉别人写的比我好…
https://blog.csdn.net/weixin_39625809/article/details/80707695

猜你喜欢

转载自blog.csdn.net/qq_42292373/article/details/102532201