pvillega’s posterous

pvillega’s posterous

Pere Villega  //  Born in Barcelona, living in Dublin, and tagged as geek since youth. Developer in the path to becoming a software architect. I swear this is not a proper blog :)

Feb 16 / 7:42am

EJB 3.0 Performance (basic)

This page contains some basic information about Performance and Scalability with EJB 3.0. It only gives basic information, for more details about life cycle and other functionalities check the EJB 3.0 reference or some book like EJB3 in Action

Entity locking

JPA entities work directly with the database. On any medium-sized application our database is prone to concurrency errors due to users modifying the data while other transactions are in progress. RDBMS vendors implement several procedures to ensure the integrity of transactions and JPA makes use of those procedures to ensure data consistency. From all the different solutions available, JPA only requires optimistic locking using entity versioning. Some JPA implementations may provide other locking mechanisms but they will be vendor specific.

Optimistic locking in JPA is based on an additional column in each table that stores a version number for the entity. That value is marked with the @Version annotation and is managed by the JPA provider, so we can ignore it in the application. The downside of this mechanism is that our table needs an additional column of int or long type to be able to process the locks, but in exchange we will be notified (with an exception) if there is some data inconsistency, so we can tell the user and show the proper data. An example of an entity implementing optimistic locking:

@Entity
@Table(name="ITEMS")
public class Item implements Serializable{

@Id
@Column(name ="ITEM_ID")
protected Long itemId;

//more data
@Version //optimistic locking value
@Column(name ="OPT_LOCK")
private Long version;
}

This mechanism is used automatically when the Entity Manager detects the existence of a @Version field, but you can request a read or write locking for an entity. This is rarely used due to the performance penalties it may create, but it's useful in situations like creating a report, when you need a read lock to avoid other users changing the contents of the report.

Entity performance

Usually bad performance in a JEE application is due to issues with the persistence layer. The wrong database structure or bad tuning can degrade the performance by a factor of 2 or even 10. Next there's a non-exhaustive list of tricks to improve entity performance:

  • Merge tables: don't try to follow the normalization rules too strictly. If you find 1-to-1 relations or data that's retrieved always (or most of the time) together, merge the tables. You can then create an @Embedded object inside the main entity to maintain the logical separation, but you have avoided a join every time you retrieve that data.
  • Divide tables: this may seem a contradiction of the previous point, but it's not. Sometimes you have a table with data that you don't use too often. That's the case when you have some fields marked as @Lob (lazy loading). If those fields include BLOB probably you are better creating a new table with a 1-to-1 relationship and lazy loading that new entity. The reason is that lazy loading of BLOB objects is not mandatory on EJB 3 and for fields you won't use frequently that can be a huge penalty for the entity.
  • Choose the right inheritance strategy: JPA supports 3 inheritance mapping strategies. If possible try to use the single-table strategy as it has no need of joins, improving the overall performance
  • Properly size the connection pool: JPA uses JDBC to connect to the database, so strategies that improve JDBC performance also have an impact on JPA. Is important to check you pool is big enough to serve as many users as possible, to avoid delays due to users waiting for a free connection.
  • Cache statements: most vendors support SQL caching, reducing the time needed to answer a select query, but JDBC will only catch queries that use parameter binding so try to build the queries that way.
  • Use named queries: use named queries (annotation @NamedQuery) to enhance even more the performance of your queries. They are cached and can receive parameters but suffer of extra optimization which makes them better than normal queries that use parameter binding.
  • Avoid read-only transactions: by default a session bean has a "Required" transaction attribute. Establishing a transaction environment is expensive so if your method won't update the database set the transaction to Not_Suported for better performance.
  • Chang fetch type: by default JPA does a lazy loading for one-to-many or many-to-many relations and eager loading for one-to-one and many-to-one relations. If you don't need the data right away, switch to lazy loading when possible as it uses queries with less joins that are easily cacheable.
  • Be careful with locking: even if your vendor supports pessimistic locking, be careful due to the performance penalties it implies. Try to use a read optimistic lock instead.
  • Set the proper cascade: when setting the cascade property be careful to choose the proper value as it creates extra queries that may not be needed for your application
  • Bulk updates: sometimes you need to apply updates to a group of entities you retrieve with a select. If possible do this using a single Update query with the proper where clause, that way you run 1 query instead of x Update queries (one per entity recovered)
  • Avoid association tables: association tables (@JoinTable) are used on one-to-many relationships but they require several extra queries that relieve heavily i joins, degrading the performance. Avoid them if you can.
  • Be careful with the generated SQL: with EJB you create JPQL queries that are translated to SQL. Try to be careful with the syntax of your queries as it may have a huge impact on performance. As an example, if you run "SELECT FROM Item I" you will do a full scan of the table when you may not need all the existing items and can add some "WHERE" clause to obtain only the needed items. Also be careful to use only indexed fields for filtering, entities relationship or ordering.

EJB Components

Although they don't create too many performance issues and most of them are related to heavy algorithms in the business layer, EJB components like Session beans and MDB can be optimized. Next there a non-exhaustive list of good practices to that end:

  • Use the proper interface: if your beans will be used in the same container use your @Local interface instead of the @Remote one, as it will allow for some runtime optimizations.
  • Use the proper session bean: never use a stateful session bean unless necessary as they can't be pooled and have a much worse performance
  • Use Facades: try to use facades in front of your fine-grained beans so the client uses just one bean. This is a good design approach and improves the performance when using the @Remote interface.
  • Check transaction attribute settings: if you use CMT by default all methods Require a trnasaction, while in fact most of them don't. Set the Not_Supported attribute to those methods.
  • Tweak the pool: stateless session beans are pooled, and usually the vendor of the container allows you to configure the pool. Try to set it at the proper size.
  • Set the passivation policy: stateful session beans don't use a pool but have a cache and policies related to their passivation. Try to set the proper policies to avoid too much passivation as it has a direct impact on performance.
  • Use the Remove method: stateful session beans have the option of marking at least one method with the @Remove annotation so the bean is scrapped when the method is called. Use it to free resources and avoid unnecessary passivations.
  • Tweak the JMS provider: most of the performance of MDB is bounded to the JMS provider you are using, so check its documentation and set the proper configuration for your usage scenario, like pool size, etc.
Loading mentions Retweet

Filed under // ejb java performance

Comments (0)