Как откатить транзакцию в JPA?
У меня есть EntityManager
объект поддерживается средой Spring, и я внедряю его в любой класс DAO, который я хочу, используя @PersistenceContext
аннотация как это..
@PersistenceContext(unitName="entityManager")
private EntityManager em;
Я использую эти классы DAO для сохранения в базе данных что-то вроде этого..
class MyClass
{
@Resource(name="myDao")
private MyDao dao;
@Resource(name="myAnotherDao")
private MyAnotherDao anotherDao;
public void save(String s1,String s2)
{
try
{
MyEntity m=new MyEntity();
m.setName(s1);
// .. and so on ..
XYZ x=new XYZ();
x.setDEF(s2);
anotherDao.save(x);
m.setXYZ(x);
// .. some other stuff .. //
dao.saveEntity(m);
}
catch(Exception e)
{
// I would like to rollback the transaction
}
}
}
Теперь оба даоса используют один и тот же EntityManager
вводится через @PersistenceContext(unitName="entityManager")
, Теперь, если исключение происходит после setXYZ()
, то я бы хотел откатить даже сохраненный XYZ
юридическое лицо. Но как я могу получить EntityManager
От этого?
Если все Daos содержат один и тот же объект, то могу ли я просто вызвать getTransaction().rollback()
метод EntityManager
учебный класс? Ли getTransaction()
вернуть новую транзакцию или любую транзакцию, которая в данный момент связана с EntityManager
?
3 ответа
Если вы использовали Spring AOP для управления транзакцией, а конфигурация и аннотация используются правильно, то по умолчанию эффект будет откат транзакции при возникновении исключения во время выполнения.
Если вы управляли транзакцией вручную, вы можете откатить транзакцию следующим образом:
EntityManager em = createEntityManager(); try { em.getTransaction().begin(); // Do something with the EntityManager such as persist(), merge() or remove() em.getTransaction().commit(); } catch(Exception e) { em.getTransaction().rollback(); } em.close();
Смотрите больше на: http://en.wikibooks.org/wiki/Java_Persistence/Transactions http://www.developerscrappad.com/547/java/java-ee/ejb3-x-jpa-when-to-use-rollback-and-setrollbackonly/
Это будет откат после того, как вы сгенерируете любое RuntimeException из метода, помеченного как @Transactional, как показано ниже:
По умолчанию все транзакции отката RuntimeExceptions, где как проверенные исключения не:
@Transactional(rollbackFor={MyRuntimeException.class, AnotherRuntimeException.class})
public SomeVal someTransactionalMethod(){
...
}
Для отката транзакции вы можете использовать аннотацию @Transaction. Вы можете реализовать его на уровне метода или класса.
Пример уровня метода:
@Transactional(rollbackFor = {YourDesiredException.class, SomeOtherException.class})
void yourMethod(datatype param1,...){
//your transaction that may throw exception
}
Пример уровня класса:
@Transactional(rollbackFor = {YourDesiredException.class, SomeOtherException.class})
public class SomeClass throws YourDesiredException{
void method1(){
//transaction 1
}
void method2(){
//transaction 2
}
}
Уровень класса @Transactional(rollbackFor = Exception.class) откатит всю транзакцию, произошедшую на уровне класса, тогда как на уровне метода будут откатываться только транзакции, произошедшие в этом методе.
PS: не используйте блок try-catch (т.е. не перехватывайте исключение) и позвольте исключению распространяться.
Только не лови исключение. Пусть это пузырь. Spring автоматически откатит транзакцию, если из вызова транзакционного метода будет сгенерировано исключение во время выполнения. И звонящий по крайней мере будет знать, что случилось что-то плохое, вместо того, чтобы думать, что все прошло хорошо.
В любом случае, ваш блок catch, вероятно, ничего не поймает, потому что большинство исключений происходит во время сброса, а сброс в основном происходит непосредственно перед коммитом в перехватчике транзакции Spring. Помните, что сохранение сущности не выполняет запрос вставки немедленно. Он просто сообщает Hibernate, что до окончания транзакции вставка должна быть выполнена.