[英]Spring requires @Transactional to be on getter services?
My understanding is @Transactional
should only be applied to service methods that need to occur within a transaction (such as setters). 我的理解是@Transactional
应该只应用于需要在事务中发生的服务方法(例如setter)。 Say I have the following two classes (DAO layer and Service layer respectively)... 假设我有以下两个类(分别是DAO层和服务层)...
@Service("playerService")
public class PlayerServiceImpl implements PlayerService {
@Autowired
private PlayerDao playerDao;
@Override
public List<Player> getAll() {
return playerDao.getAll();
}
@Override
@Transactional
public void addAllPlayers(final List<Player> players) {
playerDao.addAllPlayers(players);
}
}
@Repository("playerDao")
public class PlayerDaoImpl implements PlayerDao {
@Autowired
private SessionFactory sessionFactory;
@SuppressWarnings("unchecked")
@Override
public List<Player> getAll() {
return (List<Player>) sessionFactory.getCurrentSession()
.createQuery("FROM Player").list();
}
@Override
public void addPlayer(final Player player) {
sessionFactory.getCurrentSession().save(player);
}
}
Now if I called addAllPlayers()
this works fine, no problems at all. 现在,如果我调用addAllPlayers()
这个工作正常,没有任何问题。 But when I use getAll()
, sessionFactory.getCurrentSession throws a HibernateException, no session found for current thread. 但是当我使用getAll()
,sessionFactory.getCurrentSession会抛出一个HibernateException,找不到当前线程的会话。
If I add @Transactional
to the service layer for getAll(), this will now work "fine". 如果我将@Transactional
添加到getAll()的服务层,现在这将“正常”。 The problem with this is I shouldn't have to open a transaction just to call a getter. 这个问题是我不应该只是为了调用getter而打开一个事务。
Can anyone think of any reason why my I need to add @Transactional
on a getter method to get the sessionFactory to have a current session? 任何人都可以想到为什么我需要在getter方法上添加@Transactional
以使sessionFactory拥有当前会话? My servlet-context.xml and persistance-context.xml are shown below (these are both referenced in my web.xml in contextConfigLocation) 我的servlet-context.xml和persistance-context.xml如下所示(这些都在我的web.xml中的contextConfigLocation中引用)
servlet-context.xml servlet的context.xml中
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<tx:annotation-driven transaction-manager="hibernateTransactionManager" />
<mvc:annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<mvc:resources location="/resources/css/" mapping="/css/**" />
<mvc:resources location="/resources/js/" mapping="/js/**" />
<mvc:resources location="/resources/images/" mapping="/images/**" />
<mvc:resources location="/resources/img/" mapping="/img/**" />
<mvc:resources location="/favicon.ico" mapping="/favicon.ico" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.footieview.app" />
<beans:bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<beans:property name="mediaTypes">
<beans:map>
<beans:entry key="html" value="text/html" />
<beans:entry key="json" value="application/json" />
</beans:map>
</beans:property>
<beans:property name="defaultViews">
<beans:list>
<beans:bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<beans:property name="prefixJson" value="true" />
</beans:bean>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="PlayerImportDaoImpl"
class="com.footieview.app.importer.dao.PlayerImportDaoImpl" />
<beans:bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
</beans:beans>
persistance-context.xml 持久性-的context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url"
value="jdbc:mysql://localhost/db" />
<beans:property name="username" value="username" />
<beans:property name="password" value="password" />
</beans:bean>
<beans:bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="annotatedClasses">
<beans:list>
<beans:value>com.footieview.app.entity.Player</beans:value>
</beans:list>
</beans:property>
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="packagesToScan" value="com.footieview.app.entity.*" />
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</beans:prop>
<beans:prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory
</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="hibernate.hbm2ddl.auto">create</beans:prop>
<beans:prop key="hibernate.cache.use_second_level_cache">
true
</beans:prop>
<beans:prop key="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</beans:prop>
<beans:prop key="hibernate.cache.use_query_cache">
true
</beans:prop>
<beans:prop key="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</beans:prop>
<beans:prop key="hibernate.cglib.use_reflection_optimizer">
true
</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
</beans:beans>
@Transactional does not only open a DB transaction but in case of Hibernate it also creates a hibernate session if there is none. @Transactional不仅打开数据库事务,而且在Hibernate的情况下,如果没有,它还会创建一个hibernate会话。 A typical approach is to use OpenSessionInViewFilter
which creates one Hibernate session for each http request. 一种典型的方法是使用OpenSessionInViewFilter
,它为每个http请求创建一个Hibernate会话。
If you don't want to use this filter you need to annotate getters with @Transactional as well. 如果您不想使用此过滤器,则还需要使用@Transactional注释getter。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.