Java 你需要一个数据库事务来读取数据吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26327274/
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-11 02:14:26  来源:igfitidea点击:

Do you need a database transaction for reading data?

javaspringhibernatejdbctransactions

提问by mmm

When I try to read data from the database, at least using

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

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

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

an exception is throws saying that a transaction is not present.

抛出异常表示事务不存在。

When I add the annotation:

当我添加注释时:

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

it works fine.

它工作正常。

However, since reading will happen million of times per second to access and read data, I want to make sure that our environment is not clogged up unnecessarily.

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

If not, what is the cost of creating a read-only Propagation.Supportstransaction?

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

Can I not create a Hibernate Criteria Query without a transaction, in combination with Spring?

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

采纳答案by Vlad Mihalcea

All database statements are executed within the context of a physical transaction, even when we don't explicitly declare transaction boundaries(BEGIN/COMMIT/ROLLBACK).

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

If you don't declare transaction boundaries, then each statement will have to be executed in a separate transaction (autocommitmode). This may even lead to opening and closing one connection per statement unless your environment can deal with connection-per-thread binding.

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

Declaring a service as @Transactionalwill give you one connection for the whole transaction duration, and all statements will use that single isolation connection. This is way better than not using explicit transactions in the first place.

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

On large applications, you may have many concurrent requests, and reducing database connection acquisition request ratewill definitely improve your overall application performance.

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

JPA doesn't enforce transactions on read operations. Only writes end up throwing a transaction required exception in case you forget to start a transactional context. Nevertheless, it's always better to declare transaction boundaries even for read-only transactions (in Spring @Transactionalallows you to mark read-only transactions, which has a great performance benefit).

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

Now, if you use declarative transaction boundaries (e.g. @Transactional), you need to make sure that the database connection acquisition is delayed until there is a JDBC statement to be executed. In JTA, this is the default behavior. When using RESOURCE_LOCAL, you need to set the hibernate.connection.provider_disables_autocommitconfiguration property and make sure that the underlying connection pool is set to disable the auto-commit mode.

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

回答by vdenotaris

Accoring to my experience with JPAimplementation in J2EE, a Transaction manageris always needed in order to perform CRUDoperation safety, by guaranteeing a rollback in order to preserve data integrity.

Accoring我有经验JPA实施J2EE,一个事务管理器始终是必要的,以执行CRUD操作的安全性,通过保证回滚,以保持数据的完整性。

Enterprise applications use different resources to save data and send messages like a database or message queue. If we want to query these resources sequentially and to cancel the whole operation once a problem occurs, we have to put this query in a unit of work so that will be executed as a whole.

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

You could define it:

你可以定义它:

  • by using related annotations (as shown in the questions); in this way, the container loads automatically the transaction manager for a given persistence context;

  • by injecting manually the transaction manager, as follows:

    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();
        }
    
        // ...
    
    }
    
  • 通过使用相关的注释(如问题所示);通过这种方式,容器会自动为给定的持久化上下文加载事务管理器;

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

    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, as JPA-spec implementation, may follow the same approach.

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

You could find more information by reading the following article: Java_Persistence/Transactions.

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