leftso 1244 0 2021-01-13 09:34:21

文章位置:左搜> 编程技术> Java编程技术> 正文

出现@Transactional事务不生效原因

shiro 的Realm 中注入了用到事务的service,例如下面的

​
/**
 * 自定义权限认证器
 * 自定义实现Realm,实现自定义获取登录信息进行登录鉴权和获取权限信息进行权限鉴权
 */
public class UserRealm extends AuthorizingRealm {
    //超管账号
    @Value("${super.user}")
    String su;
    
    
    @Autowired
    SystemUserService systemUserService;
​
   
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       // TODO CODE ...
        return info;
    }
​
    /***
     * 登录鉴定(就是鉴定用户是否登录)
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       // TODO CODE ...
        return info;
    }
}
​

按上方代码使用,SystemUserService 这个service中所有的事务都将不会生效。

原因细节

  1. 首先我们在项目整合Shiro的时候通过ShiroConfig做了一些配置,其中一项包括Shiro的授权认证器MemberAuthorizingRealm。

  2. 在UserRealm中我们通过@Autowired注入了本篇的主角SystemUserService。

  3. Spring启动的时候,配置相关的都是优先初始化的,在初始化UserRealm的时候发现需要注入一个SystemUserService对象,容器里肯定是没有的,那么就提前将其初始化了。此时如果在MemberService还有通过@Autowired注入的其他依赖,那么会一并初始化,依赖中要是还有依赖会继续递归初始化,这样下来会导致一系列的实例都是没有被代理的。

  4. 但是这时候Spring中创建代理的处理器是还没有的,导致SystemUserService的BeanPostProcessor中没有AbstractAutoProxyCreator这个对象,后面整个BeanPostProcessor列表执行的时候没有为其创建代理。

  5. Spring中的数据库事务都是需要代理支持的,所以MemberService中不能开启事务。

 

解决办法

方法一(推荐):

Realm中注入的service上面添加@Lazy注解

/**
 * 自定义权限认证器
 * 自定义实现Realm,实现自定义获取登录信息进行登录鉴权和获取权限信息进行权限鉴权
 */
public class UserRealm extends AuthorizingRealm {
    //超管账号
    @Value("${super.user}")
    String su;
    
    @Lazy
    @Autowired
    SystemUserService systemUserService;
​
   
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       // TODO CODE ...
        return info;
    }
​
    /***
     * 登录鉴定(就是鉴定用户是否登录)
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       // TODO CODE ...
        return info;
    }
}

 

方法二:

单独创建一个service直接和mapper打交道,然后注入到Realm

 

方法三:

通过spring application getBean获取 service

评论区域

暂无评论,快来抢首发吧!!!