【发布时间】:2016-02-18 13:57:31
【问题描述】:
我正在开发一个 Spring-MVC 项目,在该项目中我使用注释 @Transactional(readOnly=true) 调用某些方法。不幸的是,即使这样做了,数据库的内容也在更新。不知道怎么样。我究竟做错了什么?我们有这个错误有一段时间了,只是不知道这会触发数据库中的更改,因为我们完全忽略了它,因为注释明确表示不要编辑,但我们错了。
项目属性:
<properties>
<java-version>1.8</java-version>
<org.springframework-version>4.1.6.RELEASE</org.springframework-version>
<org.aspectj-version>1.7.4</org.aspectj-version>
<org.slf4j-version>1.7.5</org.slf4j-version>
<hibernate.version>4.3.9.Final</hibernate.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<springsecurity.version>4.0.1.RELEASE</springsecurity.version>
<spring-platform.version>1.1.3.RELEASE</spring-platform.version>
<jetty.version>9.2.9.v20150224</jetty.version>
</properties>
<parent>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>1.1.3.RELEASE</version>
<relativePath />
</parent>
代码:
@Override
public byte[] createExcelSheetOutOfCanvas(int canvasId) {
String str = new BigInteger(130, random).toString(32);
List<GroupSection> groupSectionList = this.groupSectionService.listGroupSectionByCanvasid(canvasId, false);
try {
Workbook workbook = new HSSFWorkbook();
Sheet sheet = workbook.createSheet();
int rowCount = 0;
Row initialRow = sheet.createRow(rowCount);
writeNames(initialRow);
for (GroupSection groupSection : groupSectionList) {
rowCount++;
Row row = sheet.createRow(++rowCount);
writeSectionRow(row, groupSection.getMsectionname());
List<GroupNotes> groupNotesList = this.groupNotesDAO.listGroupNotesBySectionId(groupSection.getMsectionid());
for (GroupNotes note : groupNotesList) {
row = sheet.createRow(++rowCount);
writeBook(note, row);
}
}
try (FileOutputStream outputStream = new FileOutputStream("/home/deploy/excel/" + str + ".xls")) {
workbook.write(outputStream);
Path path = Paths.get("/home/deploy/excel/" + str + ".xls");
return Files.readAllBytes(path);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
GroupSectionServiceImpl :
@Service
@Transactional
public class GroupSectionServiceImpl implements GroupSectionService {
private final GroupSectionDAO groupSectionDAO;
@Autowired
public GroupSectionServiceImpl(GroupSectionDAO groupSectionDAO) {
this.groupSectionDAO = groupSectionDAO;
}
@Override
@org.springframework.transaction.annotation.Transactional(readOnly = true)
public List<GroupSection> listGroupSectionByCanvasid(int mcanvasid, boolean masterSectionFlag) {
List<GroupSection> groupSectionList = this.groupSectionDAO.listGroupSectionByCanvasid(mcanvasid);
// Other method code
}
GroupSectionDAOImpl :
@Repository
@Transactional
public class GroupSectionDAOImpl implements GroupSectionDAO {
private final SessionFactory sessionFactory;
@Autowired
public GroupSectionDAOImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
@Transactional(readOnly = true)
public List<GroupSection> listGroupSectionByCanvasid(int mcanvasid) {
Session session = this.sessionFactory.getCurrentSession();
org.hibernate.Query query = session.createQuery("From GroupSection as msection where " +
"msection.currentcanvas.mcanvasid=:mcanvasid and msection.sectionDisabled=false and msection.sectionInActive=false");
query.setParameter("mcanvasid", mcanvasid);
return query.list();
}
}
即使,毕竟,这 readOnly= true。当我调用 createTheExcel 方法时,如何覆盖数据库中的值。
控制器方法:
@RequestMapping(value = "/downloadexcel/{canvasid}")
public void downloadExcelSheet(@PathVariable("canvasid") int canvasId, HttpServletResponse response) {
try {
response.setContentType("application/octet-stream");
GroupCanvas groupCanvas = this.groupCanvasService.getCanvasById(canvasId);
if (!(groupCanvas == null)) {
byte[] excelSheet = this.groupNotesService.createExcelSheetOutOfCanvas(canvasId);
response.setHeader("Content-Disposition", "attachment; filename=\"" + groupCanvas.getMcanvasname() + ".xls" + "\"");
response.setContentLength(excelSheet.length);
FileCopyUtils.copy(excelSheet, response.getOutputStream());
response.flushBuffer();
}
} catch (IOException e) {
e.printStackTrace();
}
}
【问题讨论】:
-
为什么不应该这样做。事务结束后只读不再有效。如果已经有一个正在进行的(非只读)事务,则忽略只读部分。
-
@M.Deinum :但是我没有调用任何代码来更新值,我只是调用代码来列出从 DAO 方法中可以看到的部分。
-
如果您正在更改内容,只要您在事务中,这些内容就会自动持久化。您无需为托管实体显式调用数据访问代码。
-
一定有什么东西触发了对您的对象的更改。如果您不更改任何内容,则不会将任何内容保存到数据库中。所以在这个流程中一定有一些东西正在改变东西。尝试使最外层的方法具有事务性和只读性。这应该会导致错误。
-
那么在 create 方法或它调用的方法中一定有一些东西可以修改实体,可能是具有不需要的副作用的 getter。
标签: java spring hibernate spring-mvc transactional