<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    OMG,到底在尋找什么..................
    (構(gòu)造一個完美的J2EE系統(tǒng)所需要的完整知識體系)
    posts - 198,  comments - 37,  trackbacks - 0
    原貼地址:http://forum.springside.org.cn/viewthread.php?tid=236&extra=page%3D1

    Spring 2.0 中配置 JPA


    翻譯:SpringSide團隊? ?轉(zhuǎn)載請注明出處。

    ? ? 本文提供了一個簡單的 Spring 框架 standalone??環(huán)境下,如何 step-by-step 去開發(fā) JPA 的向?qū)А?JPA 的規(guī)范最開始時是由 EJB 3.0 的持久性機制產(chǎn)生的, 它被公認(rèn)為是把簡單的 POJOs 持久化的機制。你只需少量 JAR 在 classpath 中,配置一點 Spring 的 bean, 就能在你喜愛的IDE中去開始感受 JPA 的強大威力了。我們在這里使用的是 Glassfish JPA - 一個基于 Oracle’s TopLink ORM framework 的開源項目。


    初始化設(shè)置
    1. 保證你使用的是Java 5 (EJB 3.0 中 JPA 的先決條件).
    2. https://glassfish.dev.java.net/downloads/persistence/JavaPersistence.html 下載 glassfish JPA jar
      (注意: 我使用的是 “V2_build_02″ jar, 但該版本后的版本也應(yīng)回往前兼容的.)
    3. 從“installer” jar 中解壓,并運行:
      java -jar glassfish-persistence-installer-v2-b02.jar
    4. toplink-essentials.jar 加入你的 classpath
    5. 把數(shù)據(jù)庫的驅(qū)動 JAR 也加入( 我用的是 version 1.8.0.1 的 hsqldb.jar 作為例子,但實際上你只需很少的改變就能適配到另外的數(shù)據(jù)庫 )
    6. 加入2.0 M5 以上版本的Spring JAR( http://sourceforge.net/project/showfiles.php?group_id=73357)
      - spring.jar
      - spring-jpa.jar
      - spring-mock.jar
    7. 最后,把這些 JAR 也加入到你的classpath 中:
      - commons-logging.jar
      - log4j.jar
      - junit.jar
      領(lǐng)域模型 (domain model)
      ? ? 這個例子中我們只是有目的地列舉了3個簡單的domain model. 要注意的是這例子中我們使用了annotation。 使用 JPA 時,一般會選擇用annotation 或 XML 文件,又或者兩者一起配合用,去指定ORM(object-relational mapping)元數(shù)據(jù)。在這里,我們只是選擇了單獨用annotation, 因為只需要在domain model 的代碼中加入簡短的描述就能馬上辦到。

      首先, 看看餐廳 Restaurant class:

      package blog.jpa.domain;

      import java.util.Set;
      import javax.persistence.CascadeType;
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      import javax.persistence.JoinColumn;
      import javax.persistence.JoinTable;
      import javax.persistence.ManyToMany;
      import javax.persistence.OneToOne;
      @Entity
      public class Restaurant {
      ??@Id
      ??@GeneratedValue(strategy = GenerationType.AUTO)
      ??private long id;
      ??private String name;
      ??@OneToOne(cascade = CascadeType.ALL)
      ??private Address address;
      ??@ManyToMany
      ??@JoinTable(inverseJoinColumns = @JoinColumn(name = "ENTREE_ID"))
      ??private Set<Entree> entrees;
      ??public long getId() {
      ? ? return id;
      ??}
      ??public void setId(long id) {
      ? ? this.id = id;
      ??}
      ??public String getName() {
      ? ? return name;
      ??}
      ??public void setName(String name) {
      ? ? this.name = name;
      ??}
      ??public Address getAddress() {
      ? ? return address;
      ??}
      ??public void setAddress(Address address) {
      ? ? this.address = address;
      ??}
      ??public Set<Entree> getEntrees() {
      ? ? return entrees;
      ??}
      ??public void setEntrees(Set<Entree> entrees) {
      ? ? this.entrees = entrees;
      ??}
      }

      接著地址,??Address class:

      package blog.jpa.domain;

      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      @Entity
      public class Address {
      ??@Id
      ??@GeneratedValue(strategy = GenerationType.AUTO)
      ??private long id;
      ??@Column(name = "STREET_NUMBER")
      ??private int streetNumber;
      ??@Column(name = "STREET_NAME")
      ??private String streetName;
      ??public long getId() {
      ? ? return id;
      ??}
      ??public void setId(long id) {
      ? ? this.id = id;
      ??}
      ??public int getStreetNumber() {
      ? ? return streetNumber;
      ??}
      ??public void setStreetNumber(int streetNumber) {
      ? ? this.streetNumber = streetNumber;
      ??}
      ??public String getStreetName() {
      ? ? return streetName;
      ??}
      ??public void setStreetName(String streetName) {
      ? ? this.streetName = streetName;
      ??}
      }

      然后主食, Entree class:

      package blog.jpa.domain;

      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      @Entity
      public class Entree {
      ??@Id
      ??@GeneratedValue(strategy = GenerationType.AUTO)
      ??private long id;
      ??private String name;
      ??private boolean vegetarian;
      ??public long getId() {
      ? ? return id;
      ??}
      ??public void setId(long id) {
      ? ? this.id = id;
      ??}
      ??public String getName() {
      ? ? return name;
      ??}
      ??public void setName(String name) {
      ? ? this.name = name;
      ??}
      ??public boolean isVegetarian() {
      ? ? return vegetarian;
      ??}
      ??public void setVegetarian(boolean vegetarian) {
      ? ? this.vegetarian = vegetarian;
      ??}
      }

      如你看到的那樣,并不是所有的 field 都需要annotation。JAP 會使用默認(rèn)值(例如用數(shù)據(jù)表中的列名來精確匹配屬性名),所以在很多的情況下,你并不需要很明確的去指定元數(shù)據(jù)。需要注意的是,在 Entree 類中,我并沒有為String 屬性 “name” 或 boolean 屬性 “vegetarian” 加入 annotation。然而,在 Address 類中,我使用了annotation, 因為我不想用數(shù)據(jù)庫表中的列名作為默認(rèn)名(例如,我用 “STREET_NAME”而默認(rèn)的是 “STREETNAME”)。
      ? ? 在ORM機制中最重要的當(dāng)然是指定Objects和database間的對應(yīng)關(guān)系。在 Restaurant 類中,我們用 @OneToOne 去描述它與 Address 的關(guān)系,同時我們用 @ManyToMany 去描述它與 Entree 類中的成員關(guān)系。因為其它類的實例也是由 EntityManager 所管理的, 所以可以指定“cascade”規(guī)則,如當(dāng)一個 Restaurant 被刪除,所有相關(guān)聯(lián)的 Address 也會同時被刪除。在下面,你將會看到這個場景的測試用例。
      ? ? 最后,看看 @Id 和指定“strategy”給ID的 @GeneratedValue 。 這元數(shù)據(jù)是用來描述數(shù)據(jù)庫中唯一鍵 primary key 的生成方式的。
      想知道更多關(guān)于JPA annotation 的資料,查看 JPA 的說明文檔,JSR-220.

      數(shù)據(jù)訪問層 (Data Access Layer)
      ? ? 最好的方式是建立通用的接口去隱藏持久層所有的實現(xiàn)細(xì)節(jié),這樣就算由JPA換到其它的實現(xiàn)方式也不會影響到系統(tǒng)架構(gòu)。同時,這也為業(yè)務(wù)邏輯層提供了方便,可以更容易地實現(xiàn) stub 或 mock 測試。
      ? ? RestaurantDao 是一個接口,注意它沒有對任何 JPA 或 Spring 的類有依賴。實際上,它只對自身的domain model 有依賴(在這個簡單的例子中,只有一個,那就是 Restaurant):

      package blog.jpa.dao;

      import java.util.List;
      import blog.jpa.domain.Restaurant;
      public interface RestaurantDao {
      ??public Restaurant findById(long id);
      ??public List<Restaurant> findByName(String name);
      ??public List<Restaurant> findByStreetName(String streetName);
      ??public List<Restaurant> findByEntreeNameLike(String entreeName);
      ??public List<Restaurant> findRestaurantsWithVegetarianEntrees();
      ??public void save(Restaurant restaurant);
      ??public Restaurant update(Restaurant restaurant);
      ??public void delete(Restaurant restaurant);
      }

      對于接口的實現(xiàn),我使用了 Spring 的 JpaDaoSupport 類,它提供了方便的方法去獲取 JpaTemplate。如果你已經(jīng)比較熟悉 Spring 的 JDBC 或者起其它 ORM 技術(shù),則很容易上手。
      ? ? JpaDaoSupport 是可選的,它只是提供了通過 EntityManagerFactory??更直接使用 JpaTemplate 的方法。JpaTemplate 也是可選的,如果你不希望 Spring 的自動處理 JPA exception 的事務(wù)方式,你完全可以避免使用 JpaTemplate 。即使這樣,Spring 的 EntityManagerFactoryUtils 類還是會對你有比較大的幫助,它提供了方便的靜態(tài)方法去獲取共享的EntityManager。
      下面是具體實現(xiàn)代碼:

      package blog.jpa.dao;


      import java.util.List;
      import org.springframework.orm.jpa.support.JpaDaoSupport;
      import blog.jpa.domain.Restaurant;
      public class JpaRestaurantDao extends JpaDaoSupport implements RestaurantDao {
      ??public Restaurant findById(long id) {
      ? ? return getJpaTemplate().find(Restaurant.class, id);
      ??}
      ??public List<Restaurant> findByName(String name) {
      ? ? return getJpaTemplate().find("select r from Restaurant r where r.name = ?1", name);
      ??}
      ??public List<Restaurant> findByStreetName(String streetName) {
      ? ? return getJpaTemplate().find("select r from Restaurant r where r.address.streetName = ?1", streetName);
      ??}
      ??public List<Restaurant> findByEntreeNameLike(String entreeName) {
      ? ? return getJpaTemplate().find("select r from Restaurant r where r.entrees.name like ?1", entreeName);
      ??}
      ??public List<Restaurant> findRestaurantsWithVegetarianEntrees() {
      ? ? return getJpaTemplate().find("select r from Restaurant r where r.entrees.vegetarian = 'true'");
      ??}
      ??public void save(Restaurant restaurant) {
      ? ? getJpaTemplate().persist(restaurant);
      ??}
      ??public Restaurant update(Restaurant restaurant) {
      ? ? return getJpaTemplate().merge(restaurant);
      ??}
      ??public void delete(Restaurant restaurant) {
      ? ? getJpaTemplate().remove(restaurant);
      ??}
      }




      業(yè)務(wù)邏輯層 (Service Layer)
      ? ? 由于我們的主要目的是集中在數(shù)據(jù)訪問層 JPA 的實現(xiàn),所以業(yè)務(wù)邏輯層基本上忽略不講。在實際項目中,業(yè)務(wù)邏輯層對于整個系統(tǒng)的架構(gòu)至關(guān)重要。它是分離事務(wù)(transaction)的重點。一般情況下,我們都會通過 Spring 來配置事務(wù)。在下面的步驟中,當(dāng)你看配置時,你會注意到我已提供了一個“transactionManager” 的 bean。 它可以為測試用例中的每個測試方法提供事務(wù)回滾,同時它也讓使用同一個 “transactionManager”的業(yè)務(wù)邏輯層的方法提供事務(wù)處理。數(shù)據(jù)庫訪問層的代碼與則不負(fù)責(zé)事務(wù)處理,事務(wù)傳播的發(fā)生是自動的,最終由業(yè)務(wù)邏輯層來處理。Spring 框架中的所有持久層類的配置都是相同的,使用 Spring JpaTemplate 時要注意保證所有 DAO 都共享同一個EntityManager

      配置
      ? ? 因為我選擇了使用基于 annotation 的映射關(guān)系,你或許已經(jīng)看過許多 JPA 的配置說明,如我上面說提到的,它同樣可以通過 XML( 在‘orm.xml’文件里 )來配置映射關(guān)系。另一種則只要求配置‘META-INF/persistence.xml’。這樣的話,就能更為容易,因為database相關(guān)的屬性可以通過EntityManagerFactory 來獲得。在‘persistence.xml’中需要的信息只是需要 local 的還是global(JTA) 的事務(wù)。下面是 ‘persistence.xml’ 的具體內(nèi)容:

      <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">

      ??<persistence-unit name="SpringJpaGettingStarted" transaction-type="RESOURCE_LOCAL"/>
      </persistence>

      有4個bean在這 Spring 配置中是要注意的。首先,看看“restaurantDao” (我沒有在bean名前的"jpa"也加上去的原因是所有的業(yè)務(wù)邏輯層都必須只與接口相關(guān)),其唯一需要的 property 就是 “entityManagerFactory” ,用于產(chǎn)生JpaTemplate。 “entityManagerFactory” 需要“dataSource”, 這個在 JPA 說明文檔里并沒有提到。在這里,我們使用了DriverManagerDataSource,但是在實際操作中,你需要用你自己數(shù)據(jù)庫的連接池,或者是用JndiObjectFactoryBean來得到Jndi。最后的 “transactionManager” bean是測試和邏輯層處理事務(wù)需要到的。如果你已經(jīng)熟悉 Spring 下??JDBC, Hibernate, JDO, TopLink, 或 iBATIS 的配置,這幾個bean對于你來說是再簡單不過了。然我們來看看完整的‘a(chǎn)pplicationContext.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"
      ??xsi:schemaLocation="http://www.springframework.org/schema/beans
      ? ? http://www.springframework.org/schema/beans/spring-beans.xsd">

      ??<bean id="restaurantDao" class="blog.jpa.dao.JpaRestaurantDao">
      ? ? <property name="entityManagerFactory" ref="entityManagerFactory"/>
      ??</bean>
      ??<bean id="entityManagerFactory" class="org.springframework.orm.jpa.ContainerEntityManagerFactoryBean">
      ? ? <property name="dataSource" ref="dataSource"/>
      ? ? <property name="jpaVendorAdapter">
      ? ?? ?<bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
      ? ?? ???<property name="showSql" value="true"/>
      ? ?? ???<property name="generateDdl" value="true"/>
      ? ?? ???<property name="databasePlatform" value="oracle.toplink.essentials.platform.database.HSQLPlatform"/>
      ? ?? ?</bean>
      ? ? </property>
      ? ? <property name="loadTimeWeaver">
      ? ?? ?<bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver"/>
      ? ? </property>
      ??</bean>
      ??<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      ? ? <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
      ? ? <property name="url" value="jdbc:hsqldb:hsql://localhost/"/>
      ? ? <property name="username" value="sa"/>
      ? ? <property name="password" value=""/>
      ??</bean>
      ??<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
      ? ? <property name="entityManagerFactory" ref="entityManagerFactory"/>
      ? ? <property name="dataSource" ref="dataSource"/>
      ??</bean>
      </beans>

      “entityManagerFactory” bean需要 “jpaVendorAdapter” ,對于 “jpaVendorAdapter”有多種多樣的JPA實現(xiàn)方式。在這個例子里,我用了 TopLinkJpaVendorAdapter??作為 inner bean,它也需要自己的一些property ,它有兩個屬性分別指明是否現(xiàn)實SQL和是否生成DDL.在這里我們都設(shè)為 “true” ,所以當(dāng)測試的時候數(shù)據(jù)庫表會每次都自動生成,這對于早期的開發(fā)帶來不少方便。還有就是“databasePlatformClass” 提供了必要的數(shù)據(jù)庫庫使用的詳細(xì)信息。“entityManagerFactory”還有一個“l(fā)oadTimeWeaver” 屬性,以配合某些特性,如延遲加載(lazy-loading)。

      集成測試(Integration Testing)
      ? ? JpaRestaurantDaoTests 提供了一些基礎(chǔ)的測試。你可以自己嘗試動手修改一下配置文件和測試代碼,來掌握更多關(guān)于JPA的知識,如嘗試不同的設(shè)置cascade 。值得注意的是 JpaRestaurantDaoTests 繼承了 Spring 的 AbstractJpaTests。也許你已經(jīng)比較熟悉 Spring 的 AbstractTransactionalDataSourceSpringContextTests, 這個類可以讓在測試中的所有數(shù)據(jù)庫改變都回滾。AbstractJpaTests 實際上的作用不僅于此,但已經(jīng)超出了我們該講的范圍了。如果感興趣,你可以深入看看AbstractJpaTests的源代碼。
      這里是JpaRestaurantDaoTests
      的實現(xiàn)代碼:

      package blog.jpa.dao;

      import java.util.List;
      import org.springframework.test.jpa.AbstractJpaTests;
      import blog.jpa.dao.RestaurantDao;
      import blog.jpa.domain.Restaurant;
      public class JpaRestaurantDaoTests extends AbstractJpaTests {
      ??private RestaurantDao restaurantDao;
      ??public void setRestaurantDao(RestaurantDao restaurantDao) {
      ? ? this.restaurantDao = restaurantDao;
      ??}
      ??protected String[] getConfigLocations() {
      ? ? return new String[] {"classpath:/blog/jpa/dao/applicationContext.xml"};
      ??}
      ??protected void onSetUpInTransaction() throws Exception {
      ? ? jdbcTemplate.execute("insert into address (id, street_number, street_name) values (1, 10, 'Main Street')");
      ? ? jdbcTemplate.execute("insert into address (id, street_number, street_name) values (2, 20, 'Main Street')");
      ? ? jdbcTemplate.execute("insert into address (id, street_number, street_name) values (3, 123, 'Dover Street')");
      ? ? jdbcTemplate.execute("insert into restaurant (id, name, address_id) values (1, 'Burger Barn', 1)");
      ? ? jdbcTemplate.execute("insert into restaurant (id, name, address_id) values (2, 'Veggie Village', 2)");
      ? ? jdbcTemplate.execute("insert into restaurant (id, name, address_id) values (3, 'Dover Diner', 3)");
      ? ? jdbcTemplate.execute("insert into entree (id, name, vegetarian) values (1, 'Hamburger', 0)");
      ? ? jdbcTemplate.execute("insert into entree (id, name, vegetarian) values (2, 'Cheeseburger', 0)");
      ? ? jdbcTemplate.execute("insert into entree (id, name, vegetarian) values (3, 'Tofu Stir Fry', 1)");
      ? ? jdbcTemplate.execute("insert into entree (id, name, vegetarian) values (4, 'Vegetable Soup', 1)");
      ? ? jdbcTemplate.execute("insert into restaurant_entree (restaurant_id, entree_id) values (1, 1)");
      ? ? jdbcTemplate.execute("insert into restaurant_entree (restaurant_id, entree_id) values (1, 2)");
      ? ? jdbcTemplate.execute("insert into restaurant_entree (restaurant_id, entree_id) values (2, 3)");
      ? ? jdbcTemplate.execute("insert into restaurant_entree (restaurant_id, entree_id) values (2, 4)");
      ? ? jdbcTemplate.execute("insert into restaurant_entree (restaurant_id, entree_id) values (3, 1)");
      ? ? jdbcTemplate.execute("insert into restaurant_entree (restaurant_id, entree_id) values (3, 2)");
      ? ? jdbcTemplate.execute("insert into restaurant_entree (restaurant_id, entree_id) values (3, 4)");
      ??}
      ??public void testFindByIdWhereRestaurantExists() {
      ? ? Restaurant restaurant = restaurantDao.findById(1);
      ? ? assertNotNull(restaurant);
      ? ? assertEquals("Burger Barn", restaurant.getName());
      ??}
      ??public void testFindByIdWhereRestaurantDoesNotExist() {
      ? ? Restaurant restaurant = restaurantDao.findById(99);
      ? ? assertNull(restaurant);
      ??}
      ??public void testFindByNameWhereRestaurantExists() {
      ? ? List<Restaurant> restaurants = restaurantDao.findByName("Veggie Village");
      ? ? assertEquals(1, restaurants.size());
      ? ? Restaurant restaurant = restaurants.get(0);
      ? ? assertEquals("Veggie Village", restaurant.getName());
      ? ? assertEquals("Main Street", restaurant.getAddress().getStreetName());
      ? ? assertEquals(2, restaurant.getEntrees().size());
      ??}
      ??public void testFindByNameWhereRestaurantDoesNotExist() {
      ? ? List<Restaurant> restaurants = restaurantDao.findByName("No Such Restaurant");
      ? ? assertEquals(0, restaurants.size());
      ??}
      ??public void testFindByStreetName() {
      ? ? List<Restaurant> restaurants = restaurantDao.findByStreetName("Main Street");
      ? ? assertEquals(2, restaurants.size());
      ? ? Restaurant r1 = restaurantDao.findByName("Burger Barn").get(0);
      ? ? Restaurant r2 = restaurantDao.findByName("Veggie Village").get(0);
      ? ? assertTrue(restaurants.contains(r1));
      ? ? assertTrue(restaurants.contains(r2));
      ??}
      ??public void testFindByEntreeNameLike() {
      ? ? List<Restaurant> restaurants = restaurantDao.findByEntreeNameLike("%burger");
      ? ? assertEquals(2, restaurants.size());
      ??}
      ??public void testFindRestaurantsWithVegetarianOptions() {
      ? ? List<Restaurant> restaurants = restaurantDao.findRestaurantsWithVegetarianEntrees();
      ? ? assertEquals(2, restaurants.size());
      ??}
      ??public void testModifyRestaurant() {
      ? ? String oldName = "Burger Barn";
      ? ? String newName = "Hamburger Hut";
      ? ? Restaurant restaurant = restaurantDao.findByName(oldName).get(0);
      ? ? restaurant.setName(newName);
      ? ? restaurantDao.update(restaurant);
      ? ? List<Restaurant> results = restaurantDao.findByName(oldName);
      ? ? assertEquals(0, results.size());
      ? ? results = restaurantDao.findByName(newName);
      ? ? assertEquals(1, results.size());
      ??}
      ??public void testDeleteRestaurantAlsoDeletesAddress() {
      ? ? String restaurantName = "Dover Diner";
      ? ? int preRestaurantCount = jdbcTemplate.queryForInt("select count(*) from restaurant");
      ? ? int preAddressCount = jdbcTemplate.queryForInt("select count(*) from address where street_name = 'Dover Street'");
      ? ? Restaurant restaurant = restaurantDao.findByName(restaurantName).get(0);
      ? ? restaurantDao.delete(restaurant);
      ? ? List<Restaurant> results = restaurantDao.findByName(restaurantName);
      ? ? assertEquals(0, results.size());
      ? ? int postRestaurantCount = jdbcTemplate.queryForInt("select count(*) from restaurant");
      ? ? assertEquals(preRestaurantCount - 1, postRestaurantCount);
      ? ? int postAddressCount = jdbcTemplate.queryForInt("select count(*) from address where street_name = 'Dover Street'");
      ? ? assertEquals(preAddressCount - 1, postAddressCount);
      ??}
      ??public void testDeleteRestaurantDoesNotDeleteEntrees() {
      ? ? String restaurantName = "Dover Diner";
      ? ? int preRestaurantCount = jdbcTemplate.queryForInt("select count(*) from restaurant");
      ? ? int preEntreeCount = jdbcTemplate.queryForInt("select count(*) from entree");
      ? ? Restaurant restaurant = restaurantDao.findByName(restaurantName).get(0);
      ? ? restaurantDao.delete(restaurant);
      ? ? List<Restaurant> results = restaurantDao.findByName(restaurantName);
      ? ? assertEquals(0, results.size());
      ? ? int postRestaurantCount = jdbcTemplate.queryForInt("select count(*) from restaurant");
      ? ? assertEquals(preRestaurantCount - 1, postRestaurantCount);
      ? ? int postEntreeCount = jdbcTemplate.queryForInt("select count(*) from entree");
      ? ? assertEquals(preEntreeCount, postEntreeCount);
      ??}
      }

      進一步閱讀
      ? ? JPA是一個很大的話題,這篇日志只是講述了如何在 Spring 框架中配置 JPA. 只要你弄懂了配置如何運作,你就能很好的運用 JPA提供的ORM功能。我非常建議你去看看 JPA的官方文檔還有 Spring reference 文檔。在Spring 2.0 RC1 文檔中就有加入了 JPA 的 ORM部分內(nèi)容。
      以下是比較有用的一些連接:
      JSR-220 (包含了 JPA 說明文檔)
      Glassfish JPA (相關(guān)的實現(xiàn)說明)
      Kodo 4.0 (BEA的基于Kodo的JPA實現(xiàn))
      Hibernate JPA Migration Guide


      (自 http://blog.interface21.com/main/2006/05/30/getting-started-with-jpa-in-spring-20/ , cac 翻譯)
      posted on 2006-10-31 08:37 OMG 閱讀(996) 評論(0)  編輯  收藏 所屬分類: Hibernate

      <2006年10月>
      24252627282930
      1234567
      891011121314
      15161718192021
      22232425262728
      2930311234

      常用鏈接

      留言簿(1)

      隨筆分類

      隨筆檔案

      IT風(fēng)云人物

      文檔

      朋友

      相冊

      經(jīng)典網(wǎng)站

      搜索

      •  

      最新評論

      閱讀排行榜

      評論排行榜

      主站蜘蛛池模板: 无码国产精品一区二区免费I6| 亚洲国产成人资源在线软件 | a毛片成人免费全部播放| 国产在线不卡免费播放| 久久亚洲AV成人无码国产电影 | 久别的草原电视剧免费观看| 亚洲bt加勒比一区二区| 午夜影院免费观看| 亚洲电影一区二区三区| 19禁啪啪无遮挡免费网站| 亚洲第一成年网站大全亚洲| 国产四虎免费精品视频| 日韩亚洲人成在线| 日韩精品视频免费观看| 国产亚洲女在线线精品| 久久伊人亚洲AV无码网站| 免费观看一区二区三区| 综合自拍亚洲综合图不卡区| 国产在线观看免费观看不卡| 亚洲AV无码一区二区乱子仑| www.亚洲精品| 九九精品成人免费国产片| 亚洲经典在线观看| 日韩成人免费在线| 乱爱性全过程免费视频| 日产亚洲一区二区三区| 毛片a级毛片免费播放下载| 极品美女一级毛片免费| 久久精品国产亚洲香蕉| 性做久久久久久免费观看| 香蕉视频免费在线播放| 亚洲91av视频| 嫩草影院在线免费观看| 最近国语视频在线观看免费播放| 亚洲综合一区二区精品久久| 又粗又大又硬又爽的免费视频| 久久大香伊焦在人线免费| 亚洲色偷偷色噜噜狠狠99| 国产精品亚洲二区在线观看| 91免费播放人人爽人人快乐| 色网站在线免费观看|