Giter Site home page Giter Site logo

vladmihalcea / hypersistence-optimizer Goto Github PK

View Code? Open in Web Editor NEW
305.0 305.0 43.0 258 KB

Hypersistence Optimizer allows you to get the most out of JPA and Hibernate. By scanning your application configuration and mappings, Hypersistence Optimizer can tell you what changes you need to do to speed up your data access layer.

Home Page: https://vladmihalcea.com/hypersistence-optimizer/

License: Apache License 2.0

Java 99.38% Batchfile 0.01% HTML 0.13% Scala 0.48%

hypersistence-optimizer's Introduction

Initial examples

My personal blog features some code examples that are included in this repository.

  • customer-lock - contains concurrency examples
  • db-facts - contains DB related examples
  • hibernate-facts - contains various Hibernate examples
  • misc - contains unclassified examples
  • mongodb-facts - contains MongoDB examples

Are you struggling with application performance issues?

Hypersistence Optimizer

Imagine having a tool that can automatically detect if you are using JPA and Hibernate properly. No more performance issues, no more having to spend countless hours trying to figure out why your application is barely crawling.

Imagine discovering early during the development cycle that you are using suboptimal mappings and entity relationships or that you are missing performance-related settings.

More, with Hypersistence Optimizer, you can detect all such issues during testing and make sure you don't deploy to production a change that will affect data access layer performance.

Hypersistence Optimizer is the tool you've been long waiting for!

Training

If you are interested in on-site training, I can offer you my High-Performance Java Persistence training which can be adapted to one, two or three days of sessions. For more details, check out my website.

Consulting

If you want me to review your application and provide insight into how you can optimize it to run faster, then check out my consulting page.

High-Performance Java Persistence Video Courses

If you want the fastest way to learn how to speed up a Java database application, then you should definitely enroll in my High-Performance Java Persistence video courses.

High-Performance Java Persistence Book

Or, if you prefer reading books, you are going to love my High-Performance Java Persistence book as well.

High-Performance Java Persistence book High-Performance Java Persistence video course

hypersistence-optimizer's People

Contributors

dependabot[bot] avatar nandorholozsnyak avatar sivaprasadreddy avatar vladmihalcea avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hypersistence-optimizer's Issues

NullPointerException is thrown when scanning a unidirectional association defined with HBM mappings

We are using hbm.xml for mapping our entities. After run optimizer I see a lot of exceptions in the console

io.hypersistence.optimizer.hibernate.scanner.Hibernate53MappingScanner.getManyToManyAssociationType(Hibernate53MappingScanner.java:587)

and

io.hypersistence.optimizer.hibernate.scanner.Hibernate53MappingScanner.isUnidirectionalOneToManyWithJoinColumn(Hibernate53MappingScanner.java:527)

In debug I see that CollectionPersister.getMappedByProperty is null

Check if a given Hibernate 4.1 feature is supported prior to using it

When running Hypersistence Optimizer with 4.1.0, there are several failures because those features were later added to the 4.1 branch.

[ERROR] symbol:   method getEntityPersisters()
[ERROR] location: interface org.hibernate.engine.spi.SessionFactoryImplementor

[ERROR] symbol:   class NClobTypeDescriptor
[ERROR] location: class io.hypersistence.optimizer.hibernate.scanner.Hibernate41MappingScanner

[ERROR] symbol:   class LongNVarcharTypeDescriptor
[ERROR] location: class io.hypersistence.optimizer.hibernate.scanner.Hibernate41MappingScanner

[ERROR] symbol:   method getBatchSize()
[ERROR] location: variable collectionPersister of type org.hibernate.persister.collection.AbstractCollectionPersister

[ERROR] symbol:   method isInitializeLazyStateOutsideTransactionsEnabled()
[ERROR] location: variable sessionFactorySettings of type org.hibernate.cfg.Settings

ConfigurationScanner propagates database connectivity issues and stops the bootstrap process

