2014-01-23 51 views
13

我使用Spring注解来管理,像这样我的交易:Spring的事务管理,而不@Transactional注解

@Transactional(readOnly = true) 
public class AlertServiceImpl implements AlertService { 

    private AlertDAO alertDAO; 

    public List<Alert> getAlerts(){ 
     List<Alert> alerts = alertDAO.getAlerts(); 
     return alerts; 
    } 

} 

我想知道如果我忘了注解会发生什么:

// Oops! Forgot to use transactional annotation 
public class AlertServiceImpl implements AlertService { 

    private AlertDAO alertDAO; 

    public List<Alert> getAlerts(){ 
     List<Alert> alerts = alertDAO.getAlerts(); 
     return alerts; 
    } 

} 

当alertDAO的实现如下:

import org.springframework.orm.hibernate3.support.HibernateDaoSupport; 

// no annotation here either 
public class HibernateAlertDAO extends HibernateDaoSupport implements AlertDAO { 

    public List<Alert> getAlerts(){ 
     // some implementation details that define queryString 

     Query query = getSession().createQuery(queryString); 
     List<Alert> alerts = query.list(); 

     return alerts; 
    } 

} 

好像Hibernate允许我获取数据从数据库甚至没有注释。

这种粗心大意的后果是什么?最糟糕的情况是什么?

+1

关于你的问题,你可以得到一个会话流失,即会话被打开,但由于没有事务边界(春天用于打开/关闭会话)而没有关闭。你的dao有缺陷,你不应该在'HibernateDaoSupport'类上调用'getSession'(这会打开一个非托管的会话)。 (在2006年的某个地方,HibernateTemplate和HibernateDaoSupport必须被认为是弃用的!)。请参阅http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html#orm-hibernate-straight。 –

+1

默认情况下,事务边界不是在服务调用返回的地方,还是服务线程(在webapp的情况下)返回MVC请求的地方?如果这是一个非网络应用场景,那么是的,会话流失是一个大问题。然而,因为它总是调用getSession(),它会返回当前会话,如果它存在不是吗?因为它存储在线程本地? –

+0

@ M.Deinum你能提供类似问题的输入http://stackoverflow.com/questions/42831749/hibernate-session-with-spring-transaction? – emilly

回答

7

根据文档(Spring docs),它只是元数据,表明该方法或接口可以通过“事务性意识”(即<tx:annotation-driven/>)进行配置。

只需TX:注释驱动没有@Transactional属性,我相信你会得到应用的 “默认” 事务性:

  • 传播设置是REQUIRED
  • 隔离级别为默认
  • 交易是可读/写的。
  • 事务超时默认为基础事务系统的默认超时值,如果超时不受支持,则默认为无。
  • 任意RuntimeException触发器回滚和​​任何检查异常不。

假设你正在使用的<tx:annotation-driven />通过一个事务管理器来驱动它,然后失踪了@Transactional属性意味着你不能为readOnly的隔离传播的rollbackFor应用这些性质,noRollbackFor

我相信MVC略有不同--Hibernate会话直接绑定到MVC请求 - 即当收到请求时,trans行动开始。

回到你的榜样,为的getSession()中的HibernateDaoSupport的代码如下:

protected final Session getSession() 
    throws DataAccessResourceFailureException, IllegalStateException 
{ 
    return getSession(this.hibernateTemplate.isAllowCreate()); 
} 

这反过来又来电:

/** 
* Obtain a Hibernate Session, either from the current transaction or 
* a new one. The latter is only allowed if "allowCreate" is true. 
*....... 
*/ 
protected final Session getSession() 
    throws DataAccessResourceFailureException, IllegalStateException { 
    return getSession(this.hibernateTemplate.isAllowCreate()); 
} 

最终调用:

/** 
* .... 
* @param allowCreate whether a non-transactional Session should be created 
* when no transactional Session can be found for the current thread 
* .... 
*/ 
private static Session doGetSession(
    SessionFactory sessionFactory, Interceptor entityInterceptor, 
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate) 

基本上,交易:Sess离子绑定1:1 AFAIK,并且没有事务运行的唯一方法是使用JBoss,它有一个“烘焙进去”持久层,为您提供事务性(在封面下)。即使您在getSession()之后调用getQuery(),您仍然有效地进行事务处理,因为它是JDBC/Hibernate连接。

0

如果您没有放置@transactional注解基本上@Transactional不是强制性的放在方法签名的顶部它只是用来通知编译器何时只读事务是只读= true(仅用于数据检索目的),当它是只读=假(只用于插入,更新,删除操作)

1

如果没有标注,你失去像回滚事务的优势。

你在做一个以上的数据库操作@Transactional注解,像许多插入其中一个出现故障,事务中的所有操作可以回滚给一致性您的数据。

这也是为什么建议将注释放入不在DAO中的服务。

+0

“没有回滚或交易”?否 - 您仍然对未检查过的异常RTE衍生物进行回滚,并且无论是使用spring-config配置还是以默认值提供的事务都可以进行回滚。 –

+0

如果您使用的是声明式事务管理,当然它不会影响回滚的工作方式,但是如果您完全依赖注释,则会影响一组数据库操作的行为方式。 – pfernandom

0

在你的场景中,你的DAO将在没有事务的情况下执行,很可能是自动提交。

如果你想避免这种错误的未来,需要所有的服务,在交易,你可以用以下@Transactional注释保护DAO层运行:

@Transactional(propagation = MANDATORY) 
public class HibernateAlertDAO extends HibernateDaoSupport implements AlertDAO { 
    ... 
} 

这个注解需要服务层申报交易否则会抛出异常。