spring-boot学习:十一、spring-boot集成事务

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

spring-boot事务也就是使用spring事务,业务执行过程中出现异常事务能够自动回滚,避免数据库出现脏数据。

0. 未加事务的demo

1)Mybatis(UserMapper)加入insert方法

<mapper namespace="com.kevin.springbootstudy.dao.UserMapper">

    <select id="findUserById" resultType="user" parameterType="java.lang.String">
        select * from user where id = #{id}
    </select>

    <insert id="insert" parameterType="user">
        insert into user(id, name) values (#{id}, #{name})
    </insert>

</mapper>
@Repository
public interface UserMapper {

    @Select("select name from user where id = #{id}")
    String findNameById(@Param("id") String id);

    User findUserById(@Param("id") String id);

    int insert(User user);
}

2) 编写UserService,加入insert方法

@Service
public class UserService {
    @Autowired
    private UserMapper userDao;

    public int insert(User user){
        int i= userDao.insert(user);
        if(i==1){
            throw new RuntimeException("error");
        }
        return i;
    }
}

3)编写UserController,提供增加用户的接口

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "addUser")
    public Object addUser(@RequestParam(value = "id")String id, @RequestParam(value = "name")String name){

        User user=new User();
        user.setId(id);
        user.setName(name);
        return userService.insert(user);
    }
}

4. 测试
调用http://127.0.0.1:8081/addUser?id=3&name=kevin3后,返回异常,但数据库却增加了相应的user记录,这显然不是我们想要的,所以需要加入事务。

1. 通过注解的方式

1)在configuration上加@EnableTransactionManagement开启事务,springboot默认开启事务不需要手动加。

2)在service类(方法)上加入@Transactional可开启事务,注意加在类上只针对public的方法有效

package com.kevin.springbootstudy.service;

import com.kevin.springbootstudy.dao.UserMapper;
import com.kevin.springbootstudy.dao.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Autowired
    private UserMapper userDao;

    @Transactional
    public int insert(User user){
        int i= userDao.insert(user);
        if(i==1){
            throw new RuntimeException("error");
        }
        return i;
    }
}

3)再次测试
调用http://127.0.0.1:8081/addUser?id=4&name=kevin4后,返回异常,数据库没有增加相应的user记录,这就是我们想要的结果。

2. 通过xml配置

1)transaction.xml文件

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<aop:config>
	<aop:pointcut id="serviceOperation" expression="execution(* com.*..service.*Service.*(..))"/>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
</aop:config>

<tx:advice id="txAdvice">
	<tx:attributes>
		<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
		<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
		<tx:method name="query*" propagation="SUPPORTS" read-only="true" />
		<tx:method name="*" propagation="REQUIRED" />
	</tx:attributes>
</tx:advice>

<!--支持@Tranctional注解-->
<tx:annotation-driven transaction-manager="transactionManager" />

2)引入文件@ImportResource(“classpath:transaction.xml”)

3. aop全局配置事务

1)pom.xml引入aop

扫描二维码关注公众号,回复: 7592112 查看本文章
<!-- aop -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2)增加一个事务管理的类

@Aspect
@Configuration
public class TransactionAdviceConfig {
	
	private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.***.service..*.*(..))";

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Bean
    public TransactionInterceptor txAdvice() {

        DefaultTransactionAttribute txRequired = new DefaultTransactionAttribute();
        txRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        DefaultTransactionAttribute txRequiredReadonly = new DefaultTransactionAttribute();
        txRequiredReadonly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        txRequiredReadonly.setReadOnly(true);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        source.addTransactionalMethod("get*", txRequiredReadonly);
        source.addTransactionalMethod("query*", txRequiredReadonly);
        source.addTransactionalMethod("find*", txRequiredReadonly);
        source.addTransactionalMethod("*", txRequired);

        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
}

3)部分方法需要单独处理事务,也可以配合@Transactional一起使用

易错点(@Transactional):

1)spring推荐在具体类上使用@Transactional,而不是在接口上声明

2)@Transactional声明在类上,则对所有的public方法有效

3)使用了@Transactional的方法,被同一个类里面的未使用@Transactional的方法调用, @Transactional无效。比如有一个类Test,它的一个方法A,A再调用Test本类的方法B(不管B是否public还是private),但A没有声明注解事务,而B有。则外部调用A之后,B的事务是不会起作用的。

注:目录结构如下
在这里插入图片描述
参考
https://docs.spring.io/spring/docs/5.1.4.RELEASE/spring-framework-reference/data-access.html#transaction-declarative

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/EnableTransactionManagement.html

https://blog.csdn.net/nextyu/article/details/78669997

猜你喜欢

转载自blog.csdn.net/guangcaiwudong/article/details/101757344