我遇到了Spring事务的问题。我真的需要帮助,因为我无法弄清楚为什么PersonDao2没有回滚的原因(请参阅下面的断言评论为“FAILS!”)。有什么输入吗?
我的Eclipse项目可在http://www52.zippyshare.com/v/4142091/file.html下载。所有依赖都在那里,因此很容易上手。
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
public class MyInnerClass {
private PersonsDao personsDao;
public MyInnerClass() {
}
public PersonsDao getPersonsDao() {
return personsDao;
}
public void setPersonsDao(PersonsDao personsDao) {
this.personsDao = personsDao;
}
@Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = Exception.class)
public void method() {
personsDao.createPersons(Lists.newArrayList(new Person("Eva")));
}
}
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
public class MyOuterClass {
private MyInnerClass myInnerClass;
private PersonsDao personsDao;
public MyInnerClass getMyInnerClass() {
return myInnerClass;
}
public void setMyInnerClass(MyInnerClass myInnerClass) {
this.myInnerClass = myInnerClass;
}
public void setMyInnerClass() {
}
public PersonsDao getPersonsDao() {
return personsDao;
}
public void setPersonsDao(PersonsDao personsDao) {
this.personsDao = personsDao;
}
public MyOuterClass() {
}
@Transactional(propagation = Propagation.REQUIRED, rollbackFor=Exception.class)
public void method() {
try {
personsDao.createPersons(Lists.newArrayList(new Person("Adam")));
throw new RuntimeException("Forced rollback");
} finally {
myInnerClass.method();
}
}
}
public class Person {
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Customer [name=" + name + "]";
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
private String name;
}
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
public class PersonsDao {
public PersonsDao(DataSource dataSource, String tableName) {
namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.tableName = tableName;
}
public List<Person> getPersons() {
Map<String, Object> namedParameters = new HashMap<String, Object>();
String getCustomers = "SELECT name FROM " + tableName + " ORDER BY name ASC";
return namedParameterJdbcTemplate.query(getCustomers, namedParameters, getRowMapper());
}
public void createPersons(List<Person> customers) {
SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(customers.toArray());
String createCustomer = "INSERT INTO " + tableName + " VALUES(:name)";
namedParameterJdbcTemplate.batchUpdate(createCustomer, params);
}
public void deleteCustomers() {
Map<String, Object> namedParameters = new HashMap<String, Object>();
String deleteCustomers = "DELETE FROM " + tableName;
namedParameterJdbcTemplate.update(deleteCustomers, namedParameters);
}
private static RowMapper<Person> getRowMapper() {
return new RowMapper<Person>() {
@Override
public Person mapRow(ResultSet arg0, int arg1) throws SQLException {
return new Person(arg0.getString("name"));
}
};
}
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private String tableName;
}
import static org.junit.Assert.*;
import javax.annotation.Resource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/beans.xml")
@Transactional(rollbackFor = Exception.class)
public class PersonsDaoTest {
@Resource
private MyInnerClass myInnerClass;
@Resource
private MyOuterClass myOuterClass;
@Test(expected = Exception.class)
public void test() {
myOuterClass.method();
fail();
}
@After
public void after() {
assertEquals(1, myInnerClass.getPersonsDao().getPersons().size());
assertEquals(0, myOuterClass.getPersonsDao().getPersons().size());
}
@Before
public void before() {
myInnerClass.getPersonsDao().deleteCustomers();
myOuterClass.getPersonsDao().deleteCustomers();
assertEquals(0, myInnerClass.getPersonsDao().getPersons().size());
assertEquals(0, myOuterClass.getPersonsDao().getPersons().size());
}
}
答案 0 :(得分:2)
首先,忽略两个类的@Transactional
注释,因为您直接实例化这些类(使用new
)而不是从spring上下文中获取实例。
事实上,它归结为这段代码:
try {
personDao2.createPerson(); // creates a person in persons2
throw new RuntimeException();
}
finally {
personDao1.createPerson(); // creates a person in person1
}
即使在try块中抛出异常,也始终执行finally块。因此,该测试会在person1
和person2
中创建一个人。
答案 1 :(得分:1)