Spring 對 JPA 的支持已經非常強大,開發者只需關心核心業務邏輯的實現代碼,無需過多關註 EntityManager 的創建、事務處理等 JPA 相關的處理。Spring Data JPA更是能夠根據方法名字自動實現持久層。 目標 這次我們的目標還是實現前面幾節的功能,即對Category的 ...
Spring 對 JPA 的支持已經非常強大,開發者只需關心核心業務邏輯的實現代碼,無需過多關註 EntityManager 的創建、事務處理等 JPA 相關的處理。Spring Data JPA更是能夠根據方法名字自動實現持久層。
目標
這次我們的目標還是實現前面幾節的功能,即對Category的數據層操作。完整和的代碼結構:
首先添加實體類Category.java
Entity @Table(name = "Category") public class Category implements Serializable { @Override public String toString() { return "id="+id+" name="+name; } private Integer id; @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
引入JPA
JPA 規範要求,配置文件必須命名為 persistence.xml,並存在於類路徑下的 META-INF 目錄中。該文件通常包含了初始化 JPA 引擎所需的全部信息。Spring 提供的 LocalContainerEntityManagerFactoryBean 提供了非常靈活的配置,persistence.xml 中的信息都可以在此以屬性註入的方式提供。
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <persistence-unit name="category" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>demoJPA.entity.Category</class> <properties> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/store"/> <property name="hibernate.connection.username" value="root"/> <property name="hibernate.connection.password" value="root"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> <property name="hibernate.use_sql_comments" value="false"/> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> </persistence>
實現數據持久層
接下來到了最核心的部分,就是對於數據持久層的支持。使用 Spring Data JPA 進行持久層開發大致需要的三個步驟:
1.首先引入依賴,這裡主要用到spring data commons和spring data jpa兩個包。
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-commons</artifactId> <version>1.13.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.11.3.RELEASE</version> </dependency>
完整的pom:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>DemoStore</groupId> <artifactId>DemoJPA</artifactId> <version>1.0-SNAPSHOT</version> <properties> <hibernate.version>3.5.6-Final</hibernate.version> <hibernate.annotations.version>5.0.1.Final</hibernate.annotations.version> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-commons --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-commons</artifactId> <version>1.13.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.11.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency> <!-- hibernate相關項目依賴 start --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate.common</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>${hibernate.annotations.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.0-api --> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.0-api</artifactId> <version>1.0.1.Final</version> </dependency> <!-- hibernate相關項目依賴 end --> </dependencies> </project>
2.聲明持久層介面 CategoryDao繼承 Repository 介面。Spring Data JPA 在後臺為持久層介面創建代理對象時,會解析方法名字,並自動實現相應的功能。
public interface CategoryDao extends Repository<Category, Integer> { void save(Category category); Iterable<Category> findAll(); long count(); void delete(int id); }
3.在 Spring 配置文件中增加一行聲明,讓 Spring 為聲明的介面創建代理對象。配置了 <jpa:repositories> 後,Spring 初始化容器時將會掃描 base-package 指定的包目錄及其子目錄,為繼承 Repository 或其子介面的介面創建代理對象,並將代理對象註冊為 Spring Bean,業務層便可以通過 Spring 自動封裝的特性來直接使用該對象。
<context:component-scan base-package="demoJPA"/> <tx:annotation-driven transaction-manager="transactionManager"/> <jpa:repositories base-package="demoJPA.dao" repository-impl-postfix="Impl" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="generateDdl" value="false"/> <property name="showSql" value="true"/> </bean> </property> </bean>
使用 @Query 創建查詢
除了通過解析方法名實現功能外,開發者還可以直接在聲明的方法上面使用 @Query 註解,並提供一個查詢語句作為參數。Spring Data JPA 在創建代理對象時,便會用提供的查詢語句來實現其功能。
@Query 註解的使用非常簡單,只需在聲明的方法上面標註該註解,同時提供一個 JPQL 查詢語句即可。JPQL 語句中通過": 變數"的格式來指定參數,同時在方法的參數前面使用 @Param 將方法參數與 JP QL 中的命名參數對應。
@Query("from Category where id=:id") Category findOne(@Param("id") int id);
開發者也可以通過使用 @Query 來執行一個更新操作,為此,我們需要在使用 @Query 的同時,用 @Modifying 來將該操作標識為修改查詢,這樣框架最終會生成一個更新的操作,而非查詢。
@Transactional @Modifying @Query("update Category set name=:name where id=:id") void updateName(@Param("id")int id,@Param("name")String name);
單元測試
@ContextConfiguration(locations = "classpath:applicationContext.xml") @RunWith(SpringJUnit4ClassRunner.class) public class testJpa { int id=5; @Autowired private CategoryDao categoryDao; @Test public void testSave(){ Category category=new Category(); category.setId(id); category.setName("test"); categoryDao.save(category); } @Test public void testUpdateName(){ String name="test111"; categoryDao.updateName(id,name); } @Test public void testFindById(){ Category category=categoryDao.findOne(id); System.out.println(category); } @Test public void count(){ long count=categoryDao.count(); System.out.println(count); } @Test public void testFindAll(){ Iterable<Category> categories=categoryDao.findAll(); for(Category category:categories){ System.out.println(category); } } @Test public void delete(){ categoryDao.delete(id); } }
源碼地址:https://github.com/cathychen00/learnjava/tree/master/DemoJPA