Spring事物传播行为
Spring中事务的定义:
Propagation(key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。)有以下选项可供使用:
PROPAGATION_REQUIRED—如果当前有事务,就用当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。//如果外层方法没有事务,
就会以非事务进行执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
--- 如果当前有事务,就是以非事务进行执行
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
默认传播行为为REQUIRED
上节课已经把两种传播行为讲完了,后面还有几种,我就一一给大家讲,这里还有一个SUPPORTS,这种我给你讲一下,
传播行为应用场景,场景是什么,这个事情说一下,比如我给你讲一个场景,开发的时候都是多个人整合,如果你碰到去
调用别人的service的时候,那么说一下,你这个时候要记住一点,一定要搞清楚传播行为,其实别人写的一个service,
你调用别人的service,别人的service也是加了事务注解的,你就要去问一下别人,什么意思呢,就是说,问一下别人,
我的事务会不会影响到你的事务,这样的,这里就要考虑传播行为了,如果不影响的话,你就用required_new就行了,
然后在这边我再讲一种,叫做支持SUPPORTS,其实这个用的比较少,它是支持当前的事务,如果当前没有事务,就以非事务
进行执行,这个你们知道是什么意思吗,知不知道什么意思,这个其实就是事务嵌套,我马上就要讲嵌套了,支持当前事务,
如果当前没有事务,就以非事务进行执行,这是什么意思,有没有谁能解释一下的,这个其实什么意思呢,在这边说一下,
支持当前事务,如果当前没有事务,比如这个时候你们看一下,如果add当前没有事务的情况下,然后我把addLog的事务级别设置一下,
@Transactional(propagation = Propagation.SUPPORTS),那么我来问一下,这个时候我突然报个错,
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addLog() {
/**
* 加个时间戳System.currentTimeMillis()
*
*/
logDao.add("addLog" + System.currentTimeMillis());
int i = 1 / 0;
}
// @Transactional
public void add() {
logService.addLog();
userDao.add("test001", 20);
int i = 1 / 0;
System.out.println("################");
userDao.add("test002", 21);
}
int i = 1/0,你们说一下这个是什么意思,这个时候日志能不能插入进去,这个时候log日志能不能插入进去,当前没有事务的情况下
就以非事务进行执行,就是这样的,我设置的是新的级别,新的传播行为,你们看一下,后面的几种你们可以慢慢的去摸索一下就行了,
我把外面的事务给注释掉了,你们看看效果,你们看一下是不是报错了,最后我们刷新一遍,是不是也有记录的,我们想一下是什么意思,
你们要记住,如果当前没有事务的情况下,就以非事务进行执行,相当于我没有事务,没有事务的情况下,我肯定能够插入进去,就是外面你
调我的方法的时候,如果没有事务注解,里面就以非事务进行执行,然后我们再讲MANDATORY这种,支持当前事务,如果当前没有事务就抛出
异常,这也是借鉴一本书上写的,如果外层方法没有事务,就会以非事务进行执行,我们再说一种就是PROPAGATION_MANDATORY这种方式,
就是支持当前事务,如果当前没有事务就抛出异常,我们来设置一下这种传播行为,这里我来问你们,如果当期没事务,你们看看,
当前是没有事务的,然后运行肯定报错,不是int i = 1/0报错,是不是报错了,什么意思,他就是他没有检测到他当前有事务,
就是你的add调用我的方法是没有事务,我们可以把这个注解加上去,支持当前事务,如果当前没有事务才会报错,有事务怎么
可能报错,REQUIRES_NEW我们已经讲了,我们再讲一种PROPAGATION_NOT_SUPPORTS,以非事务执行操作,如果当前存在事务,
就把当前事务挂起,这是什么意思呢,有谁知道,就是相当于,如果当前有事务,正好是和PROPAGATION_SUPPORTS相反的,
如果当前有事务,就是以非事务进行执行,就是刚好相反的,看下效果就行了,add存在事务,如果当前存在事务,挂起不报错,
只是挂起,相当于失效,不会报错,就是addLog这边会以非事务进行执行,然后我们搞一个 int i = 1/0,
public void addLog() {
logDao.add("addLog" + System.currentTimeMillis());
int i = 1 / 0;
}
报错了,但是数据库日志记录还是有的,当前如果有事务就把当前的事务挂起,这个比较简单你们下去看一下,都是比较容易的,
然后我们这里再讲一种,以非事务进行执行,如果当前存在事务,则抛出异常,以非事务进行异常,你们下去试一试,就是看效果,
我要说一下,以非事务进行执行,如果当前有事务就抛异常,这个才会抛异常,你们看一下,
Existing transaction found for transaction marked with propagation 'never'
如果当前存在事务的情况下,他就抛个异常出来,是不是这样的,你们下去试一下就行了,传播行为不是我们的核心,
核心是我们的手写事务
<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">
<!-- aop的扫包注解是有的 -->
<context:component-scan base-package="com.learn"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<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/day20"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 我们把原生的事务注解删掉 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
</beans>
package com.learn.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 add(String name) {
String sql = "INSERT INTO t_log(log_name) VALUES(?);";
int updateResult = jdbcTemplate.update(sql, name);
System.out.println("##LogDao##updateResult:" + updateResult);
}
}
package com.learn.service;
public interface LogService {
public void addLog();
}
package com.learn.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.learn.dao.LogDao;
import com.learn.service.LogService;
/**
* 7种传播行为
* 这个问的比较多的
* 注入到Spring容器里面去@Service
*
*
* @author Leon.Sun
*
*/
@Service
public class LogServiceImpl implements LogService {
/**
* 把@Autowired这个注解也加上去
*
*/
@Autowired
private LogDao logDao;
// @Transactional(propagation = Propagation.REQUIRES_NEW)
// @Transactional
// @Transactional(propagation = Propagation.SUPPORTS)
// @Transactional(propagation = Propagation.MANDATORY)
// @Transactional(propagation = Propagation.NOT_SUPPORTED)
@Transactional(propagation = Propagation.NEVER)
public void addLog() {
logDao.add("addLog" + System.currentTimeMillis());
// int i = 1 / 0;
}
}
package com.learn.service;
//user 服务层
public interface UserService {
public void add();
public void del();
}
package com.learn.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.learn.dao.UserDao;
import com.learn.service.LogService;
import com.learn.service.UserService;
import com.learn.transaction.TransactionUtils;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private TransactionUtils transactionUtils;
@Autowired
private UserDao userDao;
@Autowired
private LogService logService;
/**
* 加上@Transactional这个注解
*
*/
@Transactional
public void add() {
logService.addLog();
userDao.add("test001", 20);
// int i = 1 / 0;
System.out.println("################");
userDao.add("test002", 21);
}
public void del() {
System.out.println("del");
}
}
package com.learn;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.learn.service.UserService;
public class Test001 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
userService.add();
}
}