JPA介紹
前面介紹過JPA是sun在JDK5中引入的JPA ORM規范,其目的在於整合ORM技術,統一規范和標准。目前比較成熟的JPA框架主要包括Jboss的HibernateEntityManager、Oracle 捐獻給 Eclipse 社區的 EclipseLink、Apache的OpenJPA等。下面將以Hibernate為例介紹JPA的使用。
使用Hibernate EntityManager
Hibernate本身是獨立於spring的,如果不使用spring框架,則Dao層的代碼如下所示,這時還需要一個標准的persistence.xml
配置文件
public class UserDaoImpl implements UserDao { public AccountInfo save(AccountInfo accountInfo) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("SimplePU"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); em.persist(accountInfo); em.getTransaction().commit(); emf.close(); return accountInfo; } }
使用spring + Hibernate
如果在項目中引入了spring,spring對JPA提供了很友好的支持,可以使用自動注入而不是手動new實現類,配置也更為靈活,最主要的是Spring將EntityManager的創建與銷毀、事務管理等代碼抽取出來,並由其統一管理。事務管理和 EntityManager 創建、銷毀的代碼都不再需要開發者關心了。
持久層代碼:
@Repository("userDao") public class UserDaoImpl implements UserDao { @PersistenceContext private EntityManager em; @Transactional public Long save(AccountInfo accountInfo) { em.persist(accountInfo); return accountInfo.getAccountId(); } }
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans...> <context:component-scan base-package="footmark.springdata.jpa"/> <tx:annotation-driven transaction-manager="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"> </bean> </beans>
測試代碼:
public class SimpleSpringJpaDemo{ public static void main(String[] args){ ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-demo-cfg.xml"); UserDao userDao = ctx.getBean("userDao", UserDao.class); userDao.createNewAccount("ZhangJianPing", "123456", 1); } }
使用Spring Data JPA
從上邊可以看到Spring對JPA的支持已經非常強大,開發者只需關心核心業務邏輯的實現代碼,無需過多關注EntityManager的創建、事務處理等JPA相關的處理。但是你會發現持久層dao的實現邏輯還是需要手動書寫。於是便出現了Spring Data JPA
,Spring Data JPA可以根據規范的持久層方法名稱自動生成想要的邏輯實現,或者通過繼承提供的標准接口Repository
、PagingAndSortingRepository
、CrudRepository
及JpaRepository
等自動獲得各種crud的基本方法,又或者通過注解@Query
自定義一些復雜的實現。
值得注意的是Spring-data-jpa依賴於Hibernate。
Spring Data JPA在后台為持久層接口創建代理對象時,有三種方式實現持久層的功能:
- 通過繼承標准接口獲得基本的crud方法
- 自定義符合指定格式的方法命名,Spring Data JPA可以根據命名自動實現其功能。
- 在聲明的方法上面使用
@Query
注解,並提供一個查詢語句作為參數,Spring Data JPA在創建代理對象時,便以提供的查詢語句來實現其功能。或增加@Modifying
注解將查詢標識為修改查詢(update操作)
繼承標准接口或自定義方法
對於Repository
、PagingAndSortingRepository
、CrudRepository
及JpaRepository
等這些持久層的接口開發的時候應該怎么選擇,直接繼承CrudRepository
或PagingAndSortingRepository
這些接口當然很方便的自動擁有了很多實現,但是這會帶來一個問題,它可能暴露了你不希望暴露給業務層的方法。比如某些接口你只希望提供增加的操作而不希望提供刪除的方法。針對這種情況,開發者只能退回到Repository接口,然后到CrudRepository中把希望保留的方法聲明復制到自定義的接口中即可,當然在一般的簡單系統(erp)中也沒有那么講究,怎么方便怎么來。
Spring Data JPA為自定義查詢提供了一些表達條件查詢的關鍵字,大致如下:
- And --- 等價於 SQL 中的 and 關鍵字,比如 findByUsernameAndPassword(String user, Striang pwd);
- Or --- 等價於 SQL 中的 or 關鍵字,比如 findByUsernameOrAddress(String user, String addr);
- Between --- 等價於 SQL 中的 between 關鍵字,比如 findBySalaryBetween(int max, int min);
- LessThan --- 等價於 SQL 中的 "<",比如 findBySalaryLessThan(int max);
- GreaterThan --- 等價於 SQL 中的">",比如 findBySalaryGreaterThan(int min);
- IsNull --- 等價於 SQL 中的 "is null",比如 findByUsernameIsNull();
- IsNotNull --- 等價於 SQL 中的 "is not null",比如 findByUsernameIsNotNull();
- NotNull --- 與 IsNotNull 等價;
- Like --- 等價於 SQL 中的 "like",比如 findByUsernameLike(String user);
- NotLike --- 等價於 SQL 中的 "not like",比如 findByUsernameNotLike(String user);
- OrderBy --- 等價於 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user);
- Not --- 等價於 SQL 中的 "! =",比如 findByUsernameNot(String user);
- In --- 等價於 SQL 中的 "in",比如 findByUsernameIn(Collection userList) ,方法的參數可以是 Collection 類型,也可以是數組或者不定長參數;
- NotIn --- 等價於 SQL 中的 "not in",比如 findByUsernameNotIn(Collection userList) ,方法的參數可以是 Collection 類型,也可以是數組或者不定長參數;
使用@Query創建查詢
@Query注解的使用非常簡單,只需在聲明的方法上面標注該注解,同時提供一個JP QL查詢語句即可
public interface UserDao extends Repository<AccountInfo, Long> { @Query("select a from AccountInfo a where a.accountId = ?1") AccountInfo findByAccountId(Long accountId); @Query("select a from AccountInfo a where a.balance > ?1") Page<AccountInfo> findByBalanceGreaterThan( Integer balance,Pageable pageable); }
開發者也可以通過使用@Query來執行一個更新操作,為此,我們需要在使用@Query的同時,用@Modifying來將該操作標識為修改查詢
@Modifying
@Query("update AccountInfo a set a.salary = ?1 where a.salary < ?2") int increaseSalary(int after, int before);
刪除的寫法稍微有些特殊:
@Transactional
int deleteByCountrycode(@Param("countrycode") String countrycode);
springboot集成Spring Data JPA
springboot官方提供了集成Spring Data JPA的starter: spring-boot-starter-data-jpa
,該依賴集成了Hibernate
、Spring Data JPA
以及Spring ORMs
(Core ORM support from the Spring Framework)。使用方法非常簡單。
一、添加依賴
<dependency
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
二、application.properties配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop
三、創建實體
@Entity
public class User { @Id @GeneratedValue private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private Integer age; // 省略構造函數 // 省略getter和setter }
四、創建數據訪問接口
public interface UserRepository extends JpaRepository<User, Long> { User findByName(String name); User findByNameAndAge(String name, Integer age); @Query("from User u where u.name=:name") User findUser(@Param("name") String name); }
github中有具體的demo工程實現可以參考,注意demo中使用的是H2內存數據庫。
Spring Data JPA對事務的支持
默認情況下,Spring Data JPA實現的方法都是使用事務的。針對查詢類型的方法,其等價於@Transactional(readOnly=true);增刪改類型的方法,等價於@Transactional。可以看出,除了將查詢的方法設為只讀事務外,其他事務屬性均采用默認值。
當然除了在持久層使用事務注解以外,開發者也可以在業務層方法上使用@Transactional指定事務屬性,這主要針對一個業務層方法多次調用持久層方法的情況。持久層的事務會根據設置的事務傳播行為來決定是掛起業務層事務還是加入業務層的事務。
用百度搜索的時候,沒有找到相關的文章,用谷歌搜索才看到,故轉載一次。
本文轉載至:https://github.com/jiwenxing/spring-boot-demo/wiki/Spring-Data-JPA