java - Spring+Hibernate集成: Transaction Manager doesn't work using @Transactional

标签 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 类是一个接口(interface),我将发布带有 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;
    }

}

最佳答案

Hibernate 仅在刷新 session 时生成 INSERT 语句。在以下场景中它将刷新 session

  1. @Transactional方法结束时,
  2. 当达到批量限制时(如果配置为批量插入),或者,
  3. 当您调用一个查询时,它检测到需要 session 刷新例如您调用 count() 方法。 Hibernate 会刷新 事务 session 并提交它,以便 count() 返回一个 记录的准确值(value)。

我唯一的想法是抛出了一个未被捕获的异常(但我希望它会显示在您的日志或控制台中),这会导致您的事务回滚,或者由于某种原因@Transactional session 没有被创建或维护或其他什么。

我尝试的第一件事是从 hibernate 属性中删除 hibernate 方言。 Hibernate 在根据您提供的驱动程序确定要使用哪种方言方面做得非常出色,并且(尤其是 Oracle 驱动程序)如果您强制它使用不同的方言,它可能会产生奇怪的错误。

我要尝试的第二件事是确定 Hibernate 是否抛出任何 SQLException。我假设您已经使用 Log4J 或您正在使用的任何日志记录提供程序打开了 hibernate 日志记录。查看是否可以发现抛出 SQLException

关于java - Spring+Hibernate集成: Transaction Manager doesn't work using @Transactional,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23416657/

相关文章:

java - 如何为 Java HTTPS *服务器*配置 SSL 密码套件?

java - 监控硬盘空间...如何实时显示信息?

java - 从外部 jar 加载一个类及其所有组件

Linux Cronjob 调度问题

java - 与 Oracle Internet Directory 的连接池

java - Android在更新后仍然坏了

java - Android 中使用 9 个补丁水平和/或垂直居中

java - 使用 JdbcTemplate 插入多行

java - Spring - 具有 hibernate 数据库插入功能的 mvc(SimpleFormController)

Oracle CONNECT BY - 仅返回第一级项目