当前位置: 首页 > 知识库问答 >
问题:

spring boot hibernate事务管理器即使在运行时异常时也不会回滚事务

夏嘉德
2023-03-14

我在一家spring boot hibernate JPA个人项目书店工作。我面临一个问题,即使用@Transactional注释注释的方法即使在运行时异常的情况下也无法回滚事务。我使用的是spring boot版本1.5.1、hibernate版本5、java版本11

下面是bean配置文件代码:

package com.freetests4u;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
public class BeanConfig {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Bean
    public SessionFactory getSessionFactory() {
        if (entityManagerFactory.unwrap(SessionFactory.class) == null) {
            throw new NullPointerException("factory is not a hibernate factory");
        }
        return entityManagerFactory.unwrap(SessionFactory.class);
    }

    @Bean
    public Module datatypeHibernateModule() {
      return new Hibernate5Module();
    }
    
    
    @Bean
    public PlatformTransactionManager hibernateTransactionManager() {
        HibernateTransactionManager transactionManager
          = new HibernateTransactionManager();
        transactionManager.setSessionFactory(getSessionFactory());
        return transactionManager;
    }
    
//  @Bean
//  public DataSource dataSource() {
//      return new MysqlDataSource(); // (1)
//  }
//
//  @Bean
//  public PlatformTransactionManager txManager() {
//      return new HibernateTransactionManager(); // (2)
//  }
    
}

下面是BooK模型文件代码

package com.freetests4u.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="books")
public class Book {

    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name="title")
    private String title;
    
    @Column(name="writer")
    private String writer;

    @Column(name="language")
    private String language;
    
    @Column(name="category")
    private String category;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getWriter() {
        return writer;
    }

    public void setWriter(String writer) {
        this.writer = writer;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }
    
    

}

下面是商店型号代码

package com.freetests4u.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="store")
public class Store {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    int id;
    
    @Column(name="bookid")
    int bookId;
    
    @OneToOne
    @JoinColumn(name="bookid", referencedColumnName="id", insertable = false, updatable = false)
    Book book;
    
    @Column(name="bookcount")
    int bookCount;
    
    @Column(name="isdeleted")
    boolean isDeleted;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getBookId() {
        return bookId;
    }

    public void setBookId(int bookId) {
        this.bookId = bookId;
    }

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }

    public int getBookCount() {
        return bookCount;
    }

    public void setBookCount(int bookCount) {
        this.bookCount = bookCount;
    }

    public boolean isDeleted() {
        return isDeleted;
    }

    public void setDeleted(boolean isDeleted) {
        this.isDeleted = isDeleted;
    }


    
}

下面是BookDaoImpl代码

package com.freetests4u.dao.impl;

import java.util.List;


import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.annotation.Transactional;
import com.freetests4u.dao.BookDao;
import com.freetests4u.model.Book;


@Component
public class BookDaoImpl implements BookDao {

