Question

Spring configuration is done in code using annotations instead of XML file. I was trying to query some data and create new columns into ORACLE database through hibernate. My problem is that hibernate only generates SELECT queries, when I use sessionFactory.getCurrentSession().save(), hibernate doesn't generate INSERT queries. I think this could be a transaction issue but couldn't find where went wrong. I'll put code below and any help will be appreciated.

That's the main configuration class:

@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"));
            }
        };
    }
}

The Service class is an interface and I'll post the Service Impl class with the main method:

@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");
                }
            }
        }

    }
}

And here's the DAO impl class:

@Repository
public class RequirementCoverageDAOImpl implements RequirementCoverageDAO {

    @Autowired
    private SessionFactory sessionFactory;

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

Then Entity Class:

@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...
}

Hope I have put this clear and thanks for reading.

WietHibernateInterceptor is used to change schema dynamically:

@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;
    }

}
Was it helpful?

Solution

Hibernate will only generate the INSERT statements when it flushes the session. It will flush the session in the following scenarios

  1. When the @Transactional method ends,
  2. When it reaches its batch limit (if configured for batch inserts) or,
  3. When you call a query that it detects needs the session to be flushed eg you call a count() method. Hibernate would flush the transactional session and commit it so that count() returns an accurate value of records.

My only ideas is that an exception is being thrown that isn't being caught (but I would have expected it to show in your logs or your console) which is causing your transaction to roll back, or that for some reason the @Transactional session isn't being created or maintained or something.

1st thing I'd try, remove the Hibernate dialect from your hibernate properties. Hibernate does a fantastic job determining which dialect to use based on the driver you give it, and (especially with Oracle drivers) if you force it to use a different dialect it can produce strange errors.

2nd thing I'd try is to determine if there are any SQLException's being thrown by Hibernate. I'd assume that you have already turned on your hibernate logging using Log4J or whatever logging provider you are using. See if you can find an SQLException being thrown.

OTHER TIPS

Your @Transaction annotation says readOnly = true. That means only read is allowed in that transaction. Remove readOnly = true. Also look at the Spring Transaction management 9.5.6. Using @Transactional.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top