No test case is provided due to complexity of a project. This is happened when Hypersistence Optimizer was integrated into an existing project (with many-many-many hibernate problems).
This is the init code:
new HypersistenceOptimizer(new HibernateConfig(sf)).init();

And this is the error happened during the start:

ERROR Hypersistence Optimizer - The [org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider] encountered a problem when calling the [supportsAggressiveRelease] method.
java.lang.NullPointerException: null
	at org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider.supportsAggressiveRelease(AbstractMultiTenantConnectionProvider.java:63) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.internal.AbstractSessionImpl$ContextualJdbcConnectionAccess.supportsAggressiveRelease(AbstractSessionImpl.java:447) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.determineConnectionReleaseMode(LogicalConnectionImpl.java:126) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.<init>(LogicalConnectionImpl.java:108) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.<init>(LogicalConnectionImpl.java:87) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.<init>(JdbcCoordinatorImpl.java:114) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.<init>(TransactionCoordinatorImpl.java:89) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.internal.SessionImpl.<init>(SessionImpl.java:258) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl.openSession(SessionFactoryImpl.java:1589) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at org.hibernate.internal.SessionFactoryImpl.openTemporarySession(SessionFactoryImpl.java:1003) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate43ConfigurationScanner$DatabaseMetadataContext.<init>(Hibernate43ConfigurationScanner.java:386) ~[hypersistence-optimizer-1.2.0-SNAPSHOT.jar:?]
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate43ConfigurationScanner.<init>(Hibernate43ConfigurationScanner.java:87) ~[hypersistence-optimizer-1.2.0-SNAPSHOT.jar:?]
	at io.hypersistence.optimizer.hibernate.Hibernate43Service.getScanners(Hibernate43Service.java:47) ~[hypersistence-optimizer-1.2.0-SNAPSHOT.jar:?]
	at io.hypersistence.optimizer.core.service.DefaultService.getHibernateScanners(DefaultService.java:73) ~[hypersistence-optimizer-1.2.0-SNAPSHOT.jar:?]
	at io.hypersistence.optimizer.core.service.DefaultService.getScanners(DefaultService.java:54) ~[hypersistence-optimizer-1.2.0-SNAPSHOT.jar:?]
	at io.hypersistence.optimizer.HypersistenceOptimizer.init(HypersistenceOptimizer.java:73) ~[hypersistence-optimizer-1.2.0-SNAPSHOT.jar:?]

Best of luck, we were not able to try this tool because of the issue.

Add an ElementCollectionEvent that is triggered when detecting that a List or an array is used as an @ElementCollection

I got following Event:

00:10:11.005 [pool-1-thread-1] [error] Hypersistence Optimizer - CRITICAL - ElementCollectionEvent - The [preferences] element collection in the [model.User] entity does not render very efficient SQL statements. Consider using a bidirectional one-to-many association instead. For more info about this event, check out this User Guide link - https://vladmihalcea.com/hypersistence-optimizer/docs/user-guide/#ElementCollectionEvent

