简体   繁体   English

手动回滚Spring MVC + Hibernate

[英]Manual rollback Spring MVC + Hibernate

I am using Spring MVC + Hibernate 我正在使用Spring MVC + Hibernate

//Class for Generic Methods for **save and update** 

@Service("PersistenceTemplate")
@Transactional
public class PersistenceTemplate {

@Resource(name = "sessionFactory")
private SessionFactory sessionFactory;

// SAVE 
public <T> long save(T entity) throws DataAccessException {
    Session session = sessionFactory.getCurrentSession();
    long getGenVal=(Long) session.save(entity);
    return getGenVal;
}
//UPDATE
public <T> void update(T entity) throws DataAccessException {
    sessionFactory.getCurrentSession().update(entity);
}

} }

AT Controller AT控制器

@Resource(name = "PersistenceTemplate")
private PersistenceTemplate pt;
long result=pt.save(receiveTrxObj1);
pt.Update(receiveTrxObj2);

Problem statement 问题陈述

How to roll back save statement if Update fails to update the entity in database ? 如果Update无法更新数据库中的实体,如何回滚保存语句?

You could use application level exception to rollback your entity operations. 您可以使用应用程序级异常回滚您的实体操作。 When this custom exception thrown the related operations rollback. 当抛出此自定义异常时,相关操作将回滚。 Please see following documents to see how to define custom rollback in Spring. 请参阅以下文档,以了解如何在Spring中定义自定义回滚

For you to be able to rollback the save if the update fails, the save and update have to occur within the same transaction. 为了使您能够在更新失败时回滚保存,保存和更新必须在同一事务中进行。 Services are a natural place to put DAO calls that need to execute within the same transaction. 服务是放置需要在同一事务中执行的DAO调用的自然场所。

Putting a @Transactional annotation on the controller method would create complications due to proxying the controller, see the Spring MVC documentation , 17.3.2: 在控制器方法上放置@Transactional批注会由于代理控制器而产生复杂性,请参见Spring MVC文档 ,17.3.2:

A common pitfall when working with annotated controller classes happens when applying functionality that requires creating a proxy for the controller object (eg @Transactional methods). 当使用需要为控制器对象创建代理的功能(例如,@ Transactional方法)时,使用带注释的控制器类会发生常见的陷阱。 Usually you will introduce an interface for the controller in order to use JDK dynamic proxies. 通常,您将为控制器引入一个接口,以便使用JDK动态代理。 To make this work you must move the @RequestMapping annotations, as well as any other type and method-level annotations (eg @ModelAttribute, @InitBinder) to the interface as well as the mapping mechanism can only "see" the interface exposed by the proxy. 为此,您必须将@RequestMapping注释以及任何其他类型和方法级别的注释(例如@ ModelAttribute,@ InitBinder)移至该接口,并且映射机制只能“查看”代理。 Alternatively, you could activate proxy-target-class="true" in the configuration for the functionality applied to the controller (in our transaction scenario in ). 另外,您可以在配置中激活应用于控制器的功能的proxy-target-class =“ true”(在中的交易场景中)。 Doing so indicates that CGLIB-based subclass proxies should be used instead of interface-based JDK proxies. 这样做表明应该使用基于CGLIB的子类代理代替基于接口的JDK代理。 For more information on various proxying mechanisms see Section 9.6, “Proxying mechanisms”. 有关各种代理机制的更多信息,请参见第9.6节“代理机制”。

See this question for what goes in a service as opposed to in a controller. 有关在服务中而不是在控制器中发生了什么的信息,请参见此问题

first your @Service("PersistenceTemplate") should be marked as @Repository because its doing the work of DAO layer. 首先,您的@Service(“ PersistenceTemplate”)应该标记为@Repository,因为它可以完成DAO层的工作。

from the controller you should call a Service which should be annotated with @service and @Transactional and inside this service you create a method which will call a DAO layer. 从控制器中,您应该调用一个服务,该服务应使用@service和@Transactional进行注释,并在该服务内部创建一个将调用DAO层的方法。

if save or Update fails to update the entity in database the method from which it is called (ie. the method in service layer) will not complete and the transaction is cancelled automatically because persistence objects are synchronized with database near the end of the completion of method of service layer once the control comes back to it. 如果save或Update无法更新数据库中的实体,则调用该实体的方法(即服务层中的方法)将不会完成,并且该事务将自动取消,因为持久性对象将在数据库完成时接近结束时与数据库同步一旦控件返回到服务层的方法。

See the below example. 请参见以下示例。

@Service("authorLoadService")
@Transactional
@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS,value="request")
public class AuthorEntityLoadService implements EntitiesLoadService{

    private AuthorDAO authorDao;//this is my DAO





    @Autowired
    @Qualifier("authorDAO")
    public void setAuthorDao(AuthorDAO authorDao) {
        this.authorDao = authorDao;
    }

    @Override
    public void deleteEntities(Object o) {
        // TODO Auto-generated method stub

    }

    @Override
    public void loadEntities(Object o) {
        Set<author_pojo> author=(Set<author_pojo>)o;
        Iterator<author_pojo> itr=author.iterator();

        while (itr.hasNext()) {
            author_pojo authorPojo = (author_pojo) itr.next();
            authorDao.save(authorPojo);

        }


    }

    @Override
    @Transactional(readOnly=true)
    public List getEntities() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    @Transactional(readOnly=true)
    public Object getEntity(Object o) {
        String author=(String)o;
    author_pojo fetAuthor=authorDao.findOneByName(author);

        return fetAuthor;
    }

}

My Abstract Generic DAO 我的抽象通用DAO

public abstract class AbstractHibernateDAO<T extends Serializable> {

    public Class<T> clazz;//class object reference

    protected SessionFactory mysessionFactory;


    @Autowired
    public void setMysessionFactory(SessionFactory mysessionFactory) {
        this.mysessionFactory = mysessionFactory;
    }

    public T findOneByName(final String name){

        return (T) getCurrentSession().createQuery("from "+clazz.getName()).uniqueResult();
    }


    public void setClazz(final Class<T> clazzToSet) {
        this.clazz = clazzToSet;
    }

    public T findOne(final Long id) {
        return (T) getCurrentSession().get(clazz, id);
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll() {
        return getCurrentSession().createQuery("from " + clazz.getName()).list();
    }

    public void save(final T entity) {
        getCurrentSession().merge(entity);
    }

    public void update(final T entity) {
        getCurrentSession().update(entity);
    }

    public void delete(final T entity) {
        getCurrentSession().delete(entity);
    }

    public void deleteById(final Long entityId) {
        final T entity = findOne(entityId);
        delete(entity);
    }

    protected Session getCurrentSession() {

        return mysessionFactory.getCurrentSession();
    }
}

my concerete DAO 我的公公DAO

@Repository("authorDAO")
@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS,value="request")
public class AuthorDAO extends AbstractHibernateDAO<author_pojo> {

    public AuthorDAO() {

        setClazz(author_pojo.class);
    }

    public author_pojo findOneByName(final String name){
        System.out.println(clazz);
        return (author_pojo) getCurrentSession().createQuery("from "+clazz.getName() +" where authorName=:name").setParameter("name", name).uniqueResult();
    }



}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM