Spring + Hibernate集成:事务管理器不使用@Transactional

时间:2014-05-01 21:09:35

标签: java spring oracle hibernate transactions

Spring配置是使用注释而不是XML文件在代码中完成的。我试图通过hibernate查询一些数据并在ORACLE数据库中创建新列。我的问题是hibernate只生成SELECT查询,当我使用sessionFactory.getCurrentSession()。save()时,hibernate不生成INSERT查询。我认为这可能是一个交易问题,但无法找到出错的地方。我将把代码放在下面,任何帮助将不胜感激。

这是主要的配置类:

@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableTransactionManagement
@PropertySource({ "file:src/main/resources/Config/database.properties" })
public class QCWordImportExportTool {

    @Autowired
    private Environment env;

    @Autowired
    private WietHibernateInterceptor wietHibernateInterceptor;

    /**
     * main, says it all! :)
     * 
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(QCWordImportExportTool.class, args);
    }

    @Bean
    MultipartConfigElement multipartConfigElement() {
        MultiPartConfigFactory factory = new MultiPartConfigFactory();
        factory.setMaxFileSize("10MB");
        factory.setMaxRequestSize("1024KB");
        return factory.createMultipartConfig();
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(restDataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.ciena.prism.almtools.wiet" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        sessionFactory.setEntityInterceptor(this.wietHibernateInterceptor);

        return sessionFactory;
    }

    @Bean
    public DataSource restDataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));

        return dataSource;
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());

        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties hibernateProperties() {
        return new Properties() {
            private static final long serialVersionUID = 1L;

            {
                setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
                setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
                setProperty("hibernate.globally_quoted_identifiers",
                            env.getProperty("hibernate.globally_quoted_identifiers"));
                setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
                setProperty("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
            }
        };
    }
}

Service类是一个接口,我将使用main方法发布Service Impl类:

@Service
@Transactional(readOnly = true)
public class ImportExportManagerImpl implements ImportExportManager {
    private TestFacade testFacade;
    private TestFolderFacade testFolderFacade;
    private UserManager userManager;

    @Autowired
    SessionFactory sessionFactory;

    @Autowired
    RequirementCoverageDAO requirementCoverageDao;

    @Autowired
    RequirementDAO requirementDao;

    @Autowired
    WietHibernateInterceptor wietHibernateInterceptor;

    @Autowired
    public ImportExportManagerImpl(TestFacade testFacade, TestFolderFacade testFolderFacade,
                                   UserManager userManager) {
        this.testFacade = testFacade;
        this.testFolderFacade = testFolderFacade;
        this.userManager = userManager;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ciena.prism.almtools.wiet.managers.ImportExportManager#importTestCases(java.lang.String,
     * java.lang.String, java.util.List)
     */
    @Override
    @Transactional(readOnly = false)
    public void importTestCases(String domain, String project, List<TestCase> testCases)
            throws RequestFailureException, RESTAPIException, InvalidDataException {
        System.out.println("Start to import...");

        setDBSchema(domain, project);

        for (TestCase testCase : testCases) {
            TestFolder testFolder = retrieveTestFolderFromPath(domain, project, testCase.getFolderPath());
            Test test = new Test(testCase, testFolder);
            ALMEntity almEntity = new ALMEntity(test);

            Test existingTest = getExistingTest(domain, project, test);
            if (existingTest == null) {
                existingTest = new Test(testFacade.createEntity(domain, project, almEntity));
            } else {
                testFacade.updateEntity(domain, project, existingTest.getId(), almEntity);
            }
            System.out.println(existingTest.getName());

            /* Create Requirement_Coverage using test and doors_object_ids */
            List<String> doors_object_ids = testCase.getDoors_object_ids();

            for (String doors_object_id : doors_object_ids) {
                List<Requirement> requirementList = requirementDao.findAllFromDoorsobjectid(doors_object_id);

                if (requirementList != null && !requirementList.isEmpty()) {
                    System.out.println("*************Requirement:" + doors_object_id + " not null");
                    /* check if the coverage already exist */
                    Requirement requirement = requirementList.get(0);
                    List<RequirementCoverage> requirementCoverageList = requirementCoverageDao
                            .findAllFromTestIdReqId(Integer.parseInt(existingTest.getId()),
                                                    requirement.getReqId());
                    if (requirementCoverageList == null || requirementCoverageList.isEmpty()) {
                        System.out.println("**************Creating new requirement coverage");

                        /* create a new Requirement Coverage Object */
                        RequirementCoverage requirementCoverage = new RequirementCoverage();
                        requirementCoverage.setRequirement(requirement);
                        requirementCoverage.setEntityId(Integer.parseInt(existingTest.getId()));
                        requirementCoverage.setEntityType("TEST");
                        requirementCoverageDao.create(requirementCoverage);
                        System.out.println("*********assigned DB id: " + requirementCoverage.getId());
                    }

                } else {
                    throw new InvalidDataException("Requirement Management Tool Id : " + doors_object_id
                            + " doesn't exist in QC");
                }
            }
        }

    }
}

