企业网站建设太原网站建设,苏州做企业网站公司,开发出来的电子商务网站域名,电子商务网站建设分析如题#xff0c;最近碰到了一个问题#xff0c;在public方法上添加Transaction没有生效#xff0c;事务没有回滚。 我自己模拟了一个功能#xff0c;向数据库表User里面插入用户数据。说一下代码背景#xff0c; 数据库MySQL#xff0c;持久化层Mybatis#xff0c;项目使…如题最近碰到了一个问题在public方法上添加Transaction没有生效事务没有回滚。 我自己模拟了一个功能向数据库表User里面插入用户数据。说一下代码背景 数据库MySQL持久化层Mybatis项目使用SpringBoot。 数据表User如下已有一条数据 下面是代码
Application启动类
package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import tk.mybatis.spring.annotation.MapperScan;SpringBootApplication(scanBasePackages {com.example.demo,com.example.demo.dao})
//启动事务
EnableTransactionManagement
//mapper接口扫描
MapperScan(com.example.demo.dao)
RestController
public class DemoApplication {GetMapping(/)String home() {return Spring is here!;}public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}实体类User对应数据表user表
Data
Table(name user)
public class User {IdColumn(name id)GeneratedValue(strategy GenerationType.IDENTITY)private int id;Column(name name)private String name;Column(name created_time)private Date createdTime;
}Mapper类
package com.example.demo.dao;import com.example.demo.domain.po.User;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;/*** TOrderMapper** author zhouxy133.cn* date 2022/8/15**/
Repository
public interface UserMapper extends MapperUser, MySqlMapperUser {
}Service接口处理业务逻辑添加Transaction
package com.example.demo.service;import com.example.demo.domain.po.User;
import org.springframework.stereotype.Service;/*** Description: TODO* Author: zhouxy* CreateTime: 2023-10-17*/
public interface IUserService {Integer addUser(User user);
}service实现类
package com.example.demo.service.impl;import com.example.demo.dao.UserMapper;
import com.example.demo.domain.po.User;
import com.example.demo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** Description: TODO* Author: zhouxy* CreateTime: 2023-10-17*/
Service
public class UserService implements IUserService {Autowiredprivate UserMapper userMapper;OverrideTransactionalpublic Integer addUser(User user) {Integer result userMapper.insertSelective(user);}
}
AOP类
package com.example.demo.aop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;/*** Description: TODO* Author: zhouxy* CreateTime: 2023-05-17*/
Aspect
Component
Slf4j
public class LogAop {Pointcut(value execution(* com.example.demo.service.*.*(..)))public void controller() {log.info(223432);}Around(controller())public Object around(ProceedingJoinPoint joinPoint) {log.info(before);try {Object res joinPoint.proceed();return res;} catch (Throwable throwable) {log.error(, throwable);}finally {log.info(after);}return null;}
}
测试类
import com.example.demo.DemoApplication;
import com.example.demo.dao.UserMapper;
import com.example.demo.domain.po.User;
import com.example.demo.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;/*** MybatisTest** author zhouxy133.cn* date 2021/7/20**/
Slf4j
RunWith(SpringRunner.class)
SpringBootTest(classes DemoApplication.class)
public class MybatisTest {Autowiredprivate IUserService userService;Testpublic void test() {User user new User();user.setName(LISI222);userService.addUser(user);}
}
当正常执行的时候会在数据库中插入数据。
打印日志
此时在实现类中加入一行异常看一下出现异常之后事务是否会回滚数据能否成功插入到数据表中。
package com.example.demo.service.impl;import com.example.demo.dao.UserMapper;
import com.example.demo.domain.po.User;
import com.example.demo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** Description: TODO* Author: zhouxy* CreateTime: 2023-10-17*/
Service
public class UserService implements IUserService {Autowiredprivate UserMapper userMapper;OverrideTransactionalpublic Integer addUser(User user) {Integer result userMapper.insertSelective(user);//添加一行异常查看事务是否会因为抛出异常回滚刚才的插入操作throw new RuntimeException();}
}
我们看执行完之后数据库的变化我刚才插入的是用户LISI222
显示的是插入成功看后台日志显示事务并没有做回滚操作说明当前事务并没有捕获到异常信息。仔细分析日志头尾可知日志打印操作包裹了service实现类的addUser方法应该是aop操作在Transaction之前执行导致异常被aop处理了aop最终也没有抛出异常所以Transaction方法没有捕获到异常信息。
2023-11-24 10:53:24.418 INFO [,,,] 29600 --- [ main] com.example.demo.aop.LogAop : before
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession6c3884f5]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl5542418c] will be managed by SpringPreparing: INSERT INTO user ( id,name ) VALUES( ?,? )Parameters: 0(Integer), LISI222(String)Updates: 1Executing: SELECT LAST_INSERT_ID()Columns: LAST_INSERT_ID()Row: 11Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession6c3884f5]
2023-11-24 10:53:24.566 ERROR [,,,] 29600 --- [ main] com.example.demo.aop.LogAop : java.lang.RuntimeException: nullat com.example.demo.service.impl.UserService.addUser(UserService.java:24) ~[classes/:na]at com.example.demo.service.impl.UserService$$FastClassBySpringCGLIB$$9c38b50f.invoke(generated) ~[classes/:na]····异常信息打印忽略2023-11-24 10:53:24.566 INFO [,,,] 29600 --- [ main] com.example.demo.aop.LogAop : after
这里仍然正常提交事务说明没有捕获到异常信息
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession6c3884f5]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession6c3884f5]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession6c3884f5]现在是因为aop中没有将异常抛出做了友好化处理将异常处理成了返回了错误码。所以需要在aop处理返回结果之前事务就要捕获到当前事务中抛出的异常并进行回滚或者不提交事务。 我在网上查找资料的时候查找到Order注解Order的作用是定义Spring IOC容器中Bean的执行顺序的优先级这里的顺序也可以理解为存放到容器中的先后顺序所以我给LogAop类加了一个Order注解让LogAOP在最后执行这样Transaction类就可以提前执行捕获异常回滚数据。Order默认为最低优先级因此可以直接设置Order即可
Aspect
Component
Slf4j
Order(10) //定义LogAOP的顺序最后执行,值越高优先级越低
public class LogAop {
·····
}这次再执行一遍查看是否成功回滚事务。 再看下日志事务在aop之前执行完成。
2023-11-24 10:59:04.879 INFO [,,,] 28412 --- [ main] com.example.demo.aop.LogAop : before
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession786e2c5e]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl78854721] will be managed by SpringPreparing: INSERT INTO user ( id,name ) VALUES( ?,? )Parameters: 0(Integer), LISI333(String)Updates: 1Executing: SELECT LAST_INSERT_ID()Columns: LAST_INSERT_ID()Row: 12Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession786e2c5e]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession786e2c5e]
这里关闭了事务并且没有提交操作。
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession786e2c5e]
2023-11-24 10:59:05.271 ERROR [,,,] 28412 --- [ main] com.example.demo.aop.LogAop : java.lang.RuntimeException: nullat com.example.demo.service.impl.UserService.addUser(UserService.java:24) ~[classes/:na]at com.example.demo.service.impl.UserService$$FastClassBySpringCGLIB$$9c38b50f.invoke(generated) ~[classes/:na]
2023-11-24 10:59:05.272 INFO [,,,] 28412 --- [ main] com.example.demo.aop.LogAop : after
使用Order注解可以调整运行级别但是需注意一个问题aop中不要做一些业务操作因为transaction不会捕获到aop中抛出的异常。可以使用try…catch捕获aop中的数据库操作并进行回滚。