我正在使用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控制器
@Resource(name = "PersistenceTemplate")
private PersistenceTemplate pt;
long result=pt.save(receiveTrxObj1);
pt.Update(receiveTrxObj2);
问题陈述
如果Update无法更新数据库中的实体,如何回滚save语句?
答案 0 :(得分:0)
您可以使用应用程序级异常来回滚实体操作。当此自定义异常抛出相关操作回滚时。请参阅以下文档,了解如何在Spring中定义custom rollback。
答案 1 :(得分:0)
如果更新失败,您可以回滚保存,则保存和更新必须在同一事务中进行。服务是放置需要在同一事务中执行的DAO调用的自然场所。
在控制器方法上放置@Transactional注释会因代理控制器而产生复杂性,请参阅the Spring MVC documentation,17.3.2:
使用带注释的控制器类时常见的陷阱 在应用需要创建代理的功能时发生 控制器对象(例如@Transactional方法)。通常你会 为控制器引入一个接口,以便使用JDK动态 代理。要使其工作,您必须移动@RequestMapping 注释,以及任何其他类型和方法级注释 (例如@ModelAttribute,@ InitBinder)到接口以及 映射机制只能“看到”代理公开的接口。 或者,您可以在中激活proxy-target-class =“true” 应用于控制器的功能的配置(在我们的 交易场景)。这样做表明 应该使用基于CGLIB的子类代理而不是 基于接口的JDK代理。有关各种代理的更多信息 机制见第9.6节“代理机制”。
请参阅this question了解服务中的内容,而不是控制器中的内容。
答案 2 :(得分:0)
首先应将@Service(“PersistenceTemplate”)标记为@Repository,因为它正在执行DAO层的工作。
从控制器你应该调用一个应该用@service和@Transactional注释的服务,在这个服务中你创建一个调用DAO层的方法。
如果保存或更新无法更新数据库中的实体,则调用它的方法(即服务层中的方法)将无法完成,并且事务会自动取消,因为持久性对象与数据库的末尾同步一旦控制回到它就完成了服务层的方法。
见下面的例子。
@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;
}
}
我的抽象通用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();
}
}
我的伙伴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();
}
}