but preferences looks like this (please ignore EnumType.STRING - it's really intentional):

  @Enumerated(EnumType.STRING)
  @ElementCollection(fetch = FetchType.LAZY)
  @Column(name = "preference", nullable = false)
  @CollectionTable(name = "user_preferences",
    joinColumns = @JoinColumn(name = "user_id", nullable = false)
  )
  private Set<Preference> preferences = new HashSet<>();

where Preference is of course simple enum.
I've read this article: https://vladmihalcea.com/how-to-optimize-unidirectional-collections-with-jpa-and-hibernate/ but it just mentions that Hibernate supports three data mapping types: basic (e.g String, int), Embeddable and Entity. but describes only how to make relation out of Embeddable and Entity.

  1. If there is no need to make relation out of enum, then this Event is invalid
  2. If it's still a mistake, then please mention this in your article

[Improvement] Mention PlayFramework in UserGuide

For PlayFramework, configuration is a little bit more tricky, therefore I want to share it.
If you don't want to include in doc - I'm fine with closing this issue.

  @Inject
  private JPAApi jpaApi;

  @Test
  public void testOptimizer() {
    jpaApi.withTransaction(em -> {
      final ListEventHandler listEventListener = new ListEventHandler();
      new HypersistenceOptimizer(
          new JpaConfig(em.getEntityManagerFactory())
                      .setEventHandler(new ChainEventHandler(
                              Arrays.asList(
                                      listEventListener,
                                      LogEventHandler.INSTANCE
                              )
                      ))
      ).init();

      assertEquals(0, listEventListener.getEvents());
      return true;
    });
  }

NullPointerException is thrown when scanning a composite entity identifier

When using 1.0.1-SNAPSHOT on one of our projects we get the following error:

10:47:12.159 ERROR Hypersistence Optimizer - The [io.hypersistence.optimizer.hibernate.scanner.Hibernate53MappingScanner$4] encountered a problem when calling the [execute] method.
java.lang.NullPointerException: null
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate53MappingScanner$4.execute(Hibernate53MappingScanner.java:203)
	at io.hypersistence.optimizer.core.action.ActionExecutor.execute(ActionExecutor.java:70)
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate53MappingScanner.scanEntityIdentifier(Hibernate53MappingScanner.java:171)
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate53MappingScanner.access$200(Hibernate53MappingScanner.java:76)
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate53MappingScanner$1.execute(Hibernate53MappingScanner.java:100)
	at io.hypersistence.optimizer.core.action.ActionExecutor.execute(ActionExecutor.java:70)
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate53MappingScanner.scan(Hibernate53MappingScanner.java:90)
	at io.hypersistence.optimizer.HypersistenceOptimizer.init(HypersistenceOptimizer.java:74)
	at our.test.HypersistenceOptimizerTest.testOptimizer(HypersistenceOptimizerTest.java:42)

This happens between some events, so it does not stop the optimizer, but it seems this swallows some possible events.

UUID types are handled as "large objects"

When I run hypersistence-optimizer on my project, it printed this warning:

00:10:10.852 [pool-1-thread-1] [warn] Hypersistence Optimizer - MAJOR - LargeColumnEvent - The [uuid] attribute in the [model.User] entity is mapped to a large column type. You should use the @DynamicUpdate annotation so that the UPDATE statement contains only the columns that have been modified by the currently running Persistence Context. For more info about this event, check out this User Guide link - https://vladmihalcea.com/hypersistence-optimizer/docs/user-guide/#LargeColumnEvent

however, User.uuid looks like this:

  @NotNull
  @Column(name = "uuid", nullable = false, unique = true)
  private UUID uuid = UUID.randomUUID();

I'm using PostgreSQL which handles UUIDs just fine (https://www.postgresql.org/docs/9.1/datatype-uuid.html), therefore I'm not sure if this warning is valid

Add support for detecting the schema generation configuration properties

Using configuration properties like:

  • hibernate.hbm2ddl.auto
  • javax.persistence.schema-generation.database.action
  • javax.persistence.schema-generation.scripts.action

to manage the database schema is not recommended. You should use an automatic migration schema tool instead (e.g. Flyway, Liquibase).

Missing the list of features (analyzed problems) and Javadocs

Hi Vlad,

There are multiple things I'd like to mention with regard to the documentation:

  1. I was not able to find the list of all problems that Hypersistence Optimizer is able to detect. It would be good to have it and maintain updated for each new version of the tool.
  2. I did not find Javadocs for the API privided by the tool. All the current docs mentions is "check your application logs", but what logging library is used by the tool, how to we feed it the logging configs from our application? Someone may also want to grab the problems programmatically and log them explicitly somewhere separately without relying on the tool logging.
  3. Is my understanding correct that Hypersistence Optimizer is a dynamic analyzer? I.e. after calling the HypersistenceOptimizer.init method (which probably mainly registers Hibernate listeners?), one need to actually use Hibernate ORM to generate the events which are analyzed by the tool. In other words calling only new HypersistenceOptimizer(new HibernateConfig(sessionFactory)).init() does not produce the report with problems. If yes, It would be great to have it explicitly explained in the docs. If no, it would still be great to have a quick explanation of what to expect from the tool: whether it does a static or dynamic analysis.

[Feature request] Check for missing indexes

In situation like this (please ignore EnumType.STRING - it's really intentional):

  @Enumerated(EnumType.STRING)
  @ElementCollection(fetch = FetchType.LAZY)
  @Column(name = "preference", nullable = false)
  @CollectionTable(name = "user_preferences",
    joinColumns = @JoinColumn(name = "user_id", nullable = false)
  )
  private Set<Preference> preferences = new HashSet<>();

but it's very probable, that we also need an index here:
indexes = @Index(name = "idx_user_preferences_user_id", columnList = "user_id")

Maybe in such obvious situations hypersistence-optimizer could point that out as well?

License cannot be loaded in an OSGi container

While optimizer startup process (trial version) there occurs the following error:

org.apache.karaf.features.internal.util.MultiException: Error restarting bundles:
Activator start error in bundle my-bundle [57].
at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:1004)
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.doProvision(FeaturesServiceImpl.java:1025)
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.lambda$doProvisionInThread$13(FeaturesServiceImpl.java:964)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Suppressed: org.osgi.framework.BundleException: Activator start error in bundle my-bundle [57].
		at org.apache.felix.framework.Felix.activateBundle(Felix.java:2290)
		at org.apache.felix.framework.Felix.startBundle(Felix.java:2146)
		at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998)
		at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:984)
		at org.apache.karaf.features.internal.service.BundleInstallSupportImpl.startBundle(BundleInstallSupportImpl.java:161)
		at org.apache.karaf.features.internal.service.FeaturesServiceImpl.startBundle(FeaturesServiceImpl.java:1116)
		at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:996)
		... 6 more
