Google Code Prettify

2016年3月20日 星期日

Hibernate + Spring + JPA (configure)

Java 有很多的 ORM framework,在 JPA 制定後得到統一的寫法,當然啦~ JPA 還不夠完善,但是在 JPA 可行的範圍內,還是建議改用 JPA。

底下的例子 database layout 如下:

不過,這個 layout 倒也不是重點,因為這一篇主要是要說明環境的設定。

使用 JPA 連線到資料庫,所先要將連線設定在 classpath:META-INF/persistence.xml,如下: (在這個設定檔裡決定採用那一個 ORM framework,這裡決定採用 Hibernate。)
<persistence 
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">
    
    <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
         <provider>org.hibernate.ejb.HibernatePersistence</provider>
         <properties>
             <property name="hibernate.ejb.autodetection" value="class"/>
             <property name="hibernate.connection.url" value="jdbc:oracle:thin:@oracledb:1521:myvote"/>
             <property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
             <property name="hibernate.connection.username" value="steven"/>
             <property name="hibernate.connection.password" value="Borland##"/>
             <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
             <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" />
             <property name="hibernate.c3p0.min_size" value="20"/>
             <property name="hibernate.c3p0.initial_Pool_Size" value="20"/>
             <property name="hibernate.c3p0.max_size" value="100"/>
             <property name="hibernate.c3p0.timeout" value="120"/>
             <property name="hibernate.c3p0.max_statements" value="50"/>
             <property name="hibernate.c3p0.idle_test_period" value="3000"/>
             <property name="hibernate.show_sql" value="true"/>
         </properties>
      </persistence-unit>
</persistence>
  1. 為這個連線設定取個名字吧! 如綠色部份,這裡取名為 persistenceUnit。
  2. 因為這裡使用了 connection pool (橘色),在 Maven 的 pom.xml 中要加入如下設定,這樣專案會加入兩個 jar 檔 - hibernate-c3p0-5.0.7.Final.jar、c3p0-0.9.2.1.jar,第一個檔案的版號會隨設定檔設定的 hibernate.version 而定。
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-c3p0</artifactId>
    <version>${hibernate.version}</version>
</dependency> 
接著在 spring 的設定檔 (beans-config.xml) 裡如下設定:
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:c="http://www.springframework.org/schema/c"
  xmlns:cache="http://www.springframework.org/schema/cache"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
        
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
  
      <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
 
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="persistenceUnit"/>
      </bean>
   
      <context:component-scan base-package="idv.steven.orm.market.dao">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
      </context:component-scan>
      
      <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager"
        p:entityManagerFactory-ref="entityManagerFactory" 
      />
  
      <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />

    <bean id="app1" class="idv.steven.orm.market.App1" />
</beans>
  1. 在 DAO 裡會用到一個 annotation - @PersistenceContext,在這裡要引入綠色部份。
  2. entityManagerFactory 只會在這個設定檔裡出現,目的是產生注入 DAO 的 EntityManager。
  3. 所有的 DAO 會放在 idv.steven.orm.market.dao 這個 package 下,並且在每個類別前加上 @Repository,透過這個設定 spring 即會掃描 package 裡所有類別,將所有的 DAO 載入。
  4. 紅色部份是關於 transaction 的管理。
設定到這裡基本上是完成了,接著要為每個 table 建立一個相對應的 table,這裡舉 Sales 為例。
@Entity
public class Sales implements Serializable {
    private static final long serialVersionUID = 2672157806527049297L;
    
    private String emNo;
    private String name;
    
    public Sales() {}
    
    public Sales(String emNo, String name) {
        this.emNo = emNo;
        this.name = name;
    }

    @Id
    public String getEmNo() {
        return emNo;
    }
    public void setEmNo(String emNo) {
        this.emNo = emNo;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Sales [emNo=" + emNo + ", name=" + name + "]";
    }
}
如上所示,類別前加上 @Entity,primary key 相關欄位的 getter method 前則加上 @Id。
完成每個 Entity 後,接著寫 DAO,一般來說會先為每個 DAO 建立一個 interface (非必要)。
public interface SalesDao {
    public List<Sales> findAll();
    public List<Customer> findCustomerByEmno(String emno);
}
這個 interface 規範了 DAO 將會有兩個 method,第一個查詢出所有的 sales,第二個查詢出指定的 sales 的所有客戶,DAO 當然要實作這個介面,如下:
@Repository
public class SalesDaoImpl implements SalesDao {
    @PersistenceContext
    private EntityManager entityManager;
      
    @SuppressWarnings("unchecked")
    @Override
    public List<Sales> findAll() {
        Query query = entityManager.createQuery("from Sales as s order by s.emNo");
        return query.getResultList();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Customer> findCustomerByEmno(String emNo) {
        Query query = entityManager.createNativeQuery("select c.cid, c.name, c.emNo from Sales s join Customer c on s.emNo = c.emNo where c.emNo = :emNo order by c.emNo, c.cid", Customer.class);
        query.setParameter("emNo", emNo);
        return query.getResultList();
    }
} 
DAO 類別前要加上 @Repository,以供 spring 識別並載入,DAO 中要注入 EntityManager 連線到資料庫,要特別注意的是,這裡不是以 @Autowired 注入,一定要用 @PersistenceContext。設定程式都寫好,寫個小程式測試一下吧 ~ 結果當然可以正常執行 ... 至於上面 DAO 中如何進行查詢,為什麼有兩種方法? 待後續說明。
public class App1 {
    static ApplicationContext context = null;
    
    @Autowired
    private SalesDaoImpl salesDao;
    
    public void run() {
        List<Sales> sales = salesDao.findAll();
        for(Sales s:sales) {
            System.out.println(s.toString());
        }
        
        List<Customer> customers = salesDao.findCustomerByEmno("007528");
        for(Customer c:customers) {
            System.out.println(c.toString());
        }
    }

    public static void main(String[] args) {
        context = new ClassPathXmlApplicationContext("classpath:beans-config.xml");
        App1 app1 = (App1) context.getBean("app1");
        app1.run();
    }
}
  • see also
JPA + Hibernate + Spring + JUnit (annotation)





【日劇 - 別讓我走】
以複製人為主題,綾瀨遙主演,應該是一齣可以讓觀眾產生許多想法的影集,但是,其中許多不合理的劇情,尤其是複製人擁有部份的人身自由,可在申請之下與外界接觸,且不同複製人所居住的農舍間並不禁止相互往來,這應該會提供複製人集結反抗的機會,編劇卻讓複製人多半順從於社會體制,這就弱化了複製人對人類社會衝擊所產生的戲劇張力。

2 則留言: