开发者

If TransactionProxyFactoryBean is used for service layer bean then is there any need of transaction annotation driven in dao?

The interface for service layer is :

EMS.java:

public interface EMS extends UserDetailsService {

    public void saveUser(User user);
}

and its implementation:

EMSImpl.java:

@Service("emsImpl")
@Transactional(readOnly=true)
public class EMSImpl implements EMS {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    @Qualifier("dao")
    private EMSDao dao;


    @Transactional(readOnly=false)
    public void saveUser(User user) {
        dao.saveUser();
    }
}

The interface for dao:

EMSDao.java:

public interface EMSDao {

    public void saveUser(User user);
}

And its implementation:

HibernateEMSDao.java

@Repository("EMSDao")
public class HibernateEMSDao extends HibernateDaoSupport implements EMSDao {

开发者_Go百科    private final Logger logger = LoggerFactory.getLogger(getClass());  

    private SchemaHelper schemaHelper;

    public void setSchemaHelper(SchemaHelper schemaHelper) {
        this.schemaHelper = schemaHelper;
    }

    @Transactional(readOnly=false)
    public synchronized void saveUser(final User user) {        
        Session session = getSessionFactory().getCurrentSession();
        session.merge(user);
        }       

    private void storeUser(User user) {
        getHibernateTemplate().save(user);
    }

    public void createSchema() {        
        try {
            getHibernateTemplate().find("from User user where user.id = 1");
        } catch (Exception e) {
            logger.warn("expected database schema does not exist, will create. Error is: " + e.getMessage());
            schemaHelper.createSchema();
            User admin = new User();
            admin.setUsername("admin");
            admin.setName("Admin");
            admin.setEmail("admin");
            admin.setPassword("21232f297a57a5a743894a0e4a801fc3");
            admin.setRoles(new HashSet<Role>(Arrays.asList(new Role("admin", "ADMINISTRATOR"))));
            logger.info("inserting default admin user into database");
            storeUser(admin);           
            logger.info("schema creation complete");                        
            return;
        }
        logger.info("database schema exists, normal startup");      
    }
}

The bean ems in appliactionContext.xml is created by TransactionProxyFactoryBean. Also I am using <tx:annotation-driven />

The complete applicationContext.xml is:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

    <bean class="info.ems.config.EMSConfigurer"/>

    <bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>

    <bean id="ems" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>        
    <property name="target">            
        <bean class="info.ems.EMSImpl" init-method="init">
            <property name="dao" ref="dao"/>
            <property name="passwordEncoder" ref="passwordEncoder"/>
            <property name="localeList" value="${ems.locales}"/>
            <property name="releaseVersion" value="${ems.version}"/>
            <property name="releaseTimestamp" value="${ems.timestamp}"/>
            <property name="emsHome" value="${ems.home}"/>
        </bean>
    </property>        
    <property name="transactionAttributes">
        <props>                
            <prop key="store*">PROPAGATION_REQUIRED</prop>
            <prop key="update*">PROPAGATION_REQUIRED</prop>
            <prop key="remove*">PROPAGATION_REQUIRED</prop>                
            <prop key="bulkUpdate*">PROPAGATION_REQUIRED</prop>
            <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
        </props>
    </property>        
    </bean>   

    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="dataSource" class="info.ems.datasource.DataSourceFactory">
    <property name="driverClassName" value="${database.driver}"/>
    <property name="url" value="${database.url}"/>
    <property name="username" value="${database.username}"/>
    <property name="password" value="${database.password}"/>
    <property name="validationQuery" value="${database.validationQuery}"/>
    <property name="dataSourceJndiName" value="${database.datasource.jndiname}"/>
    </bean>     

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation">
            <value>/WEB-INF/hibernate.cfg.xml</value>
        </property>
    <property name="configurationClass">
        <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>        
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>        
            <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> 
            <prop key="hibernate.current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</prop>    
        </props>
    </property>        
    </bean>

    <bean id="dao" class="info.ems.hibernate.HibernateEMSDao" init-method="createSchema">
    <property name="hibernateTemplate">
        <bean class="org.springframework.orm.hibernate3.HibernateTemplate">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    </property>        
    <property name="schemaHelper">
        <bean class="info.ems.hibernate.SchemaHelper">                                
            <property name="driverClassName" value="${database.driver}"/>
            <property name="url" value="${database.url}"/>
            <property name="username" value="${database.username}"/>
            <property name="password" value="${database.password}"/>
            <property name="hibernateDialect" value="${hibernate.dialect}"/>   
            <property name="dataSourceJndiName" value="${database.datasource.jndiname}"/>
        </bean>                
    </property>
    </bean>       
</beans>

I want to know:

  • Is it the right configuration for handling database transaction by spring?
  • Is it needed to use TransactionProxyFactoryBean along with <tx:annotation-driven />?

Any information or web-link where I can get example will be very helpful.

Thanks and regards.

Edit: after getting suggestion from skaffman the modified appliactionContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

    <bean class="info.ems.config.EMSConfigurer"/>

    <bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>

    <bean id="ems" class="info.ems.EMSImpl" init-method="init">
            <property name="dao" ref="dao"/>
            <property name="passwordEncoder" ref="passwordEncoder"/>
            <property name="localeList" value="${ems.locales}"/>
            <property name="releaseVersion" value="${ems.version}"/>
            <property name="releaseTimestamp" value="${ems.timestamp}"/>
            <property name="emsHome" value="${ems.home}"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="dataSource" class="info.ems.datasource.DataSourceFactory">
    <property name="driverClassName" value="${database.driver}"/>
    <property name="url" value="${database.url}"/>
    <property name="username" value="${database.username}"/>
    <property name="password" value="${database.password}"/>
    <property name="validationQuery" value="${database.validationQuery}"/>
    <property name="dataSourceJndiName" value="${database.datasource.jndiname}"/>
    </bean>     

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation">
            <value>/WEB-INF/hibernate.cfg.xml</value>
        </property>
    <property name="configurationClass">
        <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>        
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>        
            <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> 
            <prop key="hibernate.current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</prop>    
        </props>
    </property>        
    </bean>

    <bean id="dao" class="info.ems.hibernate.HibernateEMSDao" init-method="createSchema">
    <property name="hibernateTemplate">
        <bean class="org.springframework.orm.hibernate3.HibernateTemplate">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    </property>        
    <property name="schemaHelper">
        <bean class="info.ems.hibernate.SchemaHelper">                                
            <property name="driverClassName" value="${database.driver}"/>
            <property name="url" value="${database.url}"/>
            <property name="username" value="${database.username}"/>
            <property name="password" value="${database.password}"/>
            <property name="hibernateDialect" value="${hibernate.dialect}"/>   
            <property name="dataSourceJndiName" value="${database.datasource.jndiname}"/>
        </bean>                
    </property>
    </bean>       
</beans>


Is it the right configuration for handling database transaction by spring?

It's perfectly valid, but it's confusing and duplicates work. This will probably generate two layers of transactional proxies, although I doubt that will behave any differently.

As you say, you probably don't want to use both TransactionProxyFactoryBean and <tx:annotation-driven /> at the same time.

Your TransactionProxyFactoryBean config is using externalised method name patterns to decide which methods get which transaction semantics. This is fine, although with current versions of Spring it's usually easier to use annotations instead of the transactionAttributes property on TransactionProxyFactoryBean.

Given your config, I suggest getting rid of the explicit TransactionProxyFactoryBean bean definition (<tx:annotation-driven /> will create its own one as required, behind the scenes). Replace that with the undecorated EMSImpl, and <tx:annotation-driven /> will generate the transaction proxy automatically.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