Caused by: java.lang.ExceptionInInitializerError
		at io.hypersistence.optimizer.core.License.getProperties(License.java:135)
		at io.hypersistence.optimizer.core.License.isTrialVersion(License.java:110)
		at io.hypersistence.optimizer.HypersistenceOptimizer.printBanner(HypersistenceOptimizer.java:104)
		at io.hypersistence.optimizer.HypersistenceOptimizer.init(HypersistenceOptimizer.java:72)
		at MyApplication.start(MyApplication.java:493)
		at MyApplication.startApplication(ApplicationLauncher.java:116)
		at MyApplication.launch(ApplicationLauncher.java:45)
		at Activator.start(Activator.java:47)
		at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:697)
		at org.apache.felix.framework.Felix.activateBundle(Felix.java:2240)
		... 12 more
Caused by: java.lang.NullPointerException
		at io.hypersistence.optimizer.util.FileUtils.readBytesFromStream(FileUtils.java:95)
		at io.hypersistence.optimizer.core.License$LicenseKey.<clinit>(License.java:72)
		... 22 more

The optimizer jar is embedded in an OSGi bundle who's running in a Karaf container. It seems that the application can not find the license file who's inside the embedded jar. Wrapping the optimizer jar to a stand-alone bundle is also not working.

Optional OneToOne should not be used with MapsId

Let's say we have two entities: User and ActivationToken
ActivationToken is created together with User creation, but it must survive (for legal purposes) after User deletion. Therefore:

CREATE TABLE users (
  id BIGINT PRIMARY KEY,
  email VARCHAR(254)
);

CREATE TABLE activation_tokens (
  id BIGINT PRIMARY KEY,
  user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
  ip VARCHAR(20)
);

And

