EclipseLink
EclipseLink is developed as "the official reference implementation of Java Persistence API (JPA)" and serves as an enterprise-level Object-Relational Mapping (ORM) framework. In addition to complete implementation of JPA 2.0 specification, it provides advanced caching capabilities, batch processing, and diverse database support. With strong backing from Oracle Corporation, it has a proven track record of stable operation in large-scale enterprise systems and has established itself as a standard choice for data persistence solutions in Java enterprise development.
GitHub Overview
eclipse-ee4j/eclipselink
Eclipselink project
Topics
Star History
Library
EclipseLink
Overview
EclipseLink is developed as "the official reference implementation of Java Persistence API (JPA)" and serves as an enterprise-level Object-Relational Mapping (ORM) framework. In addition to complete implementation of JPA 2.0 specification, it provides advanced caching capabilities, batch processing, and diverse database support. With strong backing from Oracle Corporation, it has a proven track record of stable operation in large-scale enterprise systems and has established itself as a standard choice for data persistence solutions in Java enterprise development.
Details
EclipseLink 2025 edition continues to provide mature JPA implementation and enterprise-grade functionality through over 15 years of development experience. Beyond complete support of JPA standard specification, it encompasses features necessary for enterprise systems including advanced caching, query optimization, and connection pool management. Optimized integration with major databases like Oracle Database, MySQL, and PostgreSQL delivers high performance. Seamless integration with major frameworks like Spring Boot and Jakarta EE supports productivity improvement in modern Java development environments.
Key Features
- JPA Standard Compliance: Complete reference implementation of JPA 2.0 specification
- Advanced Caching System: Significant performance improvement through multi-level caching
- Enterprise-Grade Features: Support for batch processing, connection pooling, optimistic locking
- Database Optimization: Optimized integration with major DBs like Oracle, MySQL, PostgreSQL
- Extended Query Features: Advanced query hints and customization beyond JPA standard
- Spring Integration: Complete integration support with Spring Boot/Spring Data JPA
Pros and Cons
Pros
- High reliability and standard compliance as official reference implementation of Java Persistence API
- Strong commercial support and long-term maintenance system by Oracle Corporation
- Significant performance improvement through advanced caching capabilities
- Comprehensive features including batch processing and connection pooling necessary for enterprise systems
- Excellent performance through optimized integration with Oracle Database and others
- Excellent integration with modern frameworks like Spring Boot
Cons
- Limited learning resources and community support compared to Hibernate
- Initial configuration tends to be complex due to many configuration options
- High dependency on Oracle products may create constraints when integrating with other vendors' products
- Requires specialized knowledge beyond JPA specification to utilize advanced features
- May result in over-engineering for small-scale projects due to excessive functionality
- Fewer third-party tools and plugins compared to Hibernate
Reference Pages
Code Examples
Basic Setup
<!-- Maven dependency -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>4.0.3</version>
</dependency>
<!-- persistence.xml configuration -->
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="usersPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.example.model.User</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="password"/>
<!-- EclipseLink specific settings -->
<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
<property name="eclipselink.logging.level" value="INFO"/>
<property name="eclipselink.cache.shared.default" value="true"/>
</properties>
</persistence-unit>
</persistence>
Model Definition and Basic Operations
// Entity class definition
@Entity
@Table(name = "users")
@Cache(type = CacheType.FULL, size = 1000) // EclipseLink cache configuration
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", nullable = false, unique = true)
private String username;
@Column(name = "email")
private String email;
@Version // Optimistic locking
private Long version;
@CreationTimestamp
@Column(name = "created_at")
private LocalDateTime createdAt;
@UpdateTimestamp
@Column(name = "updated_at")
private LocalDateTime updatedAt;
// getters, setters, constructors
public User() {}
public User(String username, String email) {
this.username = username;
this.email = email;
}
// Accessor methods
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Long getVersion() { return version; }
public void setVersion(Long version) { this.version = version; }
}
// Basic CRUD operations
public class UserService {
private EntityManagerFactory emf;
private EntityManager em;
public UserService() {
emf = Persistence.createEntityManagerFactory("usersPU");
em = emf.createEntityManager();
}
// Create user
public User createUser(String username, String email) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
User user = new User(username, email);
em.persist(user);
tx.commit();
return user;
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
throw e;
}
}
// Find user by ID
public User findUserById(Long id) {
return em.find(User.class, id);
}
// Update user
public User updateUser(Long id, String newEmail) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
User user = em.find(User.class, id);
if (user != null) {
user.setEmail(newEmail);
user = em.merge(user);
}
tx.commit();
return user;
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
throw e;
}
}
// Delete user
public boolean deleteUser(Long id) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
User user = em.find(User.class, id);
if (user != null) {
em.remove(user);
tx.commit();
return true;
}
tx.rollback();
return false;
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
throw e;
}
}
public void close() {
if (em != null) em.close();
if (emf != null) emf.close();
}
}
Advanced Query Operations
public class UserQueryService {
private EntityManager em;
public UserQueryService(EntityManager em) {
this.em = em;
}
// JPQL queries
public List<User> findUsersByUsername(String username) {
return em.createQuery(
"SELECT u FROM User u WHERE u.username LIKE :username",
User.class)
.setParameter("username", "%" + username + "%")
.getResultList();
}
// Native SQL queries
public List<User> findActiveUsers() {
return em.createNativeQuery(
"SELECT * FROM users WHERE created_at > DATE_SUB(NOW(), INTERVAL 30 DAY)",
User.class)
.getResultList();
}
// Using EclipseLink query hints
public List<User> findUsersWithCaching() {
return em.createQuery("SELECT u FROM User u", User.class)
.setHint(QueryHints.CACHE_USAGE, CacheUsage.CheckCacheThenDatabase)
.setHint(QueryHints.QUERY_RESULTS_CACHE, HintValues.TRUE)
.setHint(QueryHints.QUERY_RESULTS_CACHE_SIZE, 100)
.getResultList();
}
// Batch fetching
public List<User> findUsersWithBatchFetch() {
return em.createQuery("SELECT u FROM User u", User.class)
.setHint(QueryHints.BATCH_FETCH_TYPE, BatchFetchType.IN)
.setHint(QueryHints.BATCH_SIZE, 25)
.getResultList();
}
// Dynamic queries (Criteria API)
public List<User> findUsersByCriteria(String username, String email) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> user = query.from(User.class);
List<Predicate> predicates = new ArrayList<>();
if (username != null && !username.isEmpty()) {
predicates.add(cb.like(user.get("username"), "%" + username + "%"));
}
if (email != null && !email.isEmpty()) {
predicates.add(cb.like(user.get("email"), "%" + email + "%"));
}
query.where(predicates.toArray(new Predicate[0]));
query.orderBy(cb.asc(user.get("username")));
return em.createQuery(query).getResultList();
}
// Pagination
public List<User> findUsersWithPagination(int page, int size) {
return em.createQuery("SELECT u FROM User u ORDER BY u.id", User.class)
.setFirstResult(page * size)
.setMaxResults(size)
.getResultList();
}
}
Relationship Operations
// Order entity (many-to-one relationship)
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "order_number")
private String orderNumber;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<OrderItem> items = new ArrayList<>();
@Column(name = "total_amount")
private BigDecimal totalAmount;
// constructors, getters, setters
public Order() {}
public Order(String orderNumber, User user) {
this.orderNumber = orderNumber;
this.user = user;
}
// Helper methods
public void addItem(OrderItem item) {
items.add(item);
item.setOrder(this);
}
}
// OrderItem entity
@Entity
@Table(name = "order_items")
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
@Column(name = "product_name")
private String productName;
@Column(name = "quantity")
private Integer quantity;
@Column(name = "price")
private BigDecimal price;
// constructors, getters, setters
}
// Relationship operations service
public class OrderService {
private EntityManager em;
public OrderService(EntityManager em) {
this.em = em;
}
// Create order with relationships
public Order createOrderWithItems(Long userId, String orderNumber,
List<OrderItemData> itemsData) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
// Get user
User user = em.find(User.class, userId);
if (user == null) {
throw new EntityNotFoundException("User not found: " + userId);
}
// Create order
Order order = new Order(orderNumber, user);
// Add order items
BigDecimal total = BigDecimal.ZERO;
for (OrderItemData itemData : itemsData) {
OrderItem item = new OrderItem();
item.setProductName(itemData.getProductName());
item.setQuantity(itemData.getQuantity());
item.setPrice(itemData.getPrice());
order.addItem(item);
total = total.add(itemData.getPrice().multiply(
BigDecimal.valueOf(itemData.getQuantity())));
}
order.setTotalAmount(total);
em.persist(order);
tx.commit();
return order;
} catch (Exception e) {
if (tx.isActive()) tx.rollback();
throw e;
}
}
// Get order with relationships
public Order findOrderWithItems(Long orderId) {
return em.createQuery(
"SELECT o FROM Order o " +
"LEFT JOIN FETCH o.items " +
"LEFT JOIN FETCH o.user " +
"WHERE o.id = :orderId", Order.class)
.setParameter("orderId", orderId)
.getSingleResult();
}
// Get all orders for user
public List<Order> findOrdersByUser(Long userId) {
return em.createQuery(
"SELECT o FROM Order o " +
"WHERE o.user.id = :userId " +
"ORDER BY o.id DESC", Order.class)
.setParameter("userId", userId)
.getResultList();
}
}
Practical Examples
// Spring Boot integration example
@Configuration
@EnableJpaRepositories
public class JpaConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("com.example.model");
// EclipseLink provider configuration
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
em.setJpaVendorAdapter(vendorAdapter);
// EclipseLink specific properties
Properties properties = new Properties();
properties.setProperty("eclipselink.cache.shared.default", "true");
properties.setProperty("eclipselink.cache.size.default", "1000");
properties.setProperty("eclipselink.query-results-cache", "true");
properties.setProperty("eclipselink.logging.level", "INFO");
em.setJpaProperties(properties);
return em;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
// Repository implementation (Spring Data JPA style)
@Repository
@Transactional
public class UserRepository {
@PersistenceContext
private EntityManager em;
public User save(User user) {
if (user.getId() == null) {
em.persist(user);
return user;
} else {
return em.merge(user);
}
}
public Optional<User> findById(Long id) {
User user = em.find(User.class, id);
return Optional.ofNullable(user);
}
public List<User> findAll() {
return em.createQuery("SELECT u FROM User u", User.class)
.getResultList();
}
public Optional<User> findByUsername(String username) {
try {
User user = em.createQuery(
"SELECT u FROM User u WHERE u.username = :username", User.class)
.setParameter("username", username)
.getSingleResult();
return Optional.of(user);
} catch (NoResultException e) {
return Optional.empty();
}
}
public void deleteById(Long id) {
User user = em.find(User.class, id);
if (user != null) {
em.remove(user);
}
}
// Methods utilizing EclipseLink specific features
public List<User> findAllWithCache() {
return em.createQuery("SELECT u FROM User u", User.class)
.setHint(QueryHints.CACHE_USAGE, CacheUsage.CheckCacheThenDatabase)
.getResultList();
}
}
// Service layer (practical business logic)
@Service
@Transactional
public class UserBusinessService {
private final UserRepository userRepository;
public UserBusinessService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User registerUser(String username, String email) {
// Check for duplicates
if (userRepository.findByUsername(username).isPresent()) {
throw new IllegalArgumentException("Username already exists: " + username);
}
User user = new User(username, email);
return userRepository.save(user);
}
public User updateUserEmail(Long userId, String newEmail) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException("User not found: " + userId));
user.setEmail(newEmail);
return userRepository.save(user);
}
@Transactional(readOnly = true)
public List<User> getAllUsersWithCaching() {
return userRepository.findAllWithCache();
}
}