Java 一个 Hibernate Session 中可以有多个事务吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25893476/
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
Can you have multiple transactions within one Hibernate Session?
提问by Paul Taylor
Can you have multiple transactions within one Hibernate Session?
一个 Hibernate Session 中可以有多个事务吗?
I'm unclear if this is an allowable desirable. In my code I have a long running thread and takes items from a Blocking Queue, depending on what is on the queue, it may need to create and save a hibernate object, or it may not need to do anything.
我不清楚这是否是可取的。在我的代码中,我有一个长时间运行的线程并从阻塞队列中获取项目,这取决于队列中的内容,它可能需要创建并保存一个休眠对象,或者它可能不需要执行任何操作。
Each item is distinct so if item 1 is saved and item 2 fails to save whatever reason I don't want to that to prevent item 1 being added to the database.
每个项目都是不同的,所以如果项目 1 被保存而项目 2 未能保存我不想阻止项目 1 被添加到数据库的任何原因。
So the simplest way to do this is for each item that needs to be created to create a new session, open transaction, save new object, commit transaction, close session
所以最简单的方法是为每个需要创建的项目创建一个新会话,打开事务,保存新对象,提交事务,关闭会话
However, that means a new session is created for each item, which seems to go against Hibernates own recommendations to not do Session Per Request Pattern. So my alternative was to create one session in the thread, then just open and commit a new transaction as required when needed to create a new object. But I've seen no examples of this approach and I'm unsure if it actually works.
然而,这意味着为每个项目创建一个新会话,这似乎违背了 Hibernates 自己的建议,即不执行 Session Per Request 模式。所以我的替代方法是在线程中创建一个会话,然后在需要创建新对象时根据需要打开并提交一个新事务。但是我没有看到这种方法的例子,我不确定它是否真的有效。
采纳答案by Vlad Mihalcea
The session-per-request pattern uses one JDBC connection per session if you run local transactions. For JTA, the connections are aggressively released after each statement only to be reacquired for the next statement.
如果您运行本地事务,则每次请求会话模式为每个会话使用一个 JDBC 连接。对于 JTA,在每个语句之后主动释放连接,只是为了下一个语句重新获取。
The Hibernate transaction API delegates the begin/commit/rollback to the JDBC Connection for local transactions and to the associated UserTransaction for JTA. Therefore, you can run multiple transactions on the same Hibernate Session, but there's a catch. Once an exception is thrown you can no longer reuse that Session.
在Hibernate事务API代表了开始/提交/回滚到JDBC连接本地交易,并为JTA相关的UserTransaction。因此,您可以在同一个 Hibernate Session 上运行多个事务,但有一个问题。一旦抛出异常,您就不能再重用该会话。
My advice is to divide-and-conquer. Just split all items, construct a Command object for each of those and send them to an ExecutorService#invokeAll
. Use the returned List to iterate and call Future#get()
to make sure the original thread waits after all batch jobs to complete.
我的建议是分而治之。只需拆分所有项目,为每个项目构建一个 Command 对象并将它们发送到ExecutorService#invokeAll
. 使用返回的 List 进行迭代和调用Future#get()
以确保原始线程在所有批处理作业完成后等待。
The ExecutorService
will make sure you run all Commands concurrently and each Command should use a Service that uses its own @Transaction
. Because transactions are thread-bound you will have all batch jobs run in isolation.
这ExecutorService
将确保您同时运行所有命令,并且每个命令都应该使用一个使用自己的@Transaction
. 因为事务是线程绑定的,所以所有批处理作业都将独立运行。
回答by faisalbhagat
From hibernates documentation
来自休眠文档
"A Session is an inexpensive, non-threadsafe object that should be used once and then discarded for: a single request, a conversation or a single unit of work. A Session will not obtain a JDBC Connection, or a Datasource, unless it is needed. It will not consume any resources until used."
“会话是一个廉价的、非线程安全的对象,应该被使用一次然后被丢弃:单个请求、对话或单个工作单元。会话不会获得 JDBC 连接或数据源,除非它是需要。它在使用之前不会消耗任何资源。”
so if you are creating sessions again and again it will not burden the system much. If you are continuing a session for too long it may create problems as session is not thread safe .In my opinion you simplest solution is the best "So the simplest way to do this is for each item that needs to be created to create a new session, open transaction, save new object, commit transaction, close session"
所以如果你一次又一次地创建会话,它不会给系统带来太多负担。如果您继续会话时间过长,可能会产生问题,因为会话不是线程安全的。在我看来,您最简单的解决方案是最好的“因此,最简单的方法是为需要创建的每个项目创建一个新的会话、打开事务、保存新对象、提交事务、关闭会话”
By the way if you are creating single record of anything you dont need transaction too much. creating single record is inherently " all or none" thing for which we use transaction
顺便说一句,如果您要创建任何内容的单一记录,则不需要太多交易。创建单个记录本质上是我们使用事务的“全部或无”事物
回答by Vinay
Short answer is yes, you can use same session for transaction. Take a look at org.hibernate.Transaction., it has required method to manage transaction.
简短的回答是肯定的,您可以使用相同的会话进行交易。看看org.hibernate.Transaction.,它有管理事务的必需方法。
回答by Serge Ballesta
Obviously, you can. A hibernate session is more or less a database connection and a cache for database objects. And you can have multiple successive transactions in a single database connection. More, when you use a connection pool, the connection is not closed but is recycled.
显然,你可以。休眠会话或多或少是数据库连接和数据库对象的缓存。并且您可以在单个数据库连接中拥有多个连续的事务。更多的是,当你使用连接池时,连接不是关闭而是被回收。
Whether you should or not is a matter of reusing objects from session. If there is a good chance but you can reuse objects that a preceding transaction has put in session, you should keep one single session for multiple transactions. But if once an object has been committed, it will never be re-used, it is certainly better to close the session and re-open a new one, or simply clear it.
您是否应该重用会话中的对象。如果有很好的机会但您可以重用前一个事务放入会话中的对象,则应该为多个事务保留一个会话。但是如果一个对象一旦被提交,它就永远不会被重用,最好关闭会话并重新打开一个新的,或者干脆清除它。
How to do it :
怎么做 :
If you have a Session object, you create transactions with :
如果您有一个 Session 对象,您可以使用以下命令创建交易:
Transaction transaction;
transaction = session.beginTransaction();
... (operations in the context of transaction)
transaction.commit();
... (other commands outside of any transaction)
transaction = session.beginTransaction();
... (and so on and so forth ...)
回答by Faizan Mohammad
package hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
class Tester {
public static void main(String[] args) {
SessionFactory sf = new org.hibernate.cfg.Configuration().configure().buildSessionFactory(new StandardServiceRegistryBuilder().configure().build());
Session session = sf.openSession();
session.beginTransaction();
Student student = new Student();
student.setName("Mohammad Faizan");
student.setRollNo(1309114040);
session.save(student);
session.getTransaction().commit();
session.getTransaction().begin();
session.load(Student.class,23);
student.setName("New Name");
student.setRollNo(123);
session.update(student);
session.getTransaction().commit();
session.close();
}
}