我在一家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());
}
}
如果你能指出上面代码中的错误,那就太好了。谢谢
您不应该使用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。交易回滚异常:事务被设置为仅回滚 出现这种异常的原因是什么?