首先要说明的一点是Spring的事务注解可以写在controller 也可以写在service层,下次见到写在controller层的事务注解不要惊讶....
注解失败的情况1
service层普通方法(testDeleteUser)调用带注解(deleteUserRunningTimeException)的方法,发生运行时异常后,回滚失败
解决办法:
普通方法(testDeleteUser)也加上注解
注:
如果在方法里进行了异常捕获,一定要抛出去,否则回滚依然不会生效
@Transactional
public void deleteUserRunningTimeException(int id) {
try {
usersDao.deleteUserById(id);
int num = 1 / 0;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
/**
* 普通方法调用注解方法
*/
//@Transactional
public void testDeleteUser(int id) {
deleteUserRunningTimeException(id);
}
注解失败的情况2
service层方法报了非运行时异常,回滚操作失败
解决办法:
方法添加注解,声明为Exception类型进行回滚
@Transactional(rollbackFor = Exception.class),同样,如果捕获了异常,必须抛出去,否则回滚不会生效
/**
* 测试非运行时异常,是否回滚
* @param id
*/
@Transactional(rollbackFor = Exception.class)
public void deleteUserSimpleException(int id) throws Exception {
FileReader fileReader = null;
try {
usersDao.deleteUserById(id);
//创建要读取的数据文件的文件对象 file
File file = new File("d:\\data.txt");
//创建要读取数据的输入流
fileReader = new FileReader(file);
//从输入流中读取一个字符;
int c = fileReader.read();
//判断是否读取到文件结束,如果读取到文件的最后会返回-1
while (c!=-1) {
//输出读取的这个字符
System.out.println((char)c);
//再读取下一个字符
c = fileReader.read();
}
} catch (Exception e) {
e.printStackTrace();
try {
if (fileReader != null) {
fileReader.close();
fileReader = null;
}
} catch (Exception e2) {
e2.printStackTrace();
}
} finally {
try {
if (fileReader != null) {
fileReader.close();
fileReader = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 普通方法调用注解方法
*/
@Transactional(rollbackFor = Exception.class)
public void testDeleteUser(int id) throws Exception {
deleteUserSimpleException(id);
}
注解失败的情况2.1
实际项目中,并不会对每一个方法进行仔细的排查,再决定使用哪种注解,只需要捕获异常后抛出运行时异常就可以完成回滚操作
注:
这种方式注解就不需要指定某种类型的异常了,默认就是对运行时异常进行回滚
/**
* 测试非运行时异常,是否回滚
* @param id
*/
@Transactional
public void deleteUserSimpleException2(int id) {
FileReader fileReader = null;
try {
usersDao.deleteUserById(id);
//创建要读取的数据文件的文件对象 file
File file = new File("d:\\data.txt");
//创建要读取数据的输入流
fileReader = new FileReader(file);
//从输入流中读取一个字符;
int c = fileReader.read();
//判断是否读取到文件结束,如果读取到文件的最后会返回-1
while (c!=-1) {
//输出读取的这个字符
System.out.println((char)c);
//再读取下一个字符
c = fileReader.read();
}
} catch (Exception e) {
e.printStackTrace();
try {
if (fileReader != null) {
fileReader.close();
fileReader = null;
}
} catch (Exception e2) {
e2.printStackTrace();
}
throw new RuntimeException(e.getCause());
} finally {
try {
if (fileReader != null) {
fileReader.close();
fileReader = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 普通方法调用注解方法
*/
@Transactional
public void testDeleteUser(int id) {
deleteUserSimpleException2(id);
}
注解的用法
注解可以写在类声明上,也可以写在方法上,写在类声明上的时候表示调用该类的所有方法时都会启动事务,如果对个别方法有事务的个性化定制,则可以在方法上写注解,会按照就近原则执行注解
@Service
@Transactional(readOnly = true)
public class UserServiceImpl {
/**
* 测试非运行时异常,是否回滚
* @param id
*/
@Transactional(rollbackFor = Exception.class)
public void deleteUserSimpleException(int id) throws Exception {
FileReader fileReader = null;
try {
usersDao.deleteUserById(id);
//创建要读取的数据文件的文件对象 file
File file = new File("d:\\data.txt");
//创建要读取数据的输入流
fileReader = new FileReader(file);
//从输入流中读取一个字符;
int c = fileReader.read();
//判断是否读取到文件结束,如果读取到文件的最后会返回-1
while (c!=-1) {
//输出读取的这个字符
System.out.println((char)c);
//再读取下一个字符
c = fileReader.read();
}
} catch (Exception e) {
e.printStackTrace();
try {
if (fileReader != null) {
fileReader.close();
fileReader = null;
}
} catch (Exception e2) {
e2.printStackTrace();
}
} finally {
try {
if (fileReader != null) {
fileReader.close();
fileReader = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
注解属性(readOnly = true)
当注解中出现readOnly=true时,通常用于多表多表多表查询,数据库执行SQL时,会保证数据的一致性,查到的资料有说设置为true进行查询时,会提升性能,可能是我测试库数据量小的缘故,看不出区别
readOnly属性默认为false
https://www.cnblogs.com/milton/p/6046699.html