有不少讀者留言但願鬆哥能好好聊聊 Spring Data Jpa!其實這個話題鬆哥之前零零散散的介紹過,在個人書裏也有介紹過,可是在公衆號中還沒和大夥聊過,所以本文就和你們來仔細聊聊 Spring Data 和 Jpa!php
JPA 的目標之一是制定一個能夠由不少供應商實現的 API,Hibernate 3.2+、TopLink 10.1+ 以及 OpenJPA 都提供了 JPA 的實現,Jpa 供應商有不少,常見的有以下四種:java
Spring Data 是 Spring 的一個子項目。用於簡化數據庫訪問,支持NoSQL 和 關係數據存儲。其主要目標是使數據庫的訪問變得方便快捷。Spring Data 具備以下特色:mysql
爲了讓大夥完全把這兩個東西學會,這裏我就先來介紹單純的Jpa使用,而後咱們再結合 Spring Data 來看 Jpa如何使用。spring
總體步驟以下:sql
接下來在項目中添加實體類,以下:數據庫
@Entity(name = "t_book")
public class Book {
private Long id;
private String name;
private String author;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
// 省略其餘getter/setter
}
複製代碼
首先@Entity註解表示這是一個實體類,那麼在項目啓動時會自動針對該類生成一張表,默認的表名爲類名,@Entity註解的name屬性表示自定義生成的表名。@Id註解表示這個字段是一個id,@GeneratedValue註解表示主鍵的自增加策略,對於類中的其餘屬性,默認都會根據屬性名在表中生成相應的字段,字段名和屬性名相同,若是開發者想要對字段進行定製,可使用@Column註解,去配置字段的名稱,長度,是否爲空等等。express
JPA 規範要求在類路徑的 META-INF 目錄下放置persistence.xml,文件的名稱是固定的編程
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="NewPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>org.sang.Book</class>
<properties>
<property name="hibernate.connection.url" value="jdbc:mysql:///jpa01?useUnicode=true&characterEncoding=UTF-8"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="123"/>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
複製代碼
注意:後端
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("NewPersistenceUnit");
EntityManager manager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
Book book = new Book();
book.setAuthor("羅貫中");
book.setName("三國演義");
manager.persist(book);
transaction.commit();
manager.close();
entityManagerFactory.close();
複製代碼
這裏首先根據配置文件建立出來一個 EntityManagerFactory ,而後再根據 EntityManagerFactory 的實例建立出來一個 EntityManager ,而後再開啓事務,調用 EntityManager 中的 persist 方法執行一次持久化操做,最後提交事務,執行完這些操做後,數據庫中舊多出來一個 t_book 表,而且表中有一條數據。微信
和在 SQL 中同樣,JPQL 中的 select 語句用於執行查詢。其語法可表示爲:
select_clause form_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]
其中:
在 JPQL 中,查詢全部實體的 JPQL 查詢語句很簡單,以下:
select o from Order o 或 select o from Order as o
這裏關鍵字 as 能夠省去,標識符變量的命名規範與 Java 標識符相同,且區分大小寫,調用 EntityManager 的 createQuery() 方法可建立查詢對象,接着調用 Query 接口的 getResultList() 方法就可得到查詢結果集,以下:
Query query = entityManager.createQuery( "select o from Order o");
List orders = query.getResultList();
Iterator iterator = orders.iterator();
while(iterator.hasNext() ) {
// 處理Order
}
複製代碼
其餘方法的與此相似,這裏再也不贅述。
在 Spring Boot 中,Spring Data Jpa 官方封裝了太多東西了,致使不少人用的時候不知道底層究竟是怎麼配置的,本文就和大夥來看看在手工的Spring環境下,Spring Data Jpa要怎麼配置,配置完成後,用法和 Spring Boot 中的用法是一致的。
首先建立一個普通的Maven工程,並添加以下依賴:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.27</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.12.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.2.12.Final</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.11.3.RELEASE</version>
</dependency>
</dependencies>
複製代碼
這裏除了 Jpa 的依賴以外,就是Spring Data Jpa 的依賴了。
接下來建立一個 User 實體類,建立方式參考 Jpa中實體類的建立方式,這裏再也不贅述。
接下來在resources目錄下建立一個applicationContext.xml文件,並配置Spring和Jpa,以下:
<context:property-placeholder location="classpath:db.properties"/>
<context:component-scan base-package="org.sang"/>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="packagesToScan" value="org.sang.model"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</prop>
</props>
</property>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置jpa -->
<jpa:repositories base-package="org.sang.dao" entity-manager-factory-ref="entityManagerFactory"/>
複製代碼
這裏和 Jpa 相關的配置主要是三個,一個是entityManagerFactory,一個是Jpa的事務,還有一個是配置dao的位置,配置完成後,就能夠在 org.sang.dao 包下建立相應的 Repository 了,以下:
public interface UserDao extends Repository<User, Long> {
User getUserById(Long id);
}
複製代碼
getUserById表示根據id去查詢User對象,只要咱們的方法名稱符合相似的規範,就不須要寫SQL,具體的規範一會來講。好了,接下來,建立 Service 和 Controller 來調用這個方法,以下:
@Service
@Transactional
public class UserService {
@Resource
UserDao userDao;
public User getUserById(Long id) {
return userDao.getUserById(id);
}
}
public void test1() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = ctx.getBean(UserService.class);
User user = userService.getUserById(1L);
System.out.println(user);
}
複製代碼
這樣,就能夠查詢到id爲1的用戶了。
上文咱們自定義的 UserDao 實現了 Repository 接口,這個 Repository 接口是什麼來頭呢?
首先來看 Repository 的一個繼承關係圖:
能夠看到,實現類很多。那麼到底如何理解 Repository 呢?
public interface Repository<T, ID extends Serializable> { }
@RepositoryDefinition(domainClass = User.class, idClass = Long.class)
public interface UserDao {
User findById(Long id);
List<User> findAll();
}
複製代碼
基礎的 Repository 提供了最基本的數據訪問功能,其幾個子接口則擴展了一些功能,它的幾個經常使用的實現類以下:
例如:定義一個 Entity 實體類:
class User{ private String firstName;
private String lastName;
}
複製代碼
使用And條件鏈接時,條件的屬性名稱與個數要與參數的位置與個數一一對應,以下:
findByLastNameAndFirstName(String lastName,String firstName);
複製代碼
查詢舉例:
User getUserById(Long id);
User getById(Long id);
複製代碼
List<User> findByAgeLessThan(Long age);
複製代碼
List<User> findByUsernameStartingWith(String u);
複製代碼
List<User> findByUsernameStartingWithAndIdGreaterThan(String name, Long id);
複製代碼
List<User> findByUsernameContaining(String name);
複製代碼
List<User> findByUsernameStartingWithOrAgeGreaterThan(String name, Long age);
複製代碼
List<User> findByRole_Id(Long id);
複製代碼
支持的查詢關鍵字以下圖:
爲何寫上方法名,JPA就知道你想幹嗎了呢?假如建立以下的查詢:findByUserDepUuid()
,框架在解析該方法時,首先剔除 findBy,而後對剩下的屬性進行解析,假設查詢實體爲Doc:
Page<UserModel> findByName(String name, Pageable pageable);
List<UserModel> findByName(String name, Sort sort);
複製代碼
有的時候,這裏提供的查詢關鍵字並不能知足咱們的查詢需求,這個時候就可使用 @Query 關鍵字,來自定義查詢 SQL,例如查詢Id最大的User:
@Query("select u from t_user u where id=(select max(id) from t_user)")
User getMaxIdUser();
複製代碼
若是查詢有參數的話,參數有兩種不一樣的傳遞方式,
@Query("select u from t_user u where id>?1 and username like ?2")
List<User> selectUserByParam(Long id, String name);
複製代碼
@Query("select u from t_user u where id>:id and username like :name")
List<User> selectUserByParam2(@Param("name") String name, @Param("id") Long id);
複製代碼
查詢時候,也能夠是使用原生的SQL查詢,以下:
@Query(value = "select * from t_user",nativeQuery = true)
List<User> selectAll();
複製代碼
涉及到數據修改操做,可使用 @Modifying 註解,@Query 與 @Modifying 這兩個 annotation一塊兒聲明,可定義個性化更新操做,例如涉及某些字段更新時最爲經常使用,示例以下:
@Modifying
@Query("update t_user set age=:age where id>:id")
int updateUserById(@Param("age") Long age, @Param("id") Long id);
複製代碼
注意:
說到這裏,再來順便說說Spring Data 中的事務問題:
好了,關於Spring Data Jpa 本文就先說這麼多,這一塊,鬆哥有一些私藏多年的筆記和視頻,以下圖:
那麼這些資料如何獲取呢?如下兩個條件知足其一便可:
以上條件知足其一,加鬆哥微信,給你資料。