@Transactional注释属于哪里?

如果将@Transactional放置在DAO类和/或它们的方法中,还是最好使用DAO对象来注释正在调用的Service类? 或者是否有意义的注释这两个“层”?

我认为交易属于服务层。 这是知道工作单位和用例的人。 如果您将多个DAO注入到需要在单个事务中协同工作的服务中,这是正确的答案。

总的来说,我同意其他人的观点,即交易通常是从服务级别开始的(取决于您当然要求的粒度)。

然而,同时我也开始向我的DAO层(以及其他不允许启动事务但是需要现有事务的层@Transactional(propagation = Propagation.MANDATORY)添加@Transactional(propagation = Propagation.MANDATORY) ,因为它更容易检测到错误忘记在呼叫者(例如服务)中开始交易。 如果您的DAO注释为强制传播,则会在调用该方法时得到一个exception,指出没有活动事务。

我也有一个集成testing,在这个批注中检查所有bean(bean post processor),并且如果在一个不属于服务层的bean中有一个传播(Mandatory)以外的传播的@Transactional注解,则失败。 这样我确保我们不会在错误的层上启动事务。

事务注释应该放在所有不可分割的操作周围。

例如,您的电话是“更改密码”。 这包括两个操作

  1. 更改密码。
  2. 审核更改。
  3. 通过电子邮件发送密码已更改的客户端。

所以在上面,如果审计失败,那么密码更改是否也会失败? 如果是这样,那么交易应该是1和2左右(所以在服务层)。 如果电子邮件失败(可能应该有某种失败的安全,所以它不会失败),那么它应该回滚更改密码和审计?

在决定把@Transactional放在哪里的时候,这些是你需要问的问题。

传统Spring架构的正确答案是将事务语义放在服务类上,这是因为其他人已经描述的原因。

Spring的一个新兴趋势是向领域驱动的devise。 Spring Roo很好地说明了这一趋势。 这个想法是使域对象POJO比典型的Spring架构(通常是贫乏的)要丰富得多,特别是把事务和持久性语义放在域对象本身上。 在所需要的只是简单的CRUD操作的情况下,Web控制器直接在域对象POJO上运行(它们在这种情况下作为实体运行),并且没有服务层。 在域对象之间需要某种协调的情况下,可以有一个服务bean句柄,按照传统使用@Transaction。 您可以将域对象上的事务传播设置为REQUIRED,以便域对象使用任何现有的事务,例如在服务bean上启动的事务。

从技术上讲,这个技术使用了AspectJ和<context:spring-configured /> 。 Roo使用AspectJ inter-type定义来将实体语义(事务和持久性)从域对象的东西(基本上是字段和业务方法)中分离出来。

正常的情况是在服务层级注释,但是这取决于你的要求。

在服务层上注释将导致比DAO级别注释更长的事务。 根据事务隔离级别,你可能会遇到问题,因为并发事务不会看到彼此的变化,例如。 可重复阅读。

注释DAO将尽可能缩短事务处理时间,缺点是服务层所暴露的function不能在单个(可回滚)事务中完成。

如果传播模式设置为默认值,则注释这两个层都没有意义。

我将@Transactional放置在@Service层上,并设置“rollbackFor”任何exception和“readOnly”来进一步优化事务。

默认情况下@Transactional只会查找RuntimeException (Unchecked Exceptions),通过设置回滚到Exception.class (Checked Exceptions),它将回滚任何exception。

 @Transactional(readOnly = false, rollbackFor=Exception.class) 

检查与未检查exception: http : //www.javapractices.com/topic/TopicAction.do? Id=129

或者是否有意义的注释这两个“层”? – 注释服务层和dao层是否有意义 – 如果要确保dao方法总是从dao中的传播“mandatory”的服务层调用(传播)。 这会为从UI层(或多个控制器)调用dao方法提供一些限制。 另外 – 当unit testingDao层在特定的时候 – 具有dao注释也将确保它被testing的事务function。

另外,Springbuild议只使用具体类的注解而不使用接口。

http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

通常,应该在服务层上进行交易。

但如前所述,操作的primefaces性告诉我们注释是必要的。 因此,如果你使用像Hibernate这样的框架,对一个对象的单个“保存/更新/删除/ …修改”操作有可能修改几个表中的几行(由于对象图的级联),当然,这个特定的DAO方法也应该有事务pipe理。

对于数据库级别的事务

主要是我在方法级别使用了DAO中的@Transactional ,所以configuration可以专门用于方法/使用默认(必需)

  1. DAO的获取数据的方法(select ..) – 不需要@Transactional这可能会导致一些开销,因为事务拦截器/和AOP代理也需要执行。

  2. DAO的插入/更新的方法将得到@Transactional

非常好的博客上transctional

对于应用级别 –
我正在使用业务逻辑的事务我希望能够在意外错误的情况下回滚

 @Transactional(rollbackFor={MyApplicationException.class}) public void myMethod(){ try { //service logic here } catch(Throwable e) { log.error(e) throw new MyApplicationException(..); } } 

把它放在服务层上更好! 我在昨天遇到的一篇文章中清楚地解释了这一点。 这里是你可以检查的链接 !

@Transactional注解应该放在所有不可分割的操作中。 使用@Transactional事务传播是自动处理的。在这种情况下,如果通过当前方法调用另一个方法,那么该方法将可以selectjoin正在进行的事务。

所以我们举个例子:

我们有2个模型即CountryCityCountryCity模型的关系映射就像一个Country可以有多个城市一样映射就好,

 @OneToMany(fetch = FetchType.LAZY, mappedBy="country") private Set<City> cities; 

这里国家映射到多个城市, Lazily提取它们。 因此,当我们从数据库中检索Country对象时,这里是@Transactinalangular色,那么我们将获取Country对象的所有数据,但是不会得到Set of cities,因为我们正在提取城市LAZILY

 //Without @Transactional public Country getCountry(){ Country country = countryRepository.getCountry(); //After getting Country Object connection between countryRepository and database is Closed } 

当我们想从国家对象访问Set of Cities时,我们将在该Set中获得空值,因为Set的对象只创build了这个Set,并没有初始化那里的数据来得到Set的值我们使用@Transactional即,

 //with @Transactional @Transactional public Country getCountry(){ Country country = countryRepository.getCountry(); //below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal Object object = country.getCities().size(); } 

所以基本上@Transactional是Service可以在单个事务中进行多次调用而不会closures与终点的连接。

理想情况下,服务层(经理)代表您的业务逻辑,因此它应该用@Transactional注释。服务层可能调用不同的DAO来执行数据库操作。 让我们假设你有一个服务方法中有多less个DAO操作的情况。 如果您的第一个DAO操作失败,其他人可能仍然通过,并且最终会导致DB状态不一致。 注释服务层可以让您免于这种情况。

首先让我们来定义我们要使用交易的地方

我认为正确的答案是 – 当我们需要确保一系列的行动将作为一个primefaces操作一起完成,或者即使其中一个操作失败也不会做出改变。

将业务逻辑放入服务中是众所周知的做法。 所以服务方法可能包含不同的操作,这些操作必须作为一个单一的逻辑工作单元执行。 如果是这样 – 那么这种方法必须标记为Transactional 。 当然,并不是每种方法都需要这样的限制,所以你不需要把整个服务标记为事务性的

甚至更多 – 不要忘记考虑@交易显然可能会降低方法的性能。 为了看到整个图片,你必须知道事务隔离级别。 知道这可能会帮助您避免使用@Transactional ,这不一定需要。

我更喜欢在方法级别的服务层上使用@Transactional

@Transactional用于通过控制层( @Controller )调用的服务层,服务层调用DAO层( @Repository )即数据库相关的操作。

服务层是添加@Transactional注释的最佳位置,因为这里存在的大部分业务逻辑都包含详细级别的用例行为。

假设我们将其添加到DAO,并从服务调用2个DAO类,一个失败和其他成功,在这种情况下,如果@Transactional不服务一个数据库将提交和其他将回滚。

因此,我的build议是明智地使用这个注释,只在服务层使用。

https://github.com/VishalTambe/java-algos/