EclipseLink

EclipseLinkは「Java Persistence API(JPA)の公式参照実装」として開発された、エンタープライズレベルのオブジェクト関係マッピング(ORM)フレームワークです。JPA 2.0仕様の完全実装に加え、高度なキャッシュ機能、バッチ処理、多様なデータベースサポートを提供。Oracle Corporationによる強力なサポートのもと、大規模企業システムでの安定稼働実績を持ち、Java企業開発におけるデータ永続化ソリューションの標準的選択肢として確固たる地位を築いています。

ORMJavaJPAエンタープライズキャッシュSQLクエリ

GitHub概要

eclipse-ee4j/eclipselink

Eclipselink project

スター222
ウォッチ26
フォーク185
作成日:2018年3月9日
言語:Java
ライセンス:Other

トピックス

なし

スター履歴

eclipse-ee4j/eclipselink Star History
データ取得日時: 2025/7/17 10:32

ライブラリ

EclipseLink

概要

EclipseLinkは「Java Persistence API(JPA)の公式参照実装」として開発された、エンタープライズレベルのオブジェクト関係マッピング(ORM)フレームワークです。JPA 2.0仕様の完全実装に加え、高度なキャッシュ機能、バッチ処理、多様なデータベースサポートを提供。Oracle Corporationによる強力なサポートのもと、大規模企業システムでの安定稼働実績を持ち、Java企業開発におけるデータ永続化ソリューションの標準的選択肢として確固たる地位を築いています。

詳細

EclipseLink 2025年版は、15年以上の開発実績により成熟したJPA実装とエンタープライズ級の機能を提供し続けています。JPA標準仕様の完全サポートに加え、高度なキャッシュ機能、クエリ最適化、接続プール管理など企業システムに必要な機能を網羅。Oracle Database、MySQL、PostgreSQLなど主要データベースとの最適化された統合により、高いパフォーマンスを実現。Spring BootやJakarta EEなどの主要フレームワークとのシームレスな統合により、モダンなJava開発環境での生産性向上を支援します。

主な特徴

  • JPA標準準拠: JPA 2.0仕様の完全な参照実装
  • 高度なキャッシュシステム: 複数レベルキャッシュによる大幅なパフォーマンス向上
  • 企業級機能: バッチ処理、接続プール、楽観的ロック対応
  • データベース最適化: Oracle、MySQL、PostgreSQL等主要DBとの統合最適化
  • 拡張クエリ機能: JPA標準を超えた高度なクエリヒントとカスタマイズ
  • Spring統合: Spring Boot/Spring Data JPAとの完全統合サポート

メリット・デメリット

メリット

  • Java Persistence APIの公式参照実装による高い信頼性と標準準拠
  • Oracle Corporationによる強力な商用サポートと長期保守体制
  • 高度なキャッシュ機能による大幅なパフォーマンス向上
  • 企業システムに必要なバッチ処理、接続プール等の包括的機能
  • Oracle Database等との最適化された統合による優れたパフォーマンス
  • Spring Boot等モダンフレームワークとの優れた統合性

デメリット

  • Hibernateと比較して学習リソースやコミュニティサポートが限定的
  • 設定項目が多く初期設定が複雑になりがち
  • Oracle製品への依存度が高く、他社製品との統合で制約が生じる場合
  • 高度な機能を活用するにはJPA仕様を超えた専用知識が必要
  • 小規模プロジェクトには機能が過剰でオーバーエンジニアリングになりがち
  • Hibernateと比較してサードパーティツールやプラグインが少ない

参考ページ

書き方の例

基本セットアップ

<!-- Maven dependency -->
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.jpa</artifactId>
    <version>4.0.3</version>
</dependency>

<!-- persistence.xml 設定 -->
<?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 固有設定 -->
            <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>

モデル定義と基本操作

// エンティティクラス定義
@Entity
@Table(name = "users")
@Cache(type = CacheType.FULL, size = 1000)  // EclipseLink キャッシュ設定
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  // 楽観的ロック
    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;
    }
    
    // アクセサメソッド
    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; }
}

// 基本的なCRUD操作
public class UserService {
    private EntityManagerFactory emf;
    private EntityManager em;
    
    public UserService() {
        emf = Persistence.createEntityManagerFactory("usersPU");
        em = emf.createEntityManager();
    }
    
    // ユーザー作成
    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;
        }
    }
    
    // ユーザー取得(ID)
    public User findUserById(Long id) {
        return em.find(User.class, id);
    }
    
    // ユーザー更新
    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;
        }
    }
    
    // ユーザー削除
    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();
    }
}

高度なクエリ操作

public class UserQueryService {
    private EntityManager em;
    
    public UserQueryService(EntityManager em) {
        this.em = em;
    }
    
    // JPQL クエリ
    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();
    }
    
    // ネイティブSQL クエリ
    public List<User> findActiveUsers() {
        return em.createNativeQuery(
            "SELECT * FROM users WHERE created_at > DATE_SUB(NOW(), INTERVAL 30 DAY)", 
            User.class)
            .getResultList();
    }
    
    // EclipseLink クエリヒント使用
    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();
    }
    
    // バッチフェッチ
    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();
    }
    
    // 動的クエリ(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();
    }
    
    // ページネーション
    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();
    }
}

リレーション操作

// Order エンティティ(多対一リレーション)
@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;
    }
    
    // ヘルパーメソッド
    public void addItem(OrderItem item) {
        items.add(item);
        item.setOrder(this);
    }
}

// OrderItem エンティティ
@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
}

// リレーション操作サービス
public class OrderService {
    private EntityManager em;
    
    public OrderService(EntityManager em) {
        this.em = em;
    }
    
    // 注文作成(リレーション含む)
    public Order createOrderWithItems(Long userId, String orderNumber, 
                                     List<OrderItemData> itemsData) {
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            
            // ユーザー取得
            User user = em.find(User.class, userId);
            if (user == null) {
                throw new EntityNotFoundException("User not found: " + userId);
            }
            
            // 注文作成
            Order order = new Order(orderNumber, user);
            
            // 注文アイテム追加
            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;
        }
    }
    
    // リレーション込みでの注文取得
    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();
    }
    
    // ユーザーの全注文取得
    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();
    }
}

実用例

// Spring Boot統合例
@Configuration
@EnableJpaRepositories
public class JpaConfig {
    
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan("com.example.model");
        
        // EclipseLink プロバイダー設定
        EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
        vendorAdapter.setShowSql(true);
        em.setJpaVendorAdapter(vendorAdapter);
        
        // EclipseLink固有プロパティ
        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;
    }
}

// リポジトリ実装(Spring Data JPA風)
@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);
        }
    }
    
    // EclipseLink固有機能を活用したメソッド
    public List<User> findAllWithCache() {
        return em.createQuery("SELECT u FROM User u", User.class)
            .setHint(QueryHints.CACHE_USAGE, CacheUsage.CheckCacheThenDatabase)
            .getResultList();
    }
}

// サービス層(実用的なビジネスロジック)
@Service
@Transactional
public class UserBusinessService {
    
    private final UserRepository userRepository;
    
    public UserBusinessService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    public User registerUser(String username, String email) {
        // 重複チェック
        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();
    }
}