Bhuwan Prasad Upadhyay
Bhuwan Prasad Upadhyay

Reputation: 3056

How to truncate all table data using hibernate configuration?

How to truncate all table data using hibernate configuration?

For example hibernate.hbm2ddl.auto=validate will check validity of entity model in database. Now I need an option to truncate all tables during startup of an application.

Upvotes: 2

Views: 6330

Answers (2)

mmdemirbas
mmdemirbas

Reputation: 9158

It seems that Integrator interface is changed. I re-wrote the answer for the new interface:

static final class TruncatorIntegrator implements org.hibernate.integrator.spi.Integrator {

    @Override
    public void integrate(Metadata metadata,
                          SessionFactoryImplementor sessionFactory,
                          SessionFactoryServiceRegistry serviceRegistry) {
        try (Session session = sessionFactory.openSession()) {
            session.doWork(connection -> {
                try (PreparedStatement preparedStatement = connection.prepareStatement("SET FOREIGN_KEY_CHECKS = 0;")) {
                    preparedStatement.executeUpdate();
                    System.out.printf("Disabled foreign key checks%n");
                } catch (SQLException e) {
                    System.err.printf("Cannot disable foreign key checks: %s: %s%n", e, e.getCause());
                }

                metadata.collectTableMappings().forEach(table -> {
                    String tableName = table.getQuotedName();
                    try (PreparedStatement preparedStatement = connection.prepareStatement("TRUNCATE TABLE " + tableName)) {
                        preparedStatement.executeUpdate();
                        System.out.printf("Truncated table: %s%n", tableName);
                    } catch (SQLException e) {
                        System.err.printf("Couldn't truncate table %s: %s: %s%n", tableName, e, e.getCause());
                    }
                });

                try (PreparedStatement preparedStatement = connection.prepareStatement("SET FOREIGN_KEY_CHECKS = 1;")) {
                    preparedStatement.executeUpdate();
                    System.out.printf("Enabled foreign key checks%n");
                } catch (SQLException e) {
                    System.err.printf("Cannot enable foreign key checks: %s: %s%n", e, e.getCause());
                }
            });
        }
    }

    @Override
    public void disintegrate(SessionFactoryImplementor sessionFactory,
                             SessionFactoryServiceRegistry serviceRegistry) {
    }
}

Usage:

BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder().applyIntegrator(new TruncatorIntegrator()).build();
StandardServiceRegistry registry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry).build();
SessionFactory sessionFactory = new Configuration().buildSessionFactory(registry);

Upvotes: 3

Tobias Liefke
Tobias Liefke

Reputation: 9022

Hibernate does only have the possibility to recreate the schema using hibernate.hbm2ddl.auto=create or hibernate.hbm2ddl.auto=create-drop

Another option is to create an import.sql in the root of your classpath that contains the desired TRUNCATE statements. That file is executed automatically on startup (after validation). In that case you will have to keep the table names in sync with your database.

The last possible solution is to have your own "truncate implementation" at startup, for example as Integrator:

public class Truncator implements Integrator {
    public void integrate(final Configuration config, 
            final SessionFactoryImplementor sessionFactory,
            final SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {

        // Create session
        Session session = sessionFactory.openSession();

        try {

            // Find all involved tables
            for (final ClassMetadata metadata : sessionFactory.getAllClassMetadata().values()) {
                final String tableName = ((AbstractEntityPersister) metadata).getTableName();
                if (tableName != null) {
                    session.createSQLQuery("TRUNCATE TABLE " + tableName).executeUpdate();
                }
            }

            final Map<String, CollectionMetadata> allCollectionMetadata = sessionFactory.getAllCollectionMetadata();
            for (final CollectionMetadata metadata : allCollectionMetadata.values()) {
                final String tableName = ((AbstractCollectionPersister) metadata).getTableName();
                if (tableName != null) {
                    session.createSQLQuery("TRUNCATE TABLE " + tableName).executeUpdate();
                }
            }
        } finally {
            session.close();
        }
    }
}

An Integrator has to be declared in META-INF/services/org.hibernate.integrator.spi.Integrator, which just contains the full qualified class name.

If you use enhanced features (like Envers), you will need to find more table names - so this is more a proof of concept for simple data models.

Upvotes: 3

Related Questions