class User {
  @OneToOne(mappedBy = "user", fetch = FetchType.LAZY, optional = true, orphanRemoval = false,
      cascade = {CascadeType.PERSIST, CascadeType.DETACH})
  private ActivationToken token;
}

class ActivationToken {
  @JoinColumn(name = "user_id", nullable = true, unique = false)
  @OneToOne(fetch = FetchType.LAZY, optional = true)
  private User user;
}

I think that in such situation MapsId should not be used because we can not SET NULL primary key, and having id withoult FOREIGN KEY constraint doesn't look good either, but Hypersistence Optimizer throws:

21:24:18.894 [pool-1-thread-1] [error] Hypersistence Optimizer - CRITICAL - OneToOneWithoutMapsIdEvent - The [user] one-to-one association in the [model.ActivationToken] entity is using a separate Foreign Key to reference the parent record. Consider using @MapsId so that the identifier is shared with the parent row. For more info about this event, check out this User Guide link - https://vladmihalcea.com/hypersistence-optimizer/docs/user-guide/#OneToOneWithoutMapsIdEvent

NullPointerException: null at Hibernate52MappingScanner

After providing some analysis of MINOR and CRITICAL problems, the optimizer ends up throwing the following error.

java.lang.NullPointerException: null
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate52MappingScanner$4.execute(Hibernate52MappingScanner.java:203) ~[hypersistence-optimizer-1.0.1-SNAPSHOT.jar:na]
	at io.hypersistence.optimizer.core.action.ActionExecutor.execute(ActionExecutor.java:70) [hypersistence-optimizer-1.0.1-SNAPSHOT.jar:na]
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate52MappingScanner.scanEntityIdentifier(Hibernate52MappingScanner.java:171) [hypersistence-optimizer-1.0.1-SNAPSHOT.jar:na]
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate52MappingScanner.access$200(Hibernate52MappingScanner.java:76) [hypersistence-optimizer-1.0.1-SNAPSHOT.jar:na]
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate52MappingScanner$1.execute(Hibernate52MappingScanner.java:100) [hypersistence-optimizer-1.0.1-SNAPSHOT.jar:na]
	at io.hypersistence.optimizer.core.action.ActionExecutor.execute(ActionExecutor.java:70) [hypersistence-optimizer-1.0.1-SNAPSHOT.jar:na]
	at io.hypersistence.optimizer.hibernate.scanner.Hibernate52MappingScanner.scan(Hibernate52MappingScanner.java:90) [hypersistence-optimizer-1.0.1-SNAPSHOT.jar:na]
	at io.hypersistence.optimizer.HypersistenceOptimizer.init(HypersistenceOptimizer.java:74) [hypersistence-optimizer-1.0.1-SNAPSHOT.jar:na]

@DynamicUpdate should be considered in the LargeColumnEvent

I have entity:

@Getter
@Setter
@Entity
@DynamicUpdate
@Table(name = "user")
public class User {
  @Lob
  @NotNull
  @Column(name = "photo_oid", nullable = false, columnDefinition="OID")
  private byte[] photo;
}

but Hypersistence Optimizer complains:

19:47:02.950 [pool-1-thread-1] [warn] Hypersistence Optimizer - MAJOR - LargeColumnEvent - The [photo] attribute in the [model.User] entity is mapped to a large column type. You should use the @DynamicUpdate annotation so that the UPDATE statement contains only the columns that have been modified by the currently running Persistence Context. For more info about this event, check out this User Guide link - https://vladmihalcea.com/hypersistence-optimizer/docs/user-guide/#LargeColumnEvent

Add support for detecting the "hibernate.enable_lazy_load_no_trans" configuration property

The "hibernate.enable_lazy_load_no_trans" configuration property should not be enabled as it causes Hibernate to load lazy associations even after the original Session got closed. This mechanism is inefficient since it requires a new database transaction and connection to fetch every lazy association that is being accessed outside the original and now closed Hibernate Session.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.