是否需要数据库事务来读取数据?

Do you need a database transaction for reading data?

提问人:mjs 提问时间:10/13/2014 最后编辑:Vlad Mihalceamjs 更新时间:1/9/2021 访问量:49393

问:

当我尝试从数据库中读取数据时,至少使用

((Session)em.getDelegate()).createCriteria()

抛出一个异常,指出事务不存在。

当我添加注释时:

@Transactional(
    value = SomeClass.TRANSACTIONAL_MANAGER, 
    propagation = Propagation.SUPPORTS, 
    readOnly = true
)

它工作正常。

但是,由于读取数据时每秒将发生数百万次访问和读取数据,因此我想确保我们的环境不会被不必要地堵塞。

如果不是,创建只读 Propagation.Supports 事务的成本是多少?

我不能在没有事务的情况下与 Spring 结合创建 Hibernate Criteria Query 吗?

Java Spring 休眠 JDBC 事务

评论

0赞 OO7 10/13/2014
可能重复 stackoverflow.com/questions/3713829/select-using-hibernate
0赞 mjs 11/18/2014
是的。我不小心评论了错误的帖子。你现在应该看到我的评论。但我已经接受了。

答:

198赞 Vlad Mihalcea 10/13/2014 #1

所有数据库语句都是在物理事务的上下文中执行的,即使我们没有显式声明事务边界 (BEGIN/COMMIT/ROLLBACK)。

如果不声明事务边界,则必须在单独的事务(模式)中执行每个语句。这甚至可能导致每个语句打开和关闭一个连接,除非您的环境可以处理每个线程的连接绑定。autocommit

声明一个服务将在整个事务持续时间内为您提供一个连接,并且所有语句都将使用该单个隔离连接。这比一开始就不使用显式事务要好得多。@Transactional

在大型应用程序上,您可能有很多并发请求,降低数据库连接获取请求率肯定会提高您的整体应用程序性能。

JPA 不会在读取操作时强制执行事务。只有写入最终会抛出 TransactionRequiredException,以防忘记启动事务上下文。尽管如此,即使对于只读事务,声明事务边界总是更好的(在 Spring 中允许您标记只读事务,这具有很大的性能优势)。@Transactional

现在,如果使用声明性事务边界(例如 ),则需要确保数据库连接获取延迟,直到有要执行的 JDBC 语句。在 JTA 中,这是默认行为。使用 RESOURCE_LOCAL 时,需要设置 hibernate.connection.provider_disables_autocommit 配置属性,并确保底层连接池设置为禁用自动提交模式。@Transactional

评论

1赞 mjs 11/18/2014
看这个: ibm.com/developerworks/library/j-ts1 它说:“更好的是,在执行读取操作时完全避免使用@Transactional注解,如清单 10 所示:” ..所以我得到的印象是不需要一个。考虑到它是关于执行读取 sql 语句的,我认为不需要开销
5赞 Vlad Mihalcea 1/31/2015
其他系统将自动提交模式用于非常只读的单语句事务。当每个逻辑事务(您的服务方法)有多个语句时,问题就来了。
1赞 rgielen 11/29/2017
连接开销是一回事,但更重要的是 ACID 中的 D-guarantee - 带有提交 - 即在自动提交模式下的每个语句之后!- 数据库必须保证您的更改到达磁盘(而不仅仅是磁盘缓存!在打开的事务中,对已读取的数据库块的操作仅在 DMBS 内存中执行,直到执行提交。顺便说一句,回滚是扔掉脏内存块的简单过程,几乎不需要任何成本。
4赞 Vlad Mihalcea 11/29/2017
数据库仅在提交后同步重做日志,而不是在检查点期间刷新的整个缓冲池。回滚不一定是免费的。在 Oracle 和 MySQL 上,元组需要从回滚段重建。此外,指数必须重新平衡。
5赞 Vlad Mihalcea 11/29/2017
您始终将事务与 RDBMS 一起使用,即使在自动提交模式下,当您没有显式声明它们时也是如此。自动提交使用默认隔离级别,并将语句包装在一个事务中。
4赞 vdenotaris 10/13/2014 #2

根据我在 J2EE 中实现 JPA 的经验,为了执行 CRUD 操作安全,总是需要一个事务管理器,通过保证回滚以保持数据完整性。

企业应用程序使用不同的资源来保存数据并发送消息,就像数据库或消息队列一样。如果我们想按顺序查询这些资源并在出现问题时取消整个操作,我们必须将此查询放在一个工作单元中,以便作为一个整体执行。

您可以定义它:

  • 通过使用相关的注释(如问题所示);这样,容器会自动加载给定持久性上下文的事务管理器;

  • 通过手动注入事务管理器,如下所示:

    public class sample {
    
        @PersistenceContext
        EntityManager em;
    
        // Injected transaction manager
        @Inject
        UserTransaction utx;
    
        private static final String[] GAME_TITLES = {
            "Super Mario Brothers",
            "Mario Kart",
            "F-Zero"
        };
    
        private void clearData() throws Exception {
            utx.begin();
            em.joinTransaction();
            System.out.println("Dumping old records...");
            em.createQuery("delete from Game").executeUpdate();
            utx.commit();
        }
    
        private void insertData() throws Exception {
            utx.begin();
            em.joinTransaction();
            System.out.println("Inserting records...");
            for (String title : GAME_TITLES) {
                Game game = new Game(title);
                em.persist(game);
            }
            utx.commit();
            // clear the persistence context (first-level cache)
            em.clear();
        }
    
        // ...
    
    }
    

Spring Data 作为 JPA 规范的实现,可能遵循相同的方法。

您可以通过阅读以下文章找到更多信息:Java_Persistence/交易

评论

0赞 Simon Logic 7/5/2023
最初的背景是读取数据。