close

  剛學技術時,SQL學得最好,Log是最差,現在反而倒過來了,對ORM產品上手特別鈍感,這也許我很快先學會iBatis的緣故,慣用SQL操作,卻沒有物件對映到資料庫的概念。以下飯粒只是用JUnit很簡單的存取一個Accounts table裡名字欄位,因為併使Spring3的annotation context、JPA using Hibernate,試完後,真的會癱掉:

  使用AnnotationConfigContext載入Config類別進行JUnit,其測試程式如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,
        value = "com.foo.dao.BaseDaoConfig")
public class TestBaseDaoImpl {
    @Autowired
    private IBaseDao<Accounts> baseDao;
    @Test
    public void testDao() {
       
List<Accounts> accounts =
            baseDao.find("from Accounts a where a.id = ?", new Integer(1));

        assertNotNull(accounts);
        assertEquals(accounts.size(), 1);
        for (Accounts account : accounts) {
            System.out.println(account.getName_tw());
        }
    }
} (figure 1)

  上例是很一般的DAO的使用,但在JPA寫法有幾點要特別注意,一個是Value Object,要宣告@Entity才能被JPA取得如下片段:

@Entity
@Table(name = "_Accounts")
public class Accounts {
    @Column(name = "id")
    private Integer id;
    @Column(name = "name_tw")
    private String name_tw;
    // get/set...
}
(figure 2)

  再來就是DAO的寫法:第一個要注意的是@PersistenceContext的注入;第二個是JPQL是不同於一般SQL,from後面是接Class Name(上述@Entity)而不是Table Name(@Table),可以從from後開始寫,若要用Select,則是Select a from Accounts a where a.id=?,不能用Select *,要用別名不帶欄位。

public class BaseDaoImpl<T> implements IBaseDao<T> {
    @PersistenceContext
    protected EntityManager em;

    @SuppressWarnings("unchecked")
    public List<T> find(String jpql, Object param) {
        return em.createQuery(jpql).setParameter(1, param).getResultList();
    }
}
(figure 3)

  接著是怎麼用Config類別載入JPA設定。過程是TestBaseDaoImpl(figure 1)—>AnnotationConfigContextLoader—>BaseDaoConfig(figure 4)—>RootConfig(figure 5)—>load resources.xml。有關JPA設定就藏在resources.xml了.

BaseDaoConfig.java

@Configuration
@Import(RootConfig.class)
public class BaseDaoConfig {
    @Bean
    public IBaseDao iBaseDao() {
        return new BaseDaoImpl();
    }
}

(figure 4)

RootConfig.java

@Configuration
@ImportResource("classpath:resources.xml")
public class RootConfig {
    private @Value("#{jdbcProperties.driverClassName}") String driverClass;
    private @Value("#{jdbcProperties.url}") String jdbcUrl;
    private @Value("#{jdbcProperties.username}") String username;
    private @Value("#{jdbcProperties.password}") String password;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(this.driverClass);
        dataSource.setUrl(this.jdbcUrl);
        dataSource.setUsername(this.username);
        dataSource.setPassword(this.password);
        return dataSource;
    }
}
(figure 5)

  resources.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:tx="http://www.springframework.org/schema/tx"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">   
    <util:properties id="jdbcProperties" location="classpath:jdbc.properties"/>
    <tx:annotation-driven/>

    <!-- Inject EntityManager into @PersistenceContext,宣告可以使用JPA的annotation -->
    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <!-- EntityManagerFactory Object,
@PersistenceContext所注釋的變數由此bean注入  -->
    <bean id="emf"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        destroy-method="destroy">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">  <!-- 使用Hibernate做Adapter -->
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
        <property name="jpaProperties">     <!-- Properties的Key是Hibernate要用的,JPA只是傳遞 -->
            <props>
                <prop key="showSql">true</prop>
                <prop key="generateDdl">true</prop>
                <prop key="databasePlatform">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.query.factory_class">  <!-- 這屬性可確保@Entity和@Table mapping -->
                    org.hibernate.hql.classic.ClassicQueryTranslatorFactory
                </prop>

            </props>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="dataSource" ref="dataSource"/>
        <property name="entityManagerFactory"
            ref="emf" />
    </bean>
</beans>

  呼!寫完了,若純粹單一Table存取,沒有用到JPA的@ManyToMany、@ManyToOne的話,那太殺雞用牛刀了。JPA還有得學,所以這記錄花了兩天時間用Spring3串JPA成功的sample。

arrow
arrow
    全站熱搜

    Jemmy 發表在 痞客邦 留言(0) 人氣()