【问题标题】:Spring,Hibernate : Transactional read only equals to true is not workingSpring,Hibernate:事务性只读等于 true 不起作用
【发布时间】: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


【解决方案1】:

您的数据库是否更新与readOnly = true 无关,而仅与您的逻辑有关。 readOnly = true仅供事务管理使用。

【讨论】:

  • 你这是什么意思?我不明白您的回答如何有助于理解问题。
【解决方案2】:

您还必须将 createExcelSheetOutOfCanvas 设为 @Transactional(readOnly=true)

【讨论】:

    猜你喜欢
    • 2021-06-07
    • 1970-01-01
    • 2014-01-03
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多