剛學技術時,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設定內容:
呼!寫完了,若純粹單一Table存取,沒有用到JPA的@ManyToMany、@ManyToOne的話,那太殺雞用牛刀了。JPA還有得學,所以這記錄花了兩天時間用Spring3串JPA成功的sample。