Java Spring 管理的事务没有 @Transactional 注释

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21311933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:59:31  来源:igfitidea点击:

Spring managed transactions without @Transactional annotation

javaspringhibernatetransactions

提问by Jukka H?m?l?inen

I'm using Spring annotations to manage my transactions like so:

我正在使用 Spring 注释来管理我的事务,如下所示:

@Transactional(readOnly = true)
public class AlertServiceImpl implements AlertService {

     private AlertDAO alertDAO;

     public List<Alert> getAlerts(){
         List<Alert> alerts = alertDAO.getAlerts();
         return alerts;
     }

}

I'm wondering what happens if I forget the annotation:

我想知道如果我忘记了注释会发生什么:

// Oops! Forgot to use transactional annotation 
public class AlertServiceImpl implements AlertService {

    private AlertDAO alertDAO;

    public List<Alert> getAlerts(){
         List<Alert> alerts = alertDAO.getAlerts();
         return alerts;
    }

}

When the alertDAO implementation is following:

当 alertDAO 实现如下:

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

// no annotation here either
public class HibernateAlertDAO extends HibernateDaoSupport implements AlertDAO {

    public List<Alert> getAlerts(){
         // some implementation details that define queryString

         Query query = getSession().createQuery(queryString);
         List<Alert> alerts = query.list();

         return alerts;
    }

}

It seems like Hibernate allows me to fetch data from database even without the annotation.

即使没有注释,Hibernate 似乎也允许我从数据库中获取数据。

What are the consequences of this kind of carelessness and what are the worst case scenarios that could happen?

这种粗心大意的后果是什么,可能发生的最坏情况是什么?

采纳答案by Al Sweetman

According to the documentation (Spring docs) it's just metadata to give an indication that the method or interface can be configured by something that is 'transactionally aware' (i.e. <tx:annotation-driven/>).

根据文档(Spring docs),它只是元数据,表明可以通过“事务感知”(即<tx:annotation-driven/>)的东西来配置方法或接口。

With just tx:annotation-drivenand no @Transactionalattribute I believe you get the "default" transactionality applied:

仅使用tx:annotation-driven而没有@Transactional属性,我相信您会应用“默认”事务性:

  • Propagation setting is REQUIRED.
  • Isolation level is DEFAULT.
  • Transaction is read/write.
  • Transaction timeout defaults to the default timeout of the underlying transaction system, or none if timeouts are not supported.
  • any RuntimeExceptiontriggers rollback, and any checked Exceptiondoes not.
  • 传播设置是必需的
  • 隔离级别为DEFAULT
  • 事务是读/写的。
  • 事务超时默认为底层事务系统的默认超时,如果不支持超时,则无。
  • 任何RuntimeException 都会触发回滚,而任何已检查的Exception都不会。

Assuming you're using the <tx:annotation-driven />to drive it via a transaction manager then missing out the @Transactionalattribute means you can't apply such properties as readOnly, isolation, propagation, rollbackFor, noRollbackForetc.

假设您<tx:annotation-driven />通过事务管理器使用来驱动它,然后错过该@Transactional属性意味着您无法应用诸如readOnlyisolationpropagationrollbackFornoRollbackFor属性

I believe that MVC is slightly different - the Hibernate session is tied directly to the MVC request - i.e. when the request is received the transaction starts.

我相信 MVC 略有不同 - Hibernate 会话直接绑定到 MVC 请求 - 即当收到请求时,事务开始。

Back to your example, the code for getSession() in HibernateDAOSupport is as follows:

回到你的例子,HibernateDAOSupport中getSession()的代码如下:

protected final Session getSession()
    throws DataAccessResourceFailureException, IllegalStateException 
{
    return getSession(this.hibernateTemplate.isAllowCreate());
}

Which in turn calls to:

这反过来又要求:

/**
 * Obtain a Hibernate Session, either from the current transaction or
 * a new one. The latter is only allowed if "allowCreate" is true.
 *.......
 */
protected final Session getSession()
    throws DataAccessResourceFailureException, IllegalStateException {
    return getSession(this.hibernateTemplate.isAllowCreate());
}

which ultimately calls to :

最终要求:

/** 
 * ....
 * @param allowCreate whether a non-transactional Session should be created
 * when no transactional Session can be found for the current thread
 * ....
 */
private static Session doGetSession(
    SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)

Fundamentally, a Transaction:Session is tied 1:1 AFAIK, and the only way to run without a transaction is by using say JBoss which has a 'baked in' persistence layer which provides the transactionality for you (under the covers). Even if you call getQuery()after getSession()you still effectively have a transaction occurring as it's a JDBC/Hibernate connection.

从根本上讲,事务:会话是 1:1 AFAIK 绑定的,没有事务运行的唯一方法是使用 JBoss,它具有“烘焙”持久层,为您提供事务性(在幕后)。即使您在调用getQuery()getSession()仍然有效地进行了事务,因为它是 JDBC/Hibernate 连接。

回答by Mohemmed Bilal Ilyas

Nothing would happen if you not put the @transactional Annotation Basically @Transactional is not mandatory to put on the top of method signature it is just use to inform compiler when your transactional is read only=true (only for the data retrieval purpose) and when it is read only=false(only for the insert update delete operations)

如果您不放置@transactional 注释,则不会发生任何事情基本上@Transactional 不是强制放置在方法签名的顶部,它只是用于通知编译器何时您的事务为只读=真(仅用于数据检索目的)以及何时它是只读=假(仅用于插入更新删除操作)

回答by pfernandom

Without the annotation, you lose the advantages of the transactions like the rollbacks.

如果没有注释,您将失去回滚等事务的优势。

With the @Transactional annotation you are doing more than one database operation, like many inserts and one fails, all the operations in the transaction can rollback to give consistency to your data.

使用@Transactional 注释,您正在执行多个数据库操作,例如多次插入和一次失败,事务中的所有操作都可以回滚以确保数据的一致性。

That is also why it's recommended to put the annotation in the services not in the DAOs.

这也是为什么建议将注释放在服务中而不是在 DAO 中的原因。

回答by hoaz

In your scenario your DAO will execute without transaction, most probably with auto-commit.

在您的场景中,您的 DAO 将在没有事务的情况下执行,最有可能使用自动提交。

If you want to avoid this kind of mistake in future and require all your services to run in transaction you can protect DAO layer with following @Transactionalannotation:

如果你想在未来避免这种错误并要求你的所有服务在事务中运行,你可以使用以下@Transactional注释保护 DAO 层:

@Transactional(propagation = MANDATORY)
public class HibernateAlertDAO extends HibernateDaoSupport implements AlertDAO {
   ...
}

This annotation will require service layer to declare transaction and will throw exception otherwise.

这个注解需要服务层声明事务,否则会抛出异常。