2011-06-13 51 views
0

在我的应用程序中,我隐藏了接口后面的底层存储对象,允许我随意切换存储。打开简单Pojo数据对象的自动提交?

问题是,当测试休眠似乎Hibernate是非常面向事务。我在这个主题上找到的所有东西(主要是their official docs)都说autocommit不好,应该很少使用。然而,我的整个应用程序并不是围绕Hibernate编写的,它是围绕接口编写的。这意味着从数据库获取数据发生在一个方法中(例如工厂中的getObjects()),而不是事务。

由于我已经抽象出了存储实现,是否autocommit是正确的解决方案?还是有其他选择吗?

+1

打开自动提交并不意味着您不再使用事务。每条语句都会在它自己的事务中运行。 – 2011-06-13 19:40:22

+0

@Vineet也许我可以更好地改写它。我的意思是代码的其他部分应该使用事务来获取数据(beginTransaction(),获取或设置数据,commit()),而不是pojo本身。 – TheLQ 2011-06-13 19:42:51

+0

那么,如果其他部分正在执行数据访问,那么POJO会做什么呢?通过推论,为什么POJO现在应该担心自动提交? – 2011-06-13 19:46:48

回答

1

使用自动提交并不意味着事务不再用于访问数据。它只是意味着每个语句现在都在它自己的事务中执行。在JDBC规范中定义事务开始和终止时的确切实例。为了简洁起见,这通常取决于所执行的声明的性质。

我不确定您的设计是如何实现的,但非事务性系统通常会遇到三个问题。自动提交的使用可能会重新引入一个或多个这些问题。

脏读

考虑您的应用程序中的线程A将读取的实体和更新,但没有提交新的价值。考虑另一个读取同一个实体并看到更新值的线程B.如果线程A要回滚它的更改,或者未能提交更新的值,那么B基本上使用脏值,因为它执行了脏读。

它自己的自动提交不会导致脏读。但是,如果您有一系列最初在单个事务中执行的数据库读写操作,在每次读取/写入操作之后使序列提交,将导致其他事务中的脏读操作,因为当前事务可能会简单地回滚改变。

非可重复读取

在事务的上下文中,读出同一实体(记录)两次在事务的范围内,并看到在第二读取不同的值被认为是一种非可重复阅读。当不同的事务提交了更改并且正在进行的事务读取新值时会发生这种情况。

使用自动提交(或者更确切地说是在两个不同的事务中执行读操作)很可能会导致不可重复的读操作,因为同一个线程中的读操作都将在不同的事务上下文中执行,导致第二次读取看到提交的值(来自不同线程中的事务)。

幻像读

非常相似,不可重复的读取,但并不完全。在这种情况下,执行第二次读取的执行线程将以新记录的形式看到更多数据(而不是更新的数据)。

同样,由于相同的原因,使用自动提交很可能会导致应用程序中的幻像读取。

这些问题还将取决于所使用的数据库事务隔离级别,但最终在使用ORM框架时,标记事务的开始和结束将留给应用程序开发人员。虽然单个读写操作可能会被数据库彼此隔离,但开发人员需要确保工作在事务环境中进行。使用自动提交会更改每个操作的事务上下文。

TLDR

使用自动提交时进行交易活动将意味着这是不可能的“业务事务上下文”期间执行回滚到安全状态,在发生故障的事件。另外,正是由于这个原因,在JDBC中执行批量更新时,应该禁用自动提交。当真正的需求是在批处理结束时提交时,使用自动提交将强制为批处理中的每个更新执行提交。

我建议您阅读本书Java Transaction Design Strategies(以免费电子书形式提供),以深入了解使用交易。

+0

前两个看起来像是基本的多线程同步问题。请注意,我的应用程序主要是一个大型事件侦听器系统,所有侦听器都在不同的线程中。如果没有将Hibernate深入集成到我的应用程序中,我会看到两个选择:1)在每个Listener执行并关闭后缀之前启动一个事务(实际上可能)或者2)使用Autocommit,并且只是说这些是难以解决的基本同步问题与我的应用程序设计。这些看起来都是可行的选择? – TheLQ 2011-06-13 21:15:44

+0

@TheLQ,您的选项(1)与我上面的评论一致:“通常,在访问任何事务资源之前,您将在业务逻辑的入口点开始事务,并在该上下文中执行所有事务活动。”就选项(2)而言,这取决于每个Listener所做的工作。使用自动提交功能时,问题更多的是恢复数据丢失以回滚。一次更新会成功,但另一次更新可能会失败,让您在数据库中进行清理工作。 – 2011-06-13 21:19:53

+0

虽然(1)虽然遇到与您在Autocommit中发表的文章中所述的相同的同步问题?数据对象都是共享的(它很难解释如何和为什么,甚至更难以重写程序,因此不会共享)作为共享资源,所以我看到了上面列出的所有问题。 – TheLQ 2011-06-13 22:19:53

0

确实有一个属性'hibernate.connection.autocommit',您可以在您的休眠配置XML中或编程方式将您的SessionFactory设置为true。

从您的问题中可以看出,只要开始并在您的Hibernate实施的getObjects()接口方法中提交事务,您真的会获得什么好处。

+0

这不就是autocommit本质上做什么吗? – TheLQ 2011-06-13 20:02:27

+0

这取决于你的界面方法是什么以及它们做了​​多少。如果一个方法需要一堆对象并且可能涉及到更新多个表,那么如果某个方法失败,您可能希望能够将其返回。 – Affe 2011-06-13 20:15:31

+0

所以我应该在大多数领域自动提交罚款,但写我自己的交易的关系字段(多对多+ OneToMany + ManyToOne + OneToOne关系)? – TheLQ 2011-06-13 20:48:01