@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左右(所以在服务层)。 如果电子邮件失败(可能应该有某种失败的安全,所以它不会失败),那么它应该回滚更改密码和审计?
在决定把@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可以专门用于方法/使用默认(必需)
-
DAO的获取数据的方法(select ..) – 不需要
@Transactional
这可能会导致一些开销,因为事务拦截器/和AOP代理也需要执行。 -
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个模型即Country
和City
。 Country
和City
模型的关系映射就像一个Country
可以有多个城市一样映射就好,
@OneToMany(fetch = FetchType.LAZY, mappedBy="country") private Set<City> cities;
这里国家映射到多个城市, Lazily
提取它们。 因此,当我们从数据库中检索Country对象时,这里是@Transactinal
angular色,那么我们将获取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议是明智地使用这个注释,只在服务层使用。