    @Autowired
    private SessionFactory sessionFactory;
    
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public boolean addBook(Book book) {
        // TODO Auto-generated method stub
        
          TransactionStatus status=null;
          try {
             status = TransactionAspectSupport.currentTransactionStatus();
          } catch (NoTransactionException e) {
              System.err.println(e);
          }
          System.out.println("from addBook: "+status!=null? "active transaction": "no transaction");

        
        Session session = sessionFactory.openSession();
//      Transaction trans = session.beginTransaction();
        
//      try {
            session.save(book);
//          trans.commit();
            return true;
//      }
//      catch(Exception e) {
//          e.printStackTrace();
//          trans.rollback();
//          return false;
//      }
//      finally {
//      session.close();
//      }
        
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Book> getBookList(int limit, int offset) {
        // TODO Auto-generated method stub
                
        int finalLimit = limit!=0?limit:10;
        int finalOffset = offset!=0?offset:0;
                
        return (List<Book>) sessionFactory.openSession().createCriteria(Book.class)
//              .createAlias("Book.id", "BookId")
                .addOrder(Order.desc("id"))
                .setFirstResult(finalOffset)
                .setMaxResults(finalLimit)
                .list();
    }

    @Override
    public Book getBook(int id) {
        // TODO Auto-generated method stub
        
        String hqlQuery = "from Book Where id=:id";
        return (Book) sessionFactory.openSession().createQuery(hqlQuery).setParameter("id", id).uniqueResult();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Book> getBook(String name) {
        // TODO Auto-generated method stub
        
        String hqlQuery = "from Book Where title=:title";
        return (List<Book>) sessionFactory.openSession().createQuery(hqlQuery).setParameter("title", name).list();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Book> getBooks(String writer, String language, String category, int limit, int offset) {
        // TODO Auto-generated method stub
                
        Book b = new Book();        
        b.setWriter(writer);
        b.setLanguage(language);
        b.setCategory(category);
        
        boolean flag =false;
        
        String hqlQuery = " from Book WHERE ";
        
        if(writer!=null && !writer.isEmpty()) {
            hqlQuery = hqlQuery + "writer=:writer ";
            flag=true;
        }
        
        if(language!=null && !language.isEmpty()) {
            hqlQuery = flag==true?  hqlQuery + "AND language=:language ":hqlQuery + "language=:language";
            flag=true;
        }

        if(category!=null && !category.isEmpty()) {
            hqlQuery = flag==true?  hqlQuery + "AND category=:category ":hqlQuery + "category=:category ";
            flag=true;
        }
        
        hqlQuery = hqlQuery + " Order By id desc";
        
        return (List<Book>) sessionFactory.openSession().createQuery(hqlQuery).setProperties(b)
                .setFirstResult(offset)
                .setMaxResults(limit)
                .list();
        
    }

}

下面是StoreDaoImpl代码

package com.freetests4u.dao.impl;

import org.hibernate.Transaction;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.freetests4u.dao.StoreDao;
import com.freetests4u.dto.StoreAction;
import com.freetests4u.model.Store;

@Component
public class StoreDaoImpl implements StoreDao{

    @Autowired
    SessionFactory sessionFactory;
    
    @Override
    public void updateStore(int bookId, StoreAction action) {
        // TODO Auto-generated method stub
        
        Session session = sessionFactory.openSession();
        
        try {
            String hql ="";
            if(action==StoreAction.INCREMENT) {
            hql = "UPDATE Store s SET s.count=s.count+1";
            }
            else if(action==StoreAction.DECREMENT){
                hql = "UPDATE Store s SET s.count=s.count-1";
            }
            
            int count = session.createQuery(hql).executeUpdate();
            System.out.println("updated count: "+count);
            
        }
        catch(Exception e) {
            e.printStackTrace();
            throw e;
        }
        finally {
            session.close();
        }
    }

    @Override
    public Store getBookCountByBookId(int bookId) {
        // TODO Auto-generated method stub
        
        Session session = sessionFactory.openSession();
        
        try {
            String hql ="from Store where bookId=:bookId";
            
            return (Store) session.createQuery(hql)
                    .setParameter("bookId", bookId)
                    .uniqueResult();
        }
        catch(Exception e) {
            e.printStackTrace();
            throw e;
        }
        finally {
            session.close();
        }
        
    }
    
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public void createStoreEntry(int bookId) {
        // TODO Auto-generated method stub
        Session session = sessionFactory.openSession();
//      Transaction tr = session.beginTransaction();
        
          TransactionStatus status=null;
          try {
             status = TransactionAspectSupport.currentTransactionStatus();
          } catch (NoTransactionException e) {
              System.err.println(e);
          }
          System.out.println("from createStoreEntry: "+status!=null? "active transaction": "no transaction");

        
//      try {
            Store store = new Store();
            store.setBookId(bookId);
            store.setBookCount(0);
            store.setDeleted(false);
            session.save(store);
//          tr.commit();
//      }
//      catch(Exception e) {
//          e.printStackTrace();
//          throw e;
//      }
//      finally {
//          session.close();
//      }
    }
    
}

下面是BookServiceImpl代码

package com.freetests4u.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.annotation.Transactional;
import com.freetests4u.dao.BookDao;
import com.freetests4u.dao.StoreDao;
import com.freetests4u.dto.BookSearchRequest;
import com.freetests4u.exceptions.DuplicateBookEntryException;
import com.freetests4u.model.Book;
import com.freetests4u.service.BookService;

@Service
public class BookServiceImpl implements BookService{
    
    @Autowired
    BookDao bookDao;
    
    @Autowired
    StoreDao storeDao;

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public void addBook(Book b) throws DuplicateBookEntryException {
        // TODO Auto-generated method stub
        
//      List<Book> old = bookDao.getBook(b.getTitle().toLowerCase());
//      if(old.size()>0) {
//          throw new DuplicateBookEntryException("Book with same name already exists");
//      }       
        
//      Sessio  
        
          TransactionStatus status=null;
          try {
             status = TransactionAspectSupport.currentTransactionStatus();
          } catch (NoTransactionException e) {
              System.err.println(e);
          }
          System.out.println(status!=null? "active transaction": "no transaction");

          try {
        storeDao.createStoreEntry(13);
        bookDao.addBook(b);
          }
          catch(Exception e) {
              System.out.println("throwing exception");
              e.printStackTrace();
              throw e;
          }
    }

    @Override
    public Book getBook(int id) {
        // TODO Auto-generated method stub
        return bookDao.getBook(id);
    }

    @Override
    public List<Book> getBooks(int limit, int offset) {
        // TODO Auto-generated method stub
        
        return bookDao.getBookList(limit, offset);
    }

    @Override
    public List<Book> getBook(String name) {
        // TODO Auto-generated method stub
        return bookDao.getBook(name);
    }

    @Override
    public List<Book> getBooks(BookSearchRequest br) {
        // TODO Auto-generated method stub
        return bookDao.getBooks(br.getWriter(), br.getLanguage(), br.getCategory(), br.getLimit(), br.getOffset());
    }

}

如果你能指出上面代码中的错误,那就太好了。谢谢

共有1个答案

韶云瀚
2023-03-14

您不应该使用Session Session=sessionFactory。openSession() -这将每次创建一个全新的会话。相反,您只需要注入当前会话并使用它。

顺便说一句,我不确定您的配置是否是必要的。通常,如果您包含正确的启动器,Spring Boot自动配置会处理所有事情(对于Spring Boot 2,即spring-boot-starter-data-jpa)。

@Component
public class BookDaoImpl implements BookDao {

    @Autowired
    private Session session; // Might want to use JPA EntityManager instead
    
    @Transactional(rollbackFor = MyException.class) // propagation = Propagation.REQUIRED is default anyway
    @Override
    public boolean Book addBook(Book book) {
        // No need to handle transaction manually
        session.save(book);
        return true; // Maybe return something more useful
    }
}
 类似资料:
  • 在上面的代码中,我将hibernate与mysql一起使用,hibernate会话由SpringSessionContext管理(在事务边界下使用SessionFactory.CurrentSession类) 下面的镜像(dao层)是直接的用例,但是异常没有回滚,我从简单的服务层调用这个方法(即服务层调用dao层进行CRUD操作),我了解了spring在事务管理上的代理机制,在这种情况下,下面的镜

  • 问题内容: 如果在mysql命令列表中发生任何错误,是否可以自动回滚? 例如类似以下内容的东西: 现在,在执行我希望整个交易失败,因此我应该 不 看到值1在myTable的。但是不幸的是,即使事务有错误,该表也仍使用values1进行伪造。 任何想法,我如何使其回滚?(再次出现任何错误)? 编辑-从DDL更改为标准SQL 问题答案: 您可以使用13.6.7.2。DECLARE … HANDLER语

  • 这很好,但并不总是在代码中抛出运行时异常。因此,我挖掘并发现如下所示的rollbackFor; 现在,我必须更改所有代码,以使用RollBackfor更改@Transactional。但是还有其他方法可以将所有@transaction advice属性更改为rollbackFor=exception.class吗?

  • 在上面的代码中,ConstraintViolationException发生在saveTicket()方法内,saveTicket()内的dao甚至在捕获异常之前就已经回滚了它的事务(这是我所知道的),第一个没有回滚,因为它在另一个事务中。(这是我已经知道的行为)。 当我使用另一个事务性方法调用这两个预览方法(updateRequest()和saveTicket()),当saveTicket()方

  • 我在tomcat服务器中使用具有多个数据源配置的JTA原子事务。有时我会遇到以下异常: JTA事务意外回滚(可能是由于超时);嵌套的异常是javax。交易回滚异常:事务被设置为仅回滚 出现这种异常的原因是什么?