Java Shiro身份验证领域应该是事务性的吗?

Java Shiro身份验证领域应该是事务性的吗?,java,hibernate,spring-mvc,shiro,Java,Hibernate,Spring Mvc,Shiro,我正在使用Shiro保护我的Spring MVC webapp。我使用Hibernate进行持久化,因此我有一个HibernateALM来获取和填充AuthenticationInfo对象 @Override @Transactional protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { Acco

我正在使用Shiro保护我的Spring MVC webapp。我使用Hibernate进行持久化,因此我有一个HibernateALM来获取和填充AuthenticationInfo对象

@Override
@Transactional
protected AuthenticationInfo doGetAuthenticationInfo(
        AuthenticationToken token) throws AuthenticationException {
    Account account = accountDao.findByUsername((String)token.getPrincipal());

    SimplePrincipalCollection principals = new SimplePrincipalCollection(account, getName());

    SimpleAccount info = new SimpleAccount(principals, account.getPassword());

    return info;
}
Account是我的自定义用户类。我使用DAO按用户名检索帐户。我想知道使用这种@Transactional方法是否有意义。这毕竟是一个只读操作

我还遇到了以下问题:DAO使用sessionFactory.getCurrentSession来获取会话,但是我得到了一个

HibernateException: No Session found for current thread 
当调用该方法时。我的应用程序上下文中有以下内容:

<tx:annotation-driven transaction-manager = "transactionManager" />
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

在内部,Shiro使用上面的realm方法来获取存储的用户名/密码信息。它使用@Autowired DAO检查我的数据库中是否有正确的帐户。然后,它将密码与CredentialsMatcher实现相匹配。

因此您有两个问题。通常最好将这些问题一分为二,因为这些问题并不真正相互关联

找不到当前线程的会话 似乎@Transactional注释不起作用。为了确保您可以在调试模式下运行代码或测试,并在堆栈中查找JdkDynamicAopProxy或类似的东西——如果存在,则通过拦截代理的事务调用您的领域,但我认为目前没有代理。为了让它正常工作,您需要从SpringContext中获取,而不是直接从HibernateAlm获取,而是从这个领域正在实现的接口获取。这是因为内置的标准java库代理只能处理接口。 至于使只读服务方法具有事务性。 这样做有几个正当理由: 因为您使用的是Hibernate,所以实际上很可能使用多个查询来获取Account对象。如果同时修改此帐户,则可能导致状态不一致: 帐户检索的第一个查询 帐户已被修改或删除 帐户检索的第二次查询-此查询将看到修改的结果,这些结果与第一次查询的结果一起可能导致不一致的行为,但如果第一次查询和第二次查询位于具有适当事务隔离级别的同一事务中,则第二次查询将看不到修改。 对数据库的统一访问—当您的所有数据库连接层以相同的方式访问数据库时,这非常有用—我大大简化了应用程序的维护和扩展。 使用一些事务性提示,如@TransactionalreadOnly=true,可以通过适当的配置提高性能,例如,对于负载非常高的应用程序,只读查询可以使用DB服务器的辅助副本。将java.sql.Connection.setReadOnly方法设置为Spring事务的一部分比以其他方式更容易。
所以你有两个问题。通常最好将这些问题一分为二,因为这些问题并不真正相互关联

找不到当前线程的会话 似乎@Transactional注释不起作用。为了确保您可以在调试模式下运行代码或测试,并在堆栈中查找JdkDynamicAopProxy或类似的东西——如果存在,则通过拦截代理的事务调用您的领域,但我认为目前没有代理。为了让它正常工作,您需要从SpringContext中获取,而不是直接从HibernateAlm获取,而是从这个领域正在实现的接口获取。这是因为内置的标准java库代理只能处理接口。 至于使只读服务方法具有事务性。 这样做有几个正当理由: 因为您使用的是Hibernate,所以实际上很可能使用多个查询来获取Account对象。如果同时修改此帐户,则可能导致状态不一致: 帐户检索的第一个查询 帐户已被修改或删除 帐户检索的第二次查询-此查询将看到修改的结果,这些结果与第一次查询的结果一起可能导致不一致的行为,但如果第一次查询和第二次查询位于具有适当事务隔离级别的同一事务中,则第二次查询将看不到修改。 对数据库的统一访问—当您的所有数据库连接层以相同的方式访问数据库时,这非常有用—我大大简化了应用程序的维护和扩展。 使用一些事务性提示,如@TransactionalreadOnly=true,可以通过适当的配置提高性能,例如,对于负载非常高的应用程序,只读查询可以使用DB服务器的辅助副本。将java.sql.Connection.setReadOnly方法设置为Spring事务的一部分比以其他方式更容易。
Spring似乎没有为您的RealmBean创建事务代理。这是我能理解为什么冬眠的唯一原因 会话不可用-因为线程上没有准备好使用的备份基础结构


关于你的问题,如果你想标记它是事务性的,你可以考虑指定@ TraceActualRealDime= Trime

> P>看起来Spring并没有为你的领域bean创建事务代理。这是我能理解为什么Hibernate会话不可用的唯一原因——因为线程上没有准备好使用的备份基础结构


关于你的问题,如果你想标记它是事务性的,你可以考虑指定@ TraceActualRealDime= Trime

> P> Shiro创建它自己的我的领域实例,因此Spring没有能力将它封装在代理中。这就是为什么它不能添加事务行为。

Shiro创建了自己的my Realm实例,因此Spring无权将其封装在代理中。这就是为什么它不能添加事务性行为。

您可以扩展第一点吗。注释在Shiro的AuthenticationRealm抽象类的实现上。我无法解释这一点,那么我如何克服它呢?这只是一个猜测,问题可能出在不同的地方。你能举一个简单的例子,包括Spring、Shiro和Hibernate吗?我现在没有访问它的权限,但它是用于基本登录的。我将添加我能添加的内容作为编辑。你能扩展你的第一点吗。注释在Shiro的AuthenticationRealm抽象类的实现上。我无法解释这一点,那么我如何克服它呢?这只是一个猜测,问题可能出在不同的地方。你能举一个简单的例子,包括Spring、Shiro和Hibernate吗?我现在没有访问它的权限,但它是用于基本登录的。我将添加我可以编辑的内容。为什么对于我的服务层bean,领域bean没有可用的会话?为什么对于我的服务层bean,领域bean没有可用的会话?
@RequestMapping(value = "/account/login", method = RequestMethod.POST)
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
    Subject currentUser = SecurityUtils.getSubject(); 
    if (!currentUser.isAuthenticated) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        currentUser.login(token);
        return "profile";
    } 
    return "home";
}