这是DAO impl课程:

@Repository
public class RequirementCoverageDAOImpl implements RequirementCoverageDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public Integer create(RequirementCoverage requirementCoverage) {
        return (Integer) sessionFactory.getCurrentSession().save(requirementCoverage);
    }
}

然后是实体类:

@Entity
@Table(schema = "wiet", name = "REQ_COVER")
public class RequirementCoverage {

    @SuppressWarnings("unused")
    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name = "req_cover_id_gen", sequenceName = "wiet.REQ_COVER_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "req_cover_id_gen")
    @Column(name = "RC_ITEM_ID", unique = true, nullable = false)
    private Integer id;

    @OneToOne
    @JoinColumn(name = "RC_REQ_ID", nullable = false)
    private Requirement requirement;

    @Column(name = "RC_ENTITY_ID", nullable = false)
    private Integer entityId;

    @Column(name = "RC_ENTITY_TYPE", nullable = false)
    private String entityType;

    ....setters and gettters...
}

希望我已经说清楚并感谢阅读。

WietHibernateInterceptor用于动态更改架构:

@Component
public class WietHibernateInterceptor extends EmptyInterceptor {

    private static final long serialVersionUID = 1L;
    private String schema;

    @Override
    public String onPrepareStatement(String sql) {
        String prepedStatement = super.onPrepareStatement(sql);

        if (prepedStatement.toLowerCase().contains("wiet.".toLowerCase())) {
            /* As @SequenceGenerator ignores schema, sequence squery is manually set to be correct */
            prepedStatement = prepedStatement.replaceAll("`", "\"");
            prepedStatement = prepedStatement.replaceAll("wiet.", this.schema + "\".\"");
        }
        /* Change schema dynamically */
        prepedStatement = prepedStatement.replaceAll("wiet", this.schema);
        return prepedStatement;
    }

    public String getSchema() {
        return schema;
    }

    public void setSchema(String schema) {
        this.schema = schema;
    }

}

2 个答案:

答案 0 :(得分:0)

您的@Transaction注释表示readOnly = true。这意味着在该事务中只允许读取。删除readOnly = true。 另请参阅Spring Transaction management 9.5.6。使用@Transactional。

答案 1 :(得分:0)

Hibernate只会在刷新会话时生成INSERT语句。它将在以下场景中刷新会话

  1. @Transactional方法结束时,
  2. 达到批次限制时(如果配置为批量插入)或
  3. 当您调用它检测到的查询需要会话时 刷新,例如你调用count()方法。 Hibernate将刷新 事务会话并提交它,以便count()返回一个 准确的记录价值。
  4. 我唯一的想法是抛出一个未被捕获的异常(但我希望它会在您的日志或控制台中显示)导致您的事务回滚,或者由于某种原因@Transactional会话未被创建或维护或其他内容。

    我尝试的第一件事就是从你的hibernate属性中删除Hibernate方言。 Hibernate根据您提供的驱动程序确定使用哪种方言,并且(特别是使用Oracle驱动程序)如果强制它使用不同的方言,它会产生奇怪的错误。

    我要尝试的第二件事是确定Hibernate是否抛出任何SQLException。我假设您已经使用Log4J或您正在使用的任何日志记录提供程序打开了您的休眠日志记录。看看你是否能找到SQLException